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

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",
1.1.1.2 ! misho     255:     "Stack usage errror\n",
1.1       misho     256:     "?? Unknown error ??\n"    /* Must be last in the list! */
                    257: };
                    258: #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /        \
                    259:                   sizeof(xmlXPathErrorMessages[0])) - 1)
                    260: /**
                    261:  * xmlXPathErrMemory:
                    262:  * @ctxt:  an XPath context
                    263:  * @extra:  extra informations
                    264:  *
                    265:  * Handle a redefinition of attribute error
                    266:  */
                    267: static void
                    268: xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
                    269: {
                    270:     if (ctxt != NULL) {
                    271:         if (extra) {
                    272:             xmlChar buf[200];
                    273: 
                    274:             xmlStrPrintf(buf, 200,
                    275:                          BAD_CAST "Memory allocation failed : %s\n",
                    276:                          extra);
                    277:             ctxt->lastError.message = (char *) xmlStrdup(buf);
                    278:         } else {
                    279:             ctxt->lastError.message = (char *)
                    280:               xmlStrdup(BAD_CAST "Memory allocation failed\n");
                    281:         }
                    282:         ctxt->lastError.domain = XML_FROM_XPATH;
                    283:         ctxt->lastError.code = XML_ERR_NO_MEMORY;
                    284:        if (ctxt->error != NULL)
                    285:            ctxt->error(ctxt->userData, &ctxt->lastError);
                    286:     } else {
                    287:         if (extra)
                    288:             __xmlRaiseError(NULL, NULL, NULL,
                    289:                             NULL, NULL, XML_FROM_XPATH,
                    290:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
                    291:                             extra, NULL, NULL, 0, 0,
                    292:                             "Memory allocation failed : %s\n", extra);
                    293:         else
                    294:             __xmlRaiseError(NULL, NULL, NULL,
                    295:                             NULL, NULL, XML_FROM_XPATH,
                    296:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
                    297:                             NULL, NULL, NULL, 0, 0,
                    298:                             "Memory allocation failed\n");
                    299:     }
                    300: }
                    301: 
                    302: /**
                    303:  * xmlXPathPErrMemory:
                    304:  * @ctxt:  an XPath parser context
                    305:  * @extra:  extra informations
                    306:  *
                    307:  * Handle a redefinition of attribute error
                    308:  */
                    309: static void
                    310: xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
                    311: {
                    312:     if (ctxt == NULL)
                    313:        xmlXPathErrMemory(NULL, extra);
                    314:     else {
                    315:        ctxt->error = XPATH_MEMORY_ERROR;
                    316:        xmlXPathErrMemory(ctxt->context, extra);
                    317:     }
                    318: }
                    319: 
                    320: /**
                    321:  * xmlXPathErr:
                    322:  * @ctxt:  a XPath parser context
                    323:  * @error:  the error code
                    324:  *
                    325:  * Handle an XPath error
                    326:  */
                    327: void
                    328: xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
                    329: {
                    330:     if ((error < 0) || (error > MAXERRNO))
                    331:        error = MAXERRNO;
                    332:     if (ctxt == NULL) {
                    333:        __xmlRaiseError(NULL, NULL, NULL,
                    334:                        NULL, NULL, XML_FROM_XPATH,
                    335:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
                    336:                        XML_ERR_ERROR, NULL, 0,
                    337:                        NULL, NULL, NULL, 0, 0,
                    338:                        "%s", xmlXPathErrorMessages[error]);
                    339:        return;
                    340:     }
                    341:     ctxt->error = error;
                    342:     if (ctxt->context == NULL) {
                    343:        __xmlRaiseError(NULL, NULL, NULL,
                    344:                        NULL, NULL, XML_FROM_XPATH,
                    345:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
                    346:                        XML_ERR_ERROR, NULL, 0,
                    347:                        (const char *) ctxt->base, NULL, NULL,
                    348:                        ctxt->cur - ctxt->base, 0,
                    349:                        "%s", xmlXPathErrorMessages[error]);
                    350:        return;
                    351:     }
                    352: 
                    353:     /* cleanup current last error */
                    354:     xmlResetError(&ctxt->context->lastError);
                    355: 
                    356:     ctxt->context->lastError.domain = XML_FROM_XPATH;
                    357:     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
                    358:                            XPATH_EXPRESSION_OK;
                    359:     ctxt->context->lastError.level = XML_ERR_ERROR;
                    360:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
                    361:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
                    362:     ctxt->context->lastError.node = ctxt->context->debugNode;
                    363:     if (ctxt->context->error != NULL) {
                    364:        ctxt->context->error(ctxt->context->userData,
                    365:                             &ctxt->context->lastError);
                    366:     } else {
                    367:        __xmlRaiseError(NULL, NULL, NULL,
                    368:                        NULL, ctxt->context->debugNode, XML_FROM_XPATH,
                    369:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
                    370:                        XML_ERR_ERROR, NULL, 0,
                    371:                        (const char *) ctxt->base, NULL, NULL,
                    372:                        ctxt->cur - ctxt->base, 0,
                    373:                        "%s", xmlXPathErrorMessages[error]);
                    374:     }
                    375: 
                    376: }
                    377: 
                    378: /**
                    379:  * xmlXPatherror:
                    380:  * @ctxt:  the XPath Parser context
                    381:  * @file:  the file name
                    382:  * @line:  the line number
                    383:  * @no:  the error number
                    384:  *
                    385:  * Formats an error message.
                    386:  */
                    387: void
                    388: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
                    389:               int line ATTRIBUTE_UNUSED, int no) {
                    390:     xmlXPathErr(ctxt, no);
                    391: }
                    392: 
                    393: /************************************************************************
                    394:  *                                                                     *
                    395:  *                     Utilities                                       *
                    396:  *                                                                     *
                    397:  ************************************************************************/
                    398: 
                    399: /**
                    400:  * xsltPointerList:
                    401:  *
                    402:  * Pointer-list for various purposes.
                    403:  */
                    404: typedef struct _xmlPointerList xmlPointerList;
                    405: typedef xmlPointerList *xmlPointerListPtr;
                    406: struct _xmlPointerList {
                    407:     void **items;
                    408:     int number;
                    409:     int size;
                    410: };
                    411: /*
                    412: * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
                    413: * and here, we should make the functions public.
                    414: */
                    415: static int
                    416: xmlPointerListAddSize(xmlPointerListPtr list,
                    417:                       void *item,
                    418:                       int initialSize)
                    419: {
                    420:     if (list->items == NULL) {
                    421:        if (initialSize <= 0)
                    422:            initialSize = 1;
                    423:        list->items = (void **) xmlMalloc(
                    424:            initialSize * sizeof(void *));
                    425:        if (list->items == NULL) {
                    426:            xmlXPathErrMemory(NULL,
                    427:                "xmlPointerListCreate: allocating item\n");
                    428:            return(-1);
                    429:        }
                    430:        list->number = 0;
                    431:        list->size = initialSize;
                    432:     } else if (list->size <= list->number) {
                    433:        list->size *= 2;
                    434:        list->items = (void **) xmlRealloc(list->items,
                    435:            list->size * sizeof(void *));
                    436:        if (list->items == NULL) {
                    437:            xmlXPathErrMemory(NULL,
                    438:                "xmlPointerListCreate: re-allocating item\n");
                    439:            list->size = 0;
                    440:            return(-1);
                    441:        }
                    442:     }
                    443:     list->items[list->number++] = item;
                    444:     return(0);
                    445: }
                    446: 
                    447: /**
                    448:  * xsltPointerListCreate:
                    449:  *
                    450:  * Creates an xsltPointerList structure.
                    451:  *
                    452:  * Returns a xsltPointerList structure or NULL in case of an error.
                    453:  */
                    454: static xmlPointerListPtr
                    455: xmlPointerListCreate(int initialSize)
                    456: {
                    457:     xmlPointerListPtr ret;
                    458: 
                    459:     ret = xmlMalloc(sizeof(xmlPointerList));
                    460:     if (ret == NULL) {
                    461:        xmlXPathErrMemory(NULL,
                    462:            "xmlPointerListCreate: allocating item\n");
                    463:        return (NULL);
                    464:     }
                    465:     memset(ret, 0, sizeof(xmlPointerList));
                    466:     if (initialSize > 0) {
                    467:        xmlPointerListAddSize(ret, NULL, initialSize);
                    468:        ret->number = 0;
                    469:     }
                    470:     return (ret);
                    471: }
                    472: 
                    473: /**
                    474:  * xsltPointerListFree:
                    475:  *
                    476:  * Frees the xsltPointerList structure. This does not free
                    477:  * the content of the list.
                    478:  */
                    479: static void
                    480: xmlPointerListFree(xmlPointerListPtr list)
                    481: {
                    482:     if (list == NULL)
                    483:        return;
                    484:     if (list->items != NULL)
                    485:        xmlFree(list->items);
                    486:     xmlFree(list);
                    487: }
                    488: 
                    489: /************************************************************************
                    490:  *                                                                     *
                    491:  *                     Parser Types                                    *
                    492:  *                                                                     *
                    493:  ************************************************************************/
                    494: 
                    495: /*
                    496:  * Types are private:
                    497:  */
                    498: 
                    499: typedef enum {
                    500:     XPATH_OP_END=0,
                    501:     XPATH_OP_AND,
                    502:     XPATH_OP_OR,
                    503:     XPATH_OP_EQUAL,
                    504:     XPATH_OP_CMP,
                    505:     XPATH_OP_PLUS,
                    506:     XPATH_OP_MULT,
                    507:     XPATH_OP_UNION,
                    508:     XPATH_OP_ROOT,
                    509:     XPATH_OP_NODE,
                    510:     XPATH_OP_RESET, /* 10 */
                    511:     XPATH_OP_COLLECT,
                    512:     XPATH_OP_VALUE, /* 12 */
                    513:     XPATH_OP_VARIABLE,
                    514:     XPATH_OP_FUNCTION,
                    515:     XPATH_OP_ARG,
                    516:     XPATH_OP_PREDICATE,
                    517:     XPATH_OP_FILTER, /* 17 */
                    518:     XPATH_OP_SORT /* 18 */
                    519: #ifdef LIBXML_XPTR_ENABLED
                    520:     ,XPATH_OP_RANGETO
                    521: #endif
                    522: } xmlXPathOp;
                    523: 
                    524: typedef enum {
                    525:     AXIS_ANCESTOR = 1,
                    526:     AXIS_ANCESTOR_OR_SELF,
                    527:     AXIS_ATTRIBUTE,
                    528:     AXIS_CHILD,
                    529:     AXIS_DESCENDANT,
                    530:     AXIS_DESCENDANT_OR_SELF,
                    531:     AXIS_FOLLOWING,
                    532:     AXIS_FOLLOWING_SIBLING,
                    533:     AXIS_NAMESPACE,
                    534:     AXIS_PARENT,
                    535:     AXIS_PRECEDING,
                    536:     AXIS_PRECEDING_SIBLING,
                    537:     AXIS_SELF
                    538: } xmlXPathAxisVal;
                    539: 
                    540: typedef enum {
                    541:     NODE_TEST_NONE = 0,
                    542:     NODE_TEST_TYPE = 1,
                    543:     NODE_TEST_PI = 2,
                    544:     NODE_TEST_ALL = 3,
                    545:     NODE_TEST_NS = 4,
                    546:     NODE_TEST_NAME = 5
                    547: } xmlXPathTestVal;
                    548: 
                    549: typedef enum {
                    550:     NODE_TYPE_NODE = 0,
                    551:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
                    552:     NODE_TYPE_TEXT = XML_TEXT_NODE,
                    553:     NODE_TYPE_PI = XML_PI_NODE
                    554: } xmlXPathTypeVal;
                    555: 
                    556: #define XP_REWRITE_DOS_CHILD_ELEM 1
                    557: 
                    558: typedef struct _xmlXPathStepOp xmlXPathStepOp;
                    559: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
                    560: struct _xmlXPathStepOp {
                    561:     xmlXPathOp op;             /* The identifier of the operation */
                    562:     int ch1;                   /* First child */
                    563:     int ch2;                   /* Second child */
                    564:     int value;
                    565:     int value2;
                    566:     int value3;
                    567:     void *value4;
                    568:     void *value5;
                    569:     void *cache;
                    570:     void *cacheURI;
                    571:     int rewriteType;
                    572: };
                    573: 
                    574: struct _xmlXPathCompExpr {
                    575:     int nbStep;                        /* Number of steps in this expression */
                    576:     int maxStep;               /* Maximum number of steps allocated */
                    577:     xmlXPathStepOp *steps;     /* ops for computation of this expression */
                    578:     int last;                  /* index of last step in expression */
                    579:     xmlChar *expr;             /* the expression being computed */
                    580:     xmlDictPtr dict;           /* the dictionnary to use if any */
                    581: #ifdef DEBUG_EVAL_COUNTS
                    582:     int nb;
                    583:     xmlChar *string;
                    584: #endif
                    585: #ifdef XPATH_STREAMING
                    586:     xmlPatternPtr stream;
                    587: #endif
                    588: };
                    589: 
                    590: /************************************************************************
                    591:  *                                                                     *
                    592:  *                     Forward declarations                            *
                    593:  *                                                                     *
                    594:  ************************************************************************/
                    595: static void
                    596: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
                    597: static void
                    598: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
                    599: static int
                    600: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
                    601:                         xmlXPathStepOpPtr op, xmlNodePtr *first);
                    602: static int
                    603: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
                    604:                            xmlXPathStepOpPtr op,
                    605:                            int isPredicate);
                    606: 
                    607: /************************************************************************
                    608:  *                                                                     *
                    609:  *                     Parser Type functions                           *
                    610:  *                                                                     *
                    611:  ************************************************************************/
                    612: 
                    613: /**
                    614:  * xmlXPathNewCompExpr:
                    615:  *
                    616:  * Create a new Xpath component
                    617:  *
                    618:  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
                    619:  */
                    620: static xmlXPathCompExprPtr
                    621: xmlXPathNewCompExpr(void) {
                    622:     xmlXPathCompExprPtr cur;
                    623: 
                    624:     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
                    625:     if (cur == NULL) {
                    626:         xmlXPathErrMemory(NULL, "allocating component\n");
                    627:        return(NULL);
                    628:     }
                    629:     memset(cur, 0, sizeof(xmlXPathCompExpr));
                    630:     cur->maxStep = 10;
                    631:     cur->nbStep = 0;
                    632:     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
                    633:                                           sizeof(xmlXPathStepOp));
                    634:     if (cur->steps == NULL) {
                    635:         xmlXPathErrMemory(NULL, "allocating steps\n");
                    636:        xmlFree(cur);
                    637:        return(NULL);
                    638:     }
                    639:     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
                    640:     cur->last = -1;
                    641: #ifdef DEBUG_EVAL_COUNTS
                    642:     cur->nb = 0;
                    643: #endif
                    644:     return(cur);
                    645: }
                    646: 
                    647: /**
                    648:  * xmlXPathFreeCompExpr:
                    649:  * @comp:  an XPATH comp
                    650:  *
                    651:  * Free up the memory allocated by @comp
                    652:  */
                    653: void
                    654: xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
                    655: {
                    656:     xmlXPathStepOpPtr op;
                    657:     int i;
                    658: 
                    659:     if (comp == NULL)
                    660:         return;
                    661:     if (comp->dict == NULL) {
                    662:        for (i = 0; i < comp->nbStep; i++) {
                    663:            op = &comp->steps[i];
                    664:            if (op->value4 != NULL) {
                    665:                if (op->op == XPATH_OP_VALUE)
                    666:                    xmlXPathFreeObject(op->value4);
                    667:                else
                    668:                    xmlFree(op->value4);
                    669:            }
                    670:            if (op->value5 != NULL)
                    671:                xmlFree(op->value5);
                    672:        }
                    673:     } else {
                    674:        for (i = 0; i < comp->nbStep; i++) {
                    675:            op = &comp->steps[i];
                    676:            if (op->value4 != NULL) {
                    677:                if (op->op == XPATH_OP_VALUE)
                    678:                    xmlXPathFreeObject(op->value4);
                    679:            }
                    680:        }
                    681:         xmlDictFree(comp->dict);
                    682:     }
                    683:     if (comp->steps != NULL) {
                    684:         xmlFree(comp->steps);
                    685:     }
                    686: #ifdef DEBUG_EVAL_COUNTS
                    687:     if (comp->string != NULL) {
                    688:         xmlFree(comp->string);
                    689:     }
                    690: #endif
                    691: #ifdef XPATH_STREAMING
                    692:     if (comp->stream != NULL) {
                    693:         xmlFreePatternList(comp->stream);
                    694:     }
                    695: #endif
                    696:     if (comp->expr != NULL) {
                    697:         xmlFree(comp->expr);
                    698:     }
                    699: 
                    700:     xmlFree(comp);
                    701: }
                    702: 
                    703: /**
                    704:  * xmlXPathCompExprAdd:
                    705:  * @comp:  the compiled expression
                    706:  * @ch1: first child index
                    707:  * @ch2: second child index
                    708:  * @op:  an op
                    709:  * @value:  the first int value
                    710:  * @value2:  the second int value
                    711:  * @value3:  the third int value
                    712:  * @value4:  the first string value
                    713:  * @value5:  the second string value
                    714:  *
                    715:  * Add a step to an XPath Compiled Expression
                    716:  *
                    717:  * Returns -1 in case of failure, the index otherwise
                    718:  */
                    719: static int
                    720: xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
                    721:    xmlXPathOp op, int value,
                    722:    int value2, int value3, void *value4, void *value5) {
                    723:     if (comp->nbStep >= comp->maxStep) {
                    724:        xmlXPathStepOp *real;
                    725: 
                    726:        comp->maxStep *= 2;
                    727:        real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
                    728:                                      comp->maxStep * sizeof(xmlXPathStepOp));
                    729:        if (real == NULL) {
                    730:            comp->maxStep /= 2;
                    731:            xmlXPathErrMemory(NULL, "adding step\n");
                    732:            return(-1);
                    733:        }
                    734:        comp->steps = real;
                    735:     }
                    736:     comp->last = comp->nbStep;
                    737:     comp->steps[comp->nbStep].rewriteType = 0;
                    738:     comp->steps[comp->nbStep].ch1 = ch1;
                    739:     comp->steps[comp->nbStep].ch2 = ch2;
                    740:     comp->steps[comp->nbStep].op = op;
                    741:     comp->steps[comp->nbStep].value = value;
                    742:     comp->steps[comp->nbStep].value2 = value2;
                    743:     comp->steps[comp->nbStep].value3 = value3;
                    744:     if ((comp->dict != NULL) &&
                    745:         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
                    746:         (op == XPATH_OP_COLLECT))) {
                    747:         if (value4 != NULL) {
                    748:            comp->steps[comp->nbStep].value4 = (xmlChar *)
                    749:                (void *)xmlDictLookup(comp->dict, value4, -1);
                    750:            xmlFree(value4);
                    751:        } else
                    752:            comp->steps[comp->nbStep].value4 = NULL;
                    753:         if (value5 != NULL) {
                    754:            comp->steps[comp->nbStep].value5 = (xmlChar *)
                    755:                (void *)xmlDictLookup(comp->dict, value5, -1);
                    756:            xmlFree(value5);
                    757:        } else
                    758:            comp->steps[comp->nbStep].value5 = NULL;
                    759:     } else {
                    760:        comp->steps[comp->nbStep].value4 = value4;
                    761:        comp->steps[comp->nbStep].value5 = value5;
                    762:     }
                    763:     comp->steps[comp->nbStep].cache = NULL;
                    764:     return(comp->nbStep++);
                    765: }
                    766: 
                    767: /**
                    768:  * xmlXPathCompSwap:
                    769:  * @comp:  the compiled expression
                    770:  * @op: operation index
                    771:  *
                    772:  * Swaps 2 operations in the compiled expression
                    773:  */
                    774: static void
                    775: xmlXPathCompSwap(xmlXPathStepOpPtr op) {
                    776:     int tmp;
                    777: 
                    778: #ifndef LIBXML_THREAD_ENABLED
                    779:     /*
                    780:      * Since this manipulates possibly shared variables, this is
                    781:      * disabled if one detects that the library is used in a multithreaded
                    782:      * application
                    783:      */
                    784:     if (xmlXPathDisableOptimizer)
                    785:        return;
                    786: #endif
                    787: 
                    788:     tmp = op->ch1;
                    789:     op->ch1 = op->ch2;
                    790:     op->ch2 = tmp;
                    791: }
                    792: 
                    793: #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)      \
                    794:     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                      \
                    795:                        (op), (val), (val2), (val3), (val4), (val5))
                    796: #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                        \
                    797:     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,              \
                    798:                        (op), (val), (val2), (val3), (val4), (val5))
                    799: 
                    800: #define PUSH_LEAVE_EXPR(op, val, val2)                                 \
                    801: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
                    802: 
                    803: #define PUSH_UNARY_EXPR(op, ch, val, val2)                             \
                    804: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
                    805: 
                    806: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                      \
                    807: xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                    \
                    808:                        (val), (val2), 0 ,NULL ,NULL)
                    809: 
                    810: /************************************************************************
                    811:  *                                                                     *
                    812:  *             XPath object cache structures                           *
                    813:  *                                                                     *
                    814:  ************************************************************************/
                    815: 
                    816: /* #define XP_DEFAULT_CACHE_ON */
                    817: 
                    818: #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
                    819: 
                    820: typedef struct _xmlXPathContextCache xmlXPathContextCache;
                    821: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
                    822: struct _xmlXPathContextCache {
                    823:     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
                    824:     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
                    825:     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
                    826:     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
                    827:     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
                    828:     int maxNodeset;
                    829:     int maxString;
                    830:     int maxBoolean;
                    831:     int maxNumber;
                    832:     int maxMisc;
                    833: #ifdef XP_DEBUG_OBJ_USAGE
                    834:     int dbgCachedAll;
                    835:     int dbgCachedNodeset;
                    836:     int dbgCachedString;
                    837:     int dbgCachedBool;
                    838:     int dbgCachedNumber;
                    839:     int dbgCachedPoint;
                    840:     int dbgCachedRange;
                    841:     int dbgCachedLocset;
                    842:     int dbgCachedUsers;
                    843:     int dbgCachedXSLTTree;
                    844:     int dbgCachedUndefined;
                    845: 
                    846: 
                    847:     int dbgReusedAll;
                    848:     int dbgReusedNodeset;
                    849:     int dbgReusedString;
                    850:     int dbgReusedBool;
                    851:     int dbgReusedNumber;
                    852:     int dbgReusedPoint;
                    853:     int dbgReusedRange;
                    854:     int dbgReusedLocset;
                    855:     int dbgReusedUsers;
                    856:     int dbgReusedXSLTTree;
                    857:     int dbgReusedUndefined;
                    858: 
                    859: #endif
                    860: };
                    861: 
                    862: /************************************************************************
                    863:  *                                                                     *
                    864:  *             Debugging related functions                             *
                    865:  *                                                                     *
                    866:  ************************************************************************/
                    867: 
                    868: #define STRANGE                                                        \
                    869:     xmlGenericError(xmlGenericErrorContext,                            \
                    870:            "Internal error at %s:%d\n",                                \
                    871:             __FILE__, __LINE__);
                    872: 
                    873: #ifdef LIBXML_DEBUG_ENABLED
                    874: static void
                    875: xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
                    876:     int i;
                    877:     char shift[100];
                    878: 
                    879:     for (i = 0;((i < depth) && (i < 25));i++)
                    880:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    881:     shift[2 * i] = shift[2 * i + 1] = 0;
                    882:     if (cur == NULL) {
                    883:        fprintf(output, "%s", shift);
                    884:        fprintf(output, "Node is NULL !\n");
                    885:        return;
                    886: 
                    887:     }
                    888: 
                    889:     if ((cur->type == XML_DOCUMENT_NODE) ||
                    890:             (cur->type == XML_HTML_DOCUMENT_NODE)) {
                    891:        fprintf(output, "%s", shift);
                    892:        fprintf(output, " /\n");
                    893:     } else if (cur->type == XML_ATTRIBUTE_NODE)
                    894:        xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
                    895:     else
                    896:        xmlDebugDumpOneNode(output, cur, depth);
                    897: }
                    898: static void
                    899: xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
                    900:     xmlNodePtr tmp;
                    901:     int i;
                    902:     char shift[100];
                    903: 
                    904:     for (i = 0;((i < depth) && (i < 25));i++)
                    905:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    906:     shift[2 * i] = shift[2 * i + 1] = 0;
                    907:     if (cur == NULL) {
                    908:        fprintf(output, "%s", shift);
                    909:        fprintf(output, "Node is NULL !\n");
                    910:        return;
                    911: 
                    912:     }
                    913: 
                    914:     while (cur != NULL) {
                    915:        tmp = cur;
                    916:        cur = cur->next;
                    917:        xmlDebugDumpOneNode(output, tmp, depth);
                    918:     }
                    919: }
                    920: 
                    921: static void
                    922: xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
                    923:     int i;
                    924:     char shift[100];
                    925: 
                    926:     for (i = 0;((i < depth) && (i < 25));i++)
                    927:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    928:     shift[2 * i] = shift[2 * i + 1] = 0;
                    929: 
                    930:     if (cur == NULL) {
                    931:        fprintf(output, "%s", shift);
                    932:        fprintf(output, "NodeSet is NULL !\n");
                    933:        return;
                    934: 
                    935:     }
                    936: 
                    937:     if (cur != NULL) {
                    938:        fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
                    939:        for (i = 0;i < cur->nodeNr;i++) {
                    940:            fprintf(output, "%s", shift);
                    941:            fprintf(output, "%d", i + 1);
                    942:            xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
                    943:        }
                    944:     }
                    945: }
                    946: 
                    947: static void
                    948: xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
                    949:     int i;
                    950:     char shift[100];
                    951: 
                    952:     for (i = 0;((i < depth) && (i < 25));i++)
                    953:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    954:     shift[2 * i] = shift[2 * i + 1] = 0;
                    955: 
                    956:     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
                    957:        fprintf(output, "%s", shift);
                    958:        fprintf(output, "Value Tree is NULL !\n");
                    959:        return;
                    960: 
                    961:     }
                    962: 
                    963:     fprintf(output, "%s", shift);
                    964:     fprintf(output, "%d", i + 1);
                    965:     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
                    966: }
                    967: #if defined(LIBXML_XPTR_ENABLED)
                    968: static void
                    969: xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
                    970:     int i;
                    971:     char shift[100];
                    972: 
                    973:     for (i = 0;((i < depth) && (i < 25));i++)
                    974:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    975:     shift[2 * i] = shift[2 * i + 1] = 0;
                    976: 
                    977:     if (cur == NULL) {
                    978:        fprintf(output, "%s", shift);
                    979:        fprintf(output, "LocationSet is NULL !\n");
                    980:        return;
                    981: 
                    982:     }
                    983: 
                    984:     for (i = 0;i < cur->locNr;i++) {
                    985:        fprintf(output, "%s", shift);
                    986:         fprintf(output, "%d : ", i + 1);
                    987:        xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
                    988:     }
                    989: }
                    990: #endif /* LIBXML_XPTR_ENABLED */
                    991: 
                    992: /**
                    993:  * xmlXPathDebugDumpObject:
                    994:  * @output:  the FILE * to dump the output
                    995:  * @cur:  the object to inspect
                    996:  * @depth:  indentation level
                    997:  *
                    998:  * Dump the content of the object for debugging purposes
                    999:  */
                   1000: void
                   1001: xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
                   1002:     int i;
                   1003:     char shift[100];
                   1004: 
                   1005:     if (output == NULL) return;
                   1006: 
                   1007:     for (i = 0;((i < depth) && (i < 25));i++)
                   1008:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1009:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1010: 
                   1011: 
                   1012:     fprintf(output, "%s", shift);
                   1013: 
                   1014:     if (cur == NULL) {
                   1015:         fprintf(output, "Object is empty (NULL)\n");
                   1016:        return;
                   1017:     }
                   1018:     switch(cur->type) {
                   1019:         case XPATH_UNDEFINED:
                   1020:            fprintf(output, "Object is uninitialized\n");
                   1021:            break;
                   1022:         case XPATH_NODESET:
                   1023:            fprintf(output, "Object is a Node Set :\n");
                   1024:            xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
                   1025:            break;
                   1026:        case XPATH_XSLT_TREE:
                   1027:            fprintf(output, "Object is an XSLT value tree :\n");
                   1028:            xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
                   1029:            break;
                   1030:         case XPATH_BOOLEAN:
                   1031:            fprintf(output, "Object is a Boolean : ");
                   1032:            if (cur->boolval) fprintf(output, "true\n");
                   1033:            else fprintf(output, "false\n");
                   1034:            break;
                   1035:         case XPATH_NUMBER:
                   1036:            switch (xmlXPathIsInf(cur->floatval)) {
                   1037:            case 1:
                   1038:                fprintf(output, "Object is a number : Infinity\n");
                   1039:                break;
                   1040:            case -1:
                   1041:                fprintf(output, "Object is a number : -Infinity\n");
                   1042:                break;
                   1043:            default:
                   1044:                if (xmlXPathIsNaN(cur->floatval)) {
                   1045:                    fprintf(output, "Object is a number : NaN\n");
                   1046:                } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
                   1047:                    fprintf(output, "Object is a number : 0\n");
                   1048:                } else {
                   1049:                    fprintf(output, "Object is a number : %0g\n", cur->floatval);
                   1050:                }
                   1051:            }
                   1052:            break;
                   1053:         case XPATH_STRING:
                   1054:            fprintf(output, "Object is a string : ");
                   1055:            xmlDebugDumpString(output, cur->stringval);
                   1056:            fprintf(output, "\n");
                   1057:            break;
                   1058:        case XPATH_POINT:
                   1059:            fprintf(output, "Object is a point : index %d in node", cur->index);
                   1060:            xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
                   1061:            fprintf(output, "\n");
                   1062:            break;
                   1063:        case XPATH_RANGE:
                   1064:            if ((cur->user2 == NULL) ||
                   1065:                ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
                   1066:                fprintf(output, "Object is a collapsed range :\n");
                   1067:                fprintf(output, "%s", shift);
                   1068:                if (cur->index >= 0)
                   1069:                    fprintf(output, "index %d in ", cur->index);
                   1070:                fprintf(output, "node\n");
                   1071:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
                   1072:                                      depth + 1);
                   1073:            } else  {
                   1074:                fprintf(output, "Object is a range :\n");
                   1075:                fprintf(output, "%s", shift);
                   1076:                fprintf(output, "From ");
                   1077:                if (cur->index >= 0)
                   1078:                    fprintf(output, "index %d in ", cur->index);
                   1079:                fprintf(output, "node\n");
                   1080:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
                   1081:                                      depth + 1);
                   1082:                fprintf(output, "%s", shift);
                   1083:                fprintf(output, "To ");
                   1084:                if (cur->index2 >= 0)
                   1085:                    fprintf(output, "index %d in ", cur->index2);
                   1086:                fprintf(output, "node\n");
                   1087:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
                   1088:                                      depth + 1);
                   1089:                fprintf(output, "\n");
                   1090:            }
                   1091:            break;
                   1092:        case XPATH_LOCATIONSET:
                   1093: #if defined(LIBXML_XPTR_ENABLED)
                   1094:            fprintf(output, "Object is a Location Set:\n");
                   1095:            xmlXPathDebugDumpLocationSet(output,
                   1096:                    (xmlLocationSetPtr) cur->user, depth);
                   1097: #endif
                   1098:            break;
                   1099:        case XPATH_USERS:
                   1100:            fprintf(output, "Object is user defined\n");
                   1101:            break;
                   1102:     }
                   1103: }
                   1104: 
                   1105: static void
                   1106: xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
                   1107:                             xmlXPathStepOpPtr op, int depth) {
                   1108:     int i;
                   1109:     char shift[100];
                   1110: 
                   1111:     for (i = 0;((i < depth) && (i < 25));i++)
                   1112:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1113:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1114: 
                   1115:     fprintf(output, "%s", shift);
                   1116:     if (op == NULL) {
                   1117:        fprintf(output, "Step is NULL\n");
                   1118:        return;
                   1119:     }
                   1120:     switch (op->op) {
                   1121:         case XPATH_OP_END:
                   1122:            fprintf(output, "END"); break;
                   1123:         case XPATH_OP_AND:
                   1124:            fprintf(output, "AND"); break;
                   1125:         case XPATH_OP_OR:
                   1126:            fprintf(output, "OR"); break;
                   1127:         case XPATH_OP_EQUAL:
                   1128:             if (op->value)
                   1129:                 fprintf(output, "EQUAL =");
                   1130:             else
                   1131:                 fprintf(output, "EQUAL !=");
                   1132:             break;
                   1133:         case XPATH_OP_CMP:
                   1134:             if (op->value)
                   1135:                 fprintf(output, "CMP <");
                   1136:             else
                   1137:                 fprintf(output, "CMP >");
                   1138:             if (!op->value2)
                   1139:                 fprintf(output, "=");
                   1140:             break;
                   1141:         case XPATH_OP_PLUS:
                   1142:             if (op->value == 0)
                   1143:                 fprintf(output, "PLUS -");
                   1144:             else if (op->value == 1)
                   1145:                 fprintf(output, "PLUS +");
                   1146:             else if (op->value == 2)
                   1147:                 fprintf(output, "PLUS unary -");
                   1148:             else if (op->value == 3)
                   1149:                 fprintf(output, "PLUS unary - -");
                   1150:             break;
                   1151:         case XPATH_OP_MULT:
                   1152:             if (op->value == 0)
                   1153:                 fprintf(output, "MULT *");
                   1154:             else if (op->value == 1)
                   1155:                 fprintf(output, "MULT div");
                   1156:             else
                   1157:                 fprintf(output, "MULT mod");
                   1158:             break;
                   1159:         case XPATH_OP_UNION:
                   1160:             fprintf(output, "UNION"); break;
                   1161:         case XPATH_OP_ROOT:
                   1162:             fprintf(output, "ROOT"); break;
                   1163:         case XPATH_OP_NODE:
                   1164:             fprintf(output, "NODE"); break;
                   1165:         case XPATH_OP_RESET:
                   1166:             fprintf(output, "RESET"); break;
                   1167:         case XPATH_OP_SORT:
                   1168:             fprintf(output, "SORT"); break;
                   1169:         case XPATH_OP_COLLECT: {
                   1170:            xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
                   1171:            xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
                   1172:            xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
                   1173:            const xmlChar *prefix = op->value4;
                   1174:            const xmlChar *name = op->value5;
                   1175: 
                   1176:            fprintf(output, "COLLECT ");
                   1177:            switch (axis) {
                   1178:                case AXIS_ANCESTOR:
                   1179:                    fprintf(output, " 'ancestors' "); break;
                   1180:                case AXIS_ANCESTOR_OR_SELF:
                   1181:                    fprintf(output, " 'ancestors-or-self' "); break;
                   1182:                case AXIS_ATTRIBUTE:
                   1183:                    fprintf(output, " 'attributes' "); break;
                   1184:                case AXIS_CHILD:
                   1185:                    fprintf(output, " 'child' "); break;
                   1186:                case AXIS_DESCENDANT:
                   1187:                    fprintf(output, " 'descendant' "); break;
                   1188:                case AXIS_DESCENDANT_OR_SELF:
                   1189:                    fprintf(output, " 'descendant-or-self' "); break;
                   1190:                case AXIS_FOLLOWING:
                   1191:                    fprintf(output, " 'following' "); break;
                   1192:                case AXIS_FOLLOWING_SIBLING:
                   1193:                    fprintf(output, " 'following-siblings' "); break;
                   1194:                case AXIS_NAMESPACE:
                   1195:                    fprintf(output, " 'namespace' "); break;
                   1196:                case AXIS_PARENT:
                   1197:                    fprintf(output, " 'parent' "); break;
                   1198:                case AXIS_PRECEDING:
                   1199:                    fprintf(output, " 'preceding' "); break;
                   1200:                case AXIS_PRECEDING_SIBLING:
                   1201:                    fprintf(output, " 'preceding-sibling' "); break;
                   1202:                case AXIS_SELF:
                   1203:                    fprintf(output, " 'self' "); break;
                   1204:            }
                   1205:            switch (test) {
                   1206:                 case NODE_TEST_NONE:
                   1207:                    fprintf(output, "'none' "); break;
                   1208:                 case NODE_TEST_TYPE:
                   1209:                    fprintf(output, "'type' "); break;
                   1210:                 case NODE_TEST_PI:
                   1211:                    fprintf(output, "'PI' "); break;
                   1212:                 case NODE_TEST_ALL:
                   1213:                    fprintf(output, "'all' "); break;
                   1214:                 case NODE_TEST_NS:
                   1215:                    fprintf(output, "'namespace' "); break;
                   1216:                 case NODE_TEST_NAME:
                   1217:                    fprintf(output, "'name' "); break;
                   1218:            }
                   1219:            switch (type) {
                   1220:                 case NODE_TYPE_NODE:
                   1221:                    fprintf(output, "'node' "); break;
                   1222:                 case NODE_TYPE_COMMENT:
                   1223:                    fprintf(output, "'comment' "); break;
                   1224:                 case NODE_TYPE_TEXT:
                   1225:                    fprintf(output, "'text' "); break;
                   1226:                 case NODE_TYPE_PI:
                   1227:                    fprintf(output, "'PI' "); break;
                   1228:            }
                   1229:            if (prefix != NULL)
                   1230:                fprintf(output, "%s:", prefix);
                   1231:            if (name != NULL)
                   1232:                fprintf(output, "%s", (const char *) name);
                   1233:            break;
                   1234: 
                   1235:         }
                   1236:        case XPATH_OP_VALUE: {
                   1237:            xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
                   1238: 
                   1239:            fprintf(output, "ELEM ");
                   1240:            xmlXPathDebugDumpObject(output, object, 0);
                   1241:            goto finish;
                   1242:        }
                   1243:        case XPATH_OP_VARIABLE: {
                   1244:            const xmlChar *prefix = op->value5;
                   1245:            const xmlChar *name = op->value4;
                   1246: 
                   1247:            if (prefix != NULL)
                   1248:                fprintf(output, "VARIABLE %s:%s", prefix, name);
                   1249:            else
                   1250:                fprintf(output, "VARIABLE %s", name);
                   1251:            break;
                   1252:        }
                   1253:        case XPATH_OP_FUNCTION: {
                   1254:            int nbargs = op->value;
                   1255:            const xmlChar *prefix = op->value5;
                   1256:            const xmlChar *name = op->value4;
                   1257: 
                   1258:            if (prefix != NULL)
                   1259:                fprintf(output, "FUNCTION %s:%s(%d args)",
                   1260:                        prefix, name, nbargs);
                   1261:            else
                   1262:                fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
                   1263:            break;
                   1264:        }
                   1265:         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
                   1266:         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
                   1267:         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
                   1268: #ifdef LIBXML_XPTR_ENABLED
                   1269:         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
                   1270: #endif
                   1271:        default:
                   1272:         fprintf(output, "UNKNOWN %d\n", op->op); return;
                   1273:     }
                   1274:     fprintf(output, "\n");
                   1275: finish:
                   1276:     if (op->ch1 >= 0)
                   1277:        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
                   1278:     if (op->ch2 >= 0)
                   1279:        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
                   1280: }
                   1281: 
                   1282: /**
                   1283:  * xmlXPathDebugDumpCompExpr:
                   1284:  * @output:  the FILE * for the output
                   1285:  * @comp:  the precompiled XPath expression
                   1286:  * @depth:  the indentation level.
                   1287:  *
                   1288:  * Dumps the tree of the compiled XPath expression.
                   1289:  */
                   1290: void
                   1291: xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
                   1292:                          int depth) {
                   1293:     int i;
                   1294:     char shift[100];
                   1295: 
                   1296:     if ((output == NULL) || (comp == NULL)) return;
                   1297: 
                   1298:     for (i = 0;((i < depth) && (i < 25));i++)
                   1299:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1300:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1301: 
                   1302:     fprintf(output, "%s", shift);
                   1303: 
                   1304:     fprintf(output, "Compiled Expression : %d elements\n",
                   1305:            comp->nbStep);
                   1306:     i = comp->last;
                   1307:     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
                   1308: }
                   1309: 
                   1310: #ifdef XP_DEBUG_OBJ_USAGE
                   1311: 
                   1312: /*
                   1313: * XPath object usage related debugging variables.
                   1314: */
                   1315: static int xmlXPathDebugObjCounterUndefined = 0;
                   1316: static int xmlXPathDebugObjCounterNodeset = 0;
                   1317: static int xmlXPathDebugObjCounterBool = 0;
                   1318: static int xmlXPathDebugObjCounterNumber = 0;
                   1319: static int xmlXPathDebugObjCounterString = 0;
                   1320: static int xmlXPathDebugObjCounterPoint = 0;
                   1321: static int xmlXPathDebugObjCounterRange = 0;
                   1322: static int xmlXPathDebugObjCounterLocset = 0;
                   1323: static int xmlXPathDebugObjCounterUsers = 0;
                   1324: static int xmlXPathDebugObjCounterXSLTTree = 0;
                   1325: static int xmlXPathDebugObjCounterAll = 0;
                   1326: 
                   1327: static int xmlXPathDebugObjTotalUndefined = 0;
                   1328: static int xmlXPathDebugObjTotalNodeset = 0;
                   1329: static int xmlXPathDebugObjTotalBool = 0;
                   1330: static int xmlXPathDebugObjTotalNumber = 0;
                   1331: static int xmlXPathDebugObjTotalString = 0;
                   1332: static int xmlXPathDebugObjTotalPoint = 0;
                   1333: static int xmlXPathDebugObjTotalRange = 0;
                   1334: static int xmlXPathDebugObjTotalLocset = 0;
                   1335: static int xmlXPathDebugObjTotalUsers = 0;
                   1336: static int xmlXPathDebugObjTotalXSLTTree = 0;
                   1337: static int xmlXPathDebugObjTotalAll = 0;
                   1338: 
                   1339: static int xmlXPathDebugObjMaxUndefined = 0;
                   1340: static int xmlXPathDebugObjMaxNodeset = 0;
                   1341: static int xmlXPathDebugObjMaxBool = 0;
                   1342: static int xmlXPathDebugObjMaxNumber = 0;
                   1343: static int xmlXPathDebugObjMaxString = 0;
                   1344: static int xmlXPathDebugObjMaxPoint = 0;
                   1345: static int xmlXPathDebugObjMaxRange = 0;
                   1346: static int xmlXPathDebugObjMaxLocset = 0;
                   1347: static int xmlXPathDebugObjMaxUsers = 0;
                   1348: static int xmlXPathDebugObjMaxXSLTTree = 0;
                   1349: static int xmlXPathDebugObjMaxAll = 0;
                   1350: 
                   1351: /* REVISIT TODO: Make this static when committing */
                   1352: static void
                   1353: xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
                   1354: {
                   1355:     if (ctxt != NULL) {
                   1356:        if (ctxt->cache != NULL) {
                   1357:            xmlXPathContextCachePtr cache =
                   1358:                (xmlXPathContextCachePtr) ctxt->cache;
                   1359: 
                   1360:            cache->dbgCachedAll = 0;
                   1361:            cache->dbgCachedNodeset = 0;
                   1362:            cache->dbgCachedString = 0;
                   1363:            cache->dbgCachedBool = 0;
                   1364:            cache->dbgCachedNumber = 0;
                   1365:            cache->dbgCachedPoint = 0;
                   1366:            cache->dbgCachedRange = 0;
                   1367:            cache->dbgCachedLocset = 0;
                   1368:            cache->dbgCachedUsers = 0;
                   1369:            cache->dbgCachedXSLTTree = 0;
                   1370:            cache->dbgCachedUndefined = 0;
                   1371: 
                   1372:            cache->dbgReusedAll = 0;
                   1373:            cache->dbgReusedNodeset = 0;
                   1374:            cache->dbgReusedString = 0;
                   1375:            cache->dbgReusedBool = 0;
                   1376:            cache->dbgReusedNumber = 0;
                   1377:            cache->dbgReusedPoint = 0;
                   1378:            cache->dbgReusedRange = 0;
                   1379:            cache->dbgReusedLocset = 0;
                   1380:            cache->dbgReusedUsers = 0;
                   1381:            cache->dbgReusedXSLTTree = 0;
                   1382:            cache->dbgReusedUndefined = 0;
                   1383:        }
                   1384:     }
                   1385: 
                   1386:     xmlXPathDebugObjCounterUndefined = 0;
                   1387:     xmlXPathDebugObjCounterNodeset = 0;
                   1388:     xmlXPathDebugObjCounterBool = 0;
                   1389:     xmlXPathDebugObjCounterNumber = 0;
                   1390:     xmlXPathDebugObjCounterString = 0;
                   1391:     xmlXPathDebugObjCounterPoint = 0;
                   1392:     xmlXPathDebugObjCounterRange = 0;
                   1393:     xmlXPathDebugObjCounterLocset = 0;
                   1394:     xmlXPathDebugObjCounterUsers = 0;
                   1395:     xmlXPathDebugObjCounterXSLTTree = 0;
                   1396:     xmlXPathDebugObjCounterAll = 0;
                   1397: 
                   1398:     xmlXPathDebugObjTotalUndefined = 0;
                   1399:     xmlXPathDebugObjTotalNodeset = 0;
                   1400:     xmlXPathDebugObjTotalBool = 0;
                   1401:     xmlXPathDebugObjTotalNumber = 0;
                   1402:     xmlXPathDebugObjTotalString = 0;
                   1403:     xmlXPathDebugObjTotalPoint = 0;
                   1404:     xmlXPathDebugObjTotalRange = 0;
                   1405:     xmlXPathDebugObjTotalLocset = 0;
                   1406:     xmlXPathDebugObjTotalUsers = 0;
                   1407:     xmlXPathDebugObjTotalXSLTTree = 0;
                   1408:     xmlXPathDebugObjTotalAll = 0;
                   1409: 
                   1410:     xmlXPathDebugObjMaxUndefined = 0;
                   1411:     xmlXPathDebugObjMaxNodeset = 0;
                   1412:     xmlXPathDebugObjMaxBool = 0;
                   1413:     xmlXPathDebugObjMaxNumber = 0;
                   1414:     xmlXPathDebugObjMaxString = 0;
                   1415:     xmlXPathDebugObjMaxPoint = 0;
                   1416:     xmlXPathDebugObjMaxRange = 0;
                   1417:     xmlXPathDebugObjMaxLocset = 0;
                   1418:     xmlXPathDebugObjMaxUsers = 0;
                   1419:     xmlXPathDebugObjMaxXSLTTree = 0;
                   1420:     xmlXPathDebugObjMaxAll = 0;
                   1421: 
                   1422: }
                   1423: 
                   1424: static void
                   1425: xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
                   1426:                              xmlXPathObjectType objType)
                   1427: {
                   1428:     int isCached = 0;
                   1429: 
                   1430:     if (ctxt != NULL) {
                   1431:        if (ctxt->cache != NULL) {
                   1432:            xmlXPathContextCachePtr cache =
                   1433:                (xmlXPathContextCachePtr) ctxt->cache;
                   1434: 
                   1435:            isCached = 1;
                   1436: 
                   1437:            cache->dbgReusedAll++;
                   1438:            switch (objType) {
                   1439:                case XPATH_UNDEFINED:
                   1440:                    cache->dbgReusedUndefined++;
                   1441:                    break;
                   1442:                case XPATH_NODESET:
                   1443:                    cache->dbgReusedNodeset++;
                   1444:                    break;
                   1445:                case XPATH_BOOLEAN:
                   1446:                    cache->dbgReusedBool++;
                   1447:                    break;
                   1448:                case XPATH_NUMBER:
                   1449:                    cache->dbgReusedNumber++;
                   1450:                    break;
                   1451:                case XPATH_STRING:
                   1452:                    cache->dbgReusedString++;
                   1453:                    break;
                   1454:                case XPATH_POINT:
                   1455:                    cache->dbgReusedPoint++;
                   1456:                    break;
                   1457:                case XPATH_RANGE:
                   1458:                    cache->dbgReusedRange++;
                   1459:                    break;
                   1460:                case XPATH_LOCATIONSET:
                   1461:                    cache->dbgReusedLocset++;
                   1462:                    break;
                   1463:                case XPATH_USERS:
                   1464:                    cache->dbgReusedUsers++;
                   1465:                    break;
                   1466:                case XPATH_XSLT_TREE:
                   1467:                    cache->dbgReusedXSLTTree++;
                   1468:                    break;
                   1469:                default:
                   1470:                    break;
                   1471:            }
                   1472:        }
                   1473:     }
                   1474: 
                   1475:     switch (objType) {
                   1476:        case XPATH_UNDEFINED:
                   1477:            if (! isCached)
                   1478:                xmlXPathDebugObjTotalUndefined++;
                   1479:            xmlXPathDebugObjCounterUndefined++;
                   1480:            if (xmlXPathDebugObjCounterUndefined >
                   1481:                xmlXPathDebugObjMaxUndefined)
                   1482:                xmlXPathDebugObjMaxUndefined =
                   1483:                    xmlXPathDebugObjCounterUndefined;
                   1484:            break;
                   1485:        case XPATH_NODESET:
                   1486:            if (! isCached)
                   1487:                xmlXPathDebugObjTotalNodeset++;
                   1488:            xmlXPathDebugObjCounterNodeset++;
                   1489:            if (xmlXPathDebugObjCounterNodeset >
                   1490:                xmlXPathDebugObjMaxNodeset)
                   1491:                xmlXPathDebugObjMaxNodeset =
                   1492:                    xmlXPathDebugObjCounterNodeset;
                   1493:            break;
                   1494:        case XPATH_BOOLEAN:
                   1495:            if (! isCached)
                   1496:                xmlXPathDebugObjTotalBool++;
                   1497:            xmlXPathDebugObjCounterBool++;
                   1498:            if (xmlXPathDebugObjCounterBool >
                   1499:                xmlXPathDebugObjMaxBool)
                   1500:                xmlXPathDebugObjMaxBool =
                   1501:                    xmlXPathDebugObjCounterBool;
                   1502:            break;
                   1503:        case XPATH_NUMBER:
                   1504:            if (! isCached)
                   1505:                xmlXPathDebugObjTotalNumber++;
                   1506:            xmlXPathDebugObjCounterNumber++;
                   1507:            if (xmlXPathDebugObjCounterNumber >
                   1508:                xmlXPathDebugObjMaxNumber)
                   1509:                xmlXPathDebugObjMaxNumber =
                   1510:                    xmlXPathDebugObjCounterNumber;
                   1511:            break;
                   1512:        case XPATH_STRING:
                   1513:            if (! isCached)
                   1514:                xmlXPathDebugObjTotalString++;
                   1515:            xmlXPathDebugObjCounterString++;
                   1516:            if (xmlXPathDebugObjCounterString >
                   1517:                xmlXPathDebugObjMaxString)
                   1518:                xmlXPathDebugObjMaxString =
                   1519:                    xmlXPathDebugObjCounterString;
                   1520:            break;
                   1521:        case XPATH_POINT:
                   1522:            if (! isCached)
                   1523:                xmlXPathDebugObjTotalPoint++;
                   1524:            xmlXPathDebugObjCounterPoint++;
                   1525:            if (xmlXPathDebugObjCounterPoint >
                   1526:                xmlXPathDebugObjMaxPoint)
                   1527:                xmlXPathDebugObjMaxPoint =
                   1528:                    xmlXPathDebugObjCounterPoint;
                   1529:            break;
                   1530:        case XPATH_RANGE:
                   1531:            if (! isCached)
                   1532:                xmlXPathDebugObjTotalRange++;
                   1533:            xmlXPathDebugObjCounterRange++;
                   1534:            if (xmlXPathDebugObjCounterRange >
                   1535:                xmlXPathDebugObjMaxRange)
                   1536:                xmlXPathDebugObjMaxRange =
                   1537:                    xmlXPathDebugObjCounterRange;
                   1538:            break;
                   1539:        case XPATH_LOCATIONSET:
                   1540:            if (! isCached)
                   1541:                xmlXPathDebugObjTotalLocset++;
                   1542:            xmlXPathDebugObjCounterLocset++;
                   1543:            if (xmlXPathDebugObjCounterLocset >
                   1544:                xmlXPathDebugObjMaxLocset)
                   1545:                xmlXPathDebugObjMaxLocset =
                   1546:                    xmlXPathDebugObjCounterLocset;
                   1547:            break;
                   1548:        case XPATH_USERS:
                   1549:            if (! isCached)
                   1550:                xmlXPathDebugObjTotalUsers++;
                   1551:            xmlXPathDebugObjCounterUsers++;
                   1552:            if (xmlXPathDebugObjCounterUsers >
                   1553:                xmlXPathDebugObjMaxUsers)
                   1554:                xmlXPathDebugObjMaxUsers =
                   1555:                    xmlXPathDebugObjCounterUsers;
                   1556:            break;
                   1557:        case XPATH_XSLT_TREE:
                   1558:            if (! isCached)
                   1559:                xmlXPathDebugObjTotalXSLTTree++;
                   1560:            xmlXPathDebugObjCounterXSLTTree++;
                   1561:            if (xmlXPathDebugObjCounterXSLTTree >
                   1562:                xmlXPathDebugObjMaxXSLTTree)
                   1563:                xmlXPathDebugObjMaxXSLTTree =
                   1564:                    xmlXPathDebugObjCounterXSLTTree;
                   1565:            break;
                   1566:        default:
                   1567:            break;
                   1568:     }
                   1569:     if (! isCached)
                   1570:        xmlXPathDebugObjTotalAll++;
                   1571:     xmlXPathDebugObjCounterAll++;
                   1572:     if (xmlXPathDebugObjCounterAll >
                   1573:        xmlXPathDebugObjMaxAll)
                   1574:        xmlXPathDebugObjMaxAll =
                   1575:            xmlXPathDebugObjCounterAll;
                   1576: }
                   1577: 
                   1578: static void
                   1579: xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
                   1580:                              xmlXPathObjectType objType)
                   1581: {
                   1582:     int isCached = 0;
                   1583: 
                   1584:     if (ctxt != NULL) {
                   1585:        if (ctxt->cache != NULL) {
                   1586:            xmlXPathContextCachePtr cache =
                   1587:                (xmlXPathContextCachePtr) ctxt->cache;
                   1588: 
                   1589:            isCached = 1;
                   1590: 
                   1591:            cache->dbgCachedAll++;
                   1592:            switch (objType) {
                   1593:                case XPATH_UNDEFINED:
                   1594:                    cache->dbgCachedUndefined++;
                   1595:                    break;
                   1596:                case XPATH_NODESET:
                   1597:                    cache->dbgCachedNodeset++;
                   1598:                    break;
                   1599:                case XPATH_BOOLEAN:
                   1600:                    cache->dbgCachedBool++;
                   1601:                    break;
                   1602:                case XPATH_NUMBER:
                   1603:                    cache->dbgCachedNumber++;
                   1604:                    break;
                   1605:                case XPATH_STRING:
                   1606:                    cache->dbgCachedString++;
                   1607:                    break;
                   1608:                case XPATH_POINT:
                   1609:                    cache->dbgCachedPoint++;
                   1610:                    break;
                   1611:                case XPATH_RANGE:
                   1612:                    cache->dbgCachedRange++;
                   1613:                    break;
                   1614:                case XPATH_LOCATIONSET:
                   1615:                    cache->dbgCachedLocset++;
                   1616:                    break;
                   1617:                case XPATH_USERS:
                   1618:                    cache->dbgCachedUsers++;
                   1619:                    break;
                   1620:                case XPATH_XSLT_TREE:
                   1621:                    cache->dbgCachedXSLTTree++;
                   1622:                    break;
                   1623:                default:
                   1624:                    break;
                   1625:            }
                   1626: 
                   1627:        }
                   1628:     }
                   1629:     switch (objType) {
                   1630:        case XPATH_UNDEFINED:
                   1631:            xmlXPathDebugObjCounterUndefined--;
                   1632:            break;
                   1633:        case XPATH_NODESET:
                   1634:            xmlXPathDebugObjCounterNodeset--;
                   1635:            break;
                   1636:        case XPATH_BOOLEAN:
                   1637:            xmlXPathDebugObjCounterBool--;
                   1638:            break;
                   1639:        case XPATH_NUMBER:
                   1640:            xmlXPathDebugObjCounterNumber--;
                   1641:            break;
                   1642:        case XPATH_STRING:
                   1643:            xmlXPathDebugObjCounterString--;
                   1644:            break;
                   1645:        case XPATH_POINT:
                   1646:            xmlXPathDebugObjCounterPoint--;
                   1647:            break;
                   1648:        case XPATH_RANGE:
                   1649:            xmlXPathDebugObjCounterRange--;
                   1650:            break;
                   1651:        case XPATH_LOCATIONSET:
                   1652:            xmlXPathDebugObjCounterLocset--;
                   1653:            break;
                   1654:        case XPATH_USERS:
                   1655:            xmlXPathDebugObjCounterUsers--;
                   1656:            break;
                   1657:        case XPATH_XSLT_TREE:
                   1658:            xmlXPathDebugObjCounterXSLTTree--;
                   1659:            break;
                   1660:        default:
                   1661:            break;
                   1662:     }
                   1663:     xmlXPathDebugObjCounterAll--;
                   1664: }
                   1665: 
                   1666: /* REVISIT TODO: Make this static when committing */
                   1667: static void
                   1668: xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
                   1669: {
                   1670:     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
                   1671:        reqXSLTTree, reqUndefined;
                   1672:     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
                   1673:        caNumber = 0, caXSLTTree = 0, caUndefined = 0;
                   1674:     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
                   1675:        reNumber = 0, reXSLTTree = 0, reUndefined = 0;
                   1676:     int leftObjs = xmlXPathDebugObjCounterAll;
                   1677: 
                   1678:     reqAll = xmlXPathDebugObjTotalAll;
                   1679:     reqNodeset = xmlXPathDebugObjTotalNodeset;
                   1680:     reqString = xmlXPathDebugObjTotalString;
                   1681:     reqBool = xmlXPathDebugObjTotalBool;
                   1682:     reqNumber = xmlXPathDebugObjTotalNumber;
                   1683:     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
                   1684:     reqUndefined = xmlXPathDebugObjTotalUndefined;
                   1685: 
                   1686:     printf("# XPath object usage:\n");
                   1687: 
                   1688:     if (ctxt != NULL) {
                   1689:        if (ctxt->cache != NULL) {
                   1690:            xmlXPathContextCachePtr cache =
                   1691:                (xmlXPathContextCachePtr) ctxt->cache;
                   1692: 
                   1693:            reAll = cache->dbgReusedAll;
                   1694:            reqAll += reAll;
                   1695:            reNodeset = cache->dbgReusedNodeset;
                   1696:            reqNodeset += reNodeset;
                   1697:            reString = cache->dbgReusedString;
                   1698:            reqString += reString;
                   1699:            reBool = cache->dbgReusedBool;
                   1700:            reqBool += reBool;
                   1701:            reNumber = cache->dbgReusedNumber;
                   1702:            reqNumber += reNumber;
                   1703:            reXSLTTree = cache->dbgReusedXSLTTree;
                   1704:            reqXSLTTree += reXSLTTree;
                   1705:            reUndefined = cache->dbgReusedUndefined;
                   1706:            reqUndefined += reUndefined;
                   1707: 
                   1708:            caAll = cache->dbgCachedAll;
                   1709:            caBool = cache->dbgCachedBool;
                   1710:            caNodeset = cache->dbgCachedNodeset;
                   1711:            caString = cache->dbgCachedString;
                   1712:            caNumber = cache->dbgCachedNumber;
                   1713:            caXSLTTree = cache->dbgCachedXSLTTree;
                   1714:            caUndefined = cache->dbgCachedUndefined;
                   1715: 
                   1716:            if (cache->nodesetObjs)
                   1717:                leftObjs -= cache->nodesetObjs->number;
                   1718:            if (cache->stringObjs)
                   1719:                leftObjs -= cache->stringObjs->number;
                   1720:            if (cache->booleanObjs)
                   1721:                leftObjs -= cache->booleanObjs->number;
                   1722:            if (cache->numberObjs)
                   1723:                leftObjs -= cache->numberObjs->number;
                   1724:            if (cache->miscObjs)
                   1725:                leftObjs -= cache->miscObjs->number;
                   1726:        }
                   1727:     }
                   1728: 
                   1729:     printf("# all\n");
                   1730:     printf("#   total  : %d\n", reqAll);
                   1731:     printf("#   left  : %d\n", leftObjs);
                   1732:     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
                   1733:     printf("#   reused : %d\n", reAll);
                   1734:     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
                   1735: 
                   1736:     printf("# node-sets\n");
                   1737:     printf("#   total  : %d\n", reqNodeset);
                   1738:     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
                   1739:     printf("#   reused : %d\n", reNodeset);
                   1740:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
                   1741: 
                   1742:     printf("# strings\n");
                   1743:     printf("#   total  : %d\n", reqString);
                   1744:     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
                   1745:     printf("#   reused : %d\n", reString);
                   1746:     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
                   1747: 
                   1748:     printf("# booleans\n");
                   1749:     printf("#   total  : %d\n", reqBool);
                   1750:     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
                   1751:     printf("#   reused : %d\n", reBool);
                   1752:     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
                   1753: 
                   1754:     printf("# numbers\n");
                   1755:     printf("#   total  : %d\n", reqNumber);
                   1756:     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
                   1757:     printf("#   reused : %d\n", reNumber);
                   1758:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
                   1759: 
                   1760:     printf("# XSLT result tree fragments\n");
                   1761:     printf("#   total  : %d\n", reqXSLTTree);
                   1762:     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
                   1763:     printf("#   reused : %d\n", reXSLTTree);
                   1764:     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
                   1765: 
                   1766:     printf("# undefined\n");
                   1767:     printf("#   total  : %d\n", reqUndefined);
                   1768:     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
                   1769:     printf("#   reused : %d\n", reUndefined);
                   1770:     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
                   1771: 
                   1772: }
                   1773: 
                   1774: #endif /* XP_DEBUG_OBJ_USAGE */
                   1775: 
                   1776: #endif /* LIBXML_DEBUG_ENABLED */
                   1777: 
                   1778: /************************************************************************
                   1779:  *                                                                     *
                   1780:  *                     XPath object caching                            *
                   1781:  *                                                                     *
                   1782:  ************************************************************************/
                   1783: 
                   1784: /**
                   1785:  * xmlXPathNewCache:
                   1786:  *
                   1787:  * Create a new object cache
                   1788:  *
                   1789:  * Returns the xmlXPathCache just allocated.
                   1790:  */
                   1791: static xmlXPathContextCachePtr
                   1792: xmlXPathNewCache(void)
                   1793: {
                   1794:     xmlXPathContextCachePtr ret;
                   1795: 
                   1796:     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
                   1797:     if (ret == NULL) {
                   1798:         xmlXPathErrMemory(NULL, "creating object cache\n");
                   1799:        return(NULL);
                   1800:     }
                   1801:     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
                   1802:     ret->maxNodeset = 100;
                   1803:     ret->maxString = 100;
                   1804:     ret->maxBoolean = 100;
                   1805:     ret->maxNumber = 100;
                   1806:     ret->maxMisc = 100;
                   1807:     return(ret);
                   1808: }
                   1809: 
                   1810: static void
                   1811: xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
                   1812: {
                   1813:     int i;
                   1814:     xmlXPathObjectPtr obj;
                   1815: 
                   1816:     if (list == NULL)
                   1817:        return;
                   1818: 
                   1819:     for (i = 0; i < list->number; i++) {
                   1820:        obj = list->items[i];
                   1821:        /*
                   1822:        * Note that it is already assured that we don't need to
                   1823:        * look out for namespace nodes in the node-set.
                   1824:        */
                   1825:        if (obj->nodesetval != NULL) {
                   1826:            if (obj->nodesetval->nodeTab != NULL)
                   1827:                xmlFree(obj->nodesetval->nodeTab);
                   1828:            xmlFree(obj->nodesetval);
                   1829:        }
                   1830:        xmlFree(obj);
                   1831: #ifdef XP_DEBUG_OBJ_USAGE
                   1832:        xmlXPathDebugObjCounterAll--;
                   1833: #endif
                   1834:     }
                   1835:     xmlPointerListFree(list);
                   1836: }
                   1837: 
                   1838: static void
                   1839: xmlXPathFreeCache(xmlXPathContextCachePtr cache)
                   1840: {
                   1841:     if (cache == NULL)
                   1842:        return;
                   1843:     if (cache->nodesetObjs)
                   1844:        xmlXPathCacheFreeObjectList(cache->nodesetObjs);
                   1845:     if (cache->stringObjs)
                   1846:        xmlXPathCacheFreeObjectList(cache->stringObjs);
                   1847:     if (cache->booleanObjs)
                   1848:        xmlXPathCacheFreeObjectList(cache->booleanObjs);
                   1849:     if (cache->numberObjs)
                   1850:        xmlXPathCacheFreeObjectList(cache->numberObjs);
                   1851:     if (cache->miscObjs)
                   1852:        xmlXPathCacheFreeObjectList(cache->miscObjs);
                   1853:     xmlFree(cache);
                   1854: }
                   1855: 
                   1856: /**
                   1857:  * xmlXPathContextSetCache:
                   1858:  *
                   1859:  * @ctxt:  the XPath context
                   1860:  * @active: enables/disables (creates/frees) the cache
                   1861:  * @value: a value with semantics dependant on @options
                   1862:  * @options: options (currently only the value 0 is used)
                   1863:  *
                   1864:  * Creates/frees an object cache on the XPath context.
                   1865:  * If activates XPath objects (xmlXPathObject) will be cached internally
                   1866:  * to be reused.
                   1867:  * @options:
                   1868:  *   0: This will set the XPath object caching:
                   1869:  *      @value:
                   1870:  *        This will set the maximum number of XPath objects
                   1871:  *        to be cached per slot
                   1872:  *        There are 5 slots for: node-set, string, number, boolean, and
                   1873:  *        misc objects. Use <0 for the default number (100).
                   1874:  *   Other values for @options have currently no effect.
                   1875:  *
                   1876:  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
                   1877:  */
                   1878: int
                   1879: xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
                   1880:                        int active,
                   1881:                        int value,
                   1882:                        int options)
                   1883: {
                   1884:     if (ctxt == NULL)
                   1885:        return(-1);
                   1886:     if (active) {
                   1887:        xmlXPathContextCachePtr cache;
                   1888: 
                   1889:        if (ctxt->cache == NULL) {
                   1890:            ctxt->cache = xmlXPathNewCache();
                   1891:            if (ctxt->cache == NULL)
                   1892:                return(-1);
                   1893:        }
                   1894:        cache = (xmlXPathContextCachePtr) ctxt->cache;
                   1895:        if (options == 0) {
                   1896:            if (value < 0)
                   1897:                value = 100;
                   1898:            cache->maxNodeset = value;
                   1899:            cache->maxString = value;
                   1900:            cache->maxNumber = value;
                   1901:            cache->maxBoolean = value;
                   1902:            cache->maxMisc = value;
                   1903:        }
                   1904:     } else if (ctxt->cache != NULL) {
                   1905:        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
                   1906:        ctxt->cache = NULL;
                   1907:     }
                   1908:     return(0);
                   1909: }
                   1910: 
                   1911: /**
                   1912:  * xmlXPathCacheWrapNodeSet:
                   1913:  * @ctxt: the XPath context
                   1914:  * @val:  the NodePtr value
                   1915:  *
                   1916:  * This is the cached version of xmlXPathWrapNodeSet().
                   1917:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
                   1918:  *
                   1919:  * Returns the created or reused object.
                   1920:  */
                   1921: static xmlXPathObjectPtr
                   1922: xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
                   1923: {
                   1924:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
                   1925:        xmlXPathContextCachePtr cache =
                   1926:            (xmlXPathContextCachePtr) ctxt->cache;
                   1927: 
                   1928:        if ((cache->miscObjs != NULL) &&
                   1929:            (cache->miscObjs->number != 0))
                   1930:        {
                   1931:            xmlXPathObjectPtr ret;
                   1932: 
                   1933:            ret = (xmlXPathObjectPtr)
                   1934:                cache->miscObjs->items[--cache->miscObjs->number];
                   1935:            ret->type = XPATH_NODESET;
                   1936:            ret->nodesetval = val;
                   1937: #ifdef XP_DEBUG_OBJ_USAGE
                   1938:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
                   1939: #endif
                   1940:            return(ret);
                   1941:        }
                   1942:     }
                   1943: 
                   1944:     return(xmlXPathWrapNodeSet(val));
                   1945: 
                   1946: }
                   1947: 
                   1948: /**
                   1949:  * xmlXPathCacheWrapString:
                   1950:  * @ctxt: the XPath context
                   1951:  * @val:  the xmlChar * value
                   1952:  *
                   1953:  * This is the cached version of xmlXPathWrapString().
                   1954:  * Wraps the @val string into an XPath object.
                   1955:  *
                   1956:  * Returns the created or reused object.
                   1957:  */
                   1958: static xmlXPathObjectPtr
                   1959: xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
                   1960: {
                   1961:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
                   1962:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   1963: 
                   1964:        if ((cache->stringObjs != NULL) &&
                   1965:            (cache->stringObjs->number != 0))
                   1966:        {
                   1967: 
                   1968:            xmlXPathObjectPtr ret;
                   1969: 
                   1970:            ret = (xmlXPathObjectPtr)
                   1971:                cache->stringObjs->items[--cache->stringObjs->number];
                   1972:            ret->type = XPATH_STRING;
                   1973:            ret->stringval = val;
                   1974: #ifdef XP_DEBUG_OBJ_USAGE
                   1975:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   1976: #endif
                   1977:            return(ret);
                   1978:        } else if ((cache->miscObjs != NULL) &&
                   1979:            (cache->miscObjs->number != 0))
                   1980:        {
                   1981:            xmlXPathObjectPtr ret;
                   1982:            /*
                   1983:            * Fallback to misc-cache.
                   1984:            */
                   1985:            ret = (xmlXPathObjectPtr)
                   1986:                cache->miscObjs->items[--cache->miscObjs->number];
                   1987: 
                   1988:            ret->type = XPATH_STRING;
                   1989:            ret->stringval = val;
                   1990: #ifdef XP_DEBUG_OBJ_USAGE
                   1991:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   1992: #endif
                   1993:            return(ret);
                   1994:        }
                   1995:     }
                   1996:     return(xmlXPathWrapString(val));
                   1997: }
                   1998: 
                   1999: /**
                   2000:  * xmlXPathCacheNewNodeSet:
                   2001:  * @ctxt: the XPath context
                   2002:  * @val:  the NodePtr value
                   2003:  *
                   2004:  * This is the cached version of xmlXPathNewNodeSet().
                   2005:  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
                   2006:  * it with the single Node @val
                   2007:  *
                   2008:  * Returns the created or reused object.
                   2009:  */
                   2010: static xmlXPathObjectPtr
                   2011: xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
                   2012: {
                   2013:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2014:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2015: 
                   2016:        if ((cache->nodesetObjs != NULL) &&
                   2017:            (cache->nodesetObjs->number != 0))
                   2018:        {
                   2019:            xmlXPathObjectPtr ret;
                   2020:            /*
                   2021:            * Use the nodset-cache.
                   2022:            */
                   2023:            ret = (xmlXPathObjectPtr)
                   2024:                cache->nodesetObjs->items[--cache->nodesetObjs->number];
                   2025:            ret->type = XPATH_NODESET;
                   2026:            ret->boolval = 0;
                   2027:            if (val) {
                   2028:                if ((ret->nodesetval->nodeMax == 0) ||
                   2029:                    (val->type == XML_NAMESPACE_DECL))
                   2030:                {
                   2031:                    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
                   2032:                } else {
                   2033:                    ret->nodesetval->nodeTab[0] = val;
                   2034:                    ret->nodesetval->nodeNr = 1;
                   2035:                }
                   2036:            }
                   2037: #ifdef XP_DEBUG_OBJ_USAGE
                   2038:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
                   2039: #endif
                   2040:            return(ret);
                   2041:        } else if ((cache->miscObjs != NULL) &&
                   2042:            (cache->miscObjs->number != 0))
                   2043:        {
                   2044:            xmlXPathObjectPtr ret;
                   2045:            /*
                   2046:            * Fallback to misc-cache.
                   2047:            */
                   2048: 
                   2049:            ret = (xmlXPathObjectPtr)
                   2050:                cache->miscObjs->items[--cache->miscObjs->number];
                   2051: 
                   2052:            ret->type = XPATH_NODESET;
                   2053:            ret->boolval = 0;
                   2054:            ret->nodesetval = xmlXPathNodeSetCreate(val);
                   2055: #ifdef XP_DEBUG_OBJ_USAGE
                   2056:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
                   2057: #endif
                   2058:            return(ret);
                   2059:        }
                   2060:     }
                   2061:     return(xmlXPathNewNodeSet(val));
                   2062: }
                   2063: 
                   2064: /**
                   2065:  * xmlXPathCacheNewCString:
                   2066:  * @ctxt: the XPath context
                   2067:  * @val:  the char * value
                   2068:  *
                   2069:  * This is the cached version of xmlXPathNewCString().
                   2070:  * Acquire an xmlXPathObjectPtr of type string and of value @val
                   2071:  *
                   2072:  * Returns the created or reused object.
                   2073:  */
                   2074: static xmlXPathObjectPtr
                   2075: xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
                   2076: {
                   2077:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2078:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2079: 
                   2080:        if ((cache->stringObjs != NULL) &&
                   2081:            (cache->stringObjs->number != 0))
                   2082:        {
                   2083:            xmlXPathObjectPtr ret;
                   2084: 
                   2085:            ret = (xmlXPathObjectPtr)
                   2086:                cache->stringObjs->items[--cache->stringObjs->number];
                   2087: 
                   2088:            ret->type = XPATH_STRING;
                   2089:            ret->stringval = xmlStrdup(BAD_CAST val);
                   2090: #ifdef XP_DEBUG_OBJ_USAGE
                   2091:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2092: #endif
                   2093:            return(ret);
                   2094:        } else if ((cache->miscObjs != NULL) &&
                   2095:            (cache->miscObjs->number != 0))
                   2096:        {
                   2097:            xmlXPathObjectPtr ret;
                   2098: 
                   2099:            ret = (xmlXPathObjectPtr)
                   2100:                cache->miscObjs->items[--cache->miscObjs->number];
                   2101: 
                   2102:            ret->type = XPATH_STRING;
                   2103:            ret->stringval = xmlStrdup(BAD_CAST val);
                   2104: #ifdef XP_DEBUG_OBJ_USAGE
                   2105:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2106: #endif
                   2107:            return(ret);
                   2108:        }
                   2109:     }
                   2110:     return(xmlXPathNewCString(val));
                   2111: }
                   2112: 
                   2113: /**
                   2114:  * xmlXPathCacheNewString:
                   2115:  * @ctxt: the XPath context
                   2116:  * @val:  the xmlChar * value
                   2117:  *
                   2118:  * This is the cached version of xmlXPathNewString().
                   2119:  * Acquire an xmlXPathObjectPtr of type string and of value @val
                   2120:  *
                   2121:  * Returns the created or reused object.
                   2122:  */
                   2123: static xmlXPathObjectPtr
                   2124: xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
                   2125: {
                   2126:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2127:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2128: 
                   2129:        if ((cache->stringObjs != NULL) &&
                   2130:            (cache->stringObjs->number != 0))
                   2131:        {
                   2132:            xmlXPathObjectPtr ret;
                   2133: 
                   2134:            ret = (xmlXPathObjectPtr)
                   2135:                cache->stringObjs->items[--cache->stringObjs->number];
                   2136:            ret->type = XPATH_STRING;
                   2137:            if (val != NULL)
                   2138:                ret->stringval = xmlStrdup(val);
                   2139:            else
                   2140:                ret->stringval = xmlStrdup((const xmlChar *)"");
                   2141: #ifdef XP_DEBUG_OBJ_USAGE
                   2142:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2143: #endif
                   2144:            return(ret);
                   2145:        } else if ((cache->miscObjs != NULL) &&
                   2146:            (cache->miscObjs->number != 0))
                   2147:        {
                   2148:            xmlXPathObjectPtr ret;
                   2149: 
                   2150:            ret = (xmlXPathObjectPtr)
                   2151:                cache->miscObjs->items[--cache->miscObjs->number];
                   2152: 
                   2153:            ret->type = XPATH_STRING;
                   2154:            if (val != NULL)
                   2155:                ret->stringval = xmlStrdup(val);
                   2156:            else
                   2157:                ret->stringval = xmlStrdup((const xmlChar *)"");
                   2158: #ifdef XP_DEBUG_OBJ_USAGE
                   2159:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2160: #endif
                   2161:            return(ret);
                   2162:        }
                   2163:     }
                   2164:     return(xmlXPathNewString(val));
                   2165: }
                   2166: 
                   2167: /**
                   2168:  * xmlXPathCacheNewBoolean:
                   2169:  * @ctxt: the XPath context
                   2170:  * @val:  the boolean value
                   2171:  *
                   2172:  * This is the cached version of xmlXPathNewBoolean().
                   2173:  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
                   2174:  *
                   2175:  * Returns the created or reused object.
                   2176:  */
                   2177: static xmlXPathObjectPtr
                   2178: xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
                   2179: {
                   2180:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2181:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2182: 
                   2183:        if ((cache->booleanObjs != NULL) &&
                   2184:            (cache->booleanObjs->number != 0))
                   2185:        {
                   2186:            xmlXPathObjectPtr ret;
                   2187: 
                   2188:            ret = (xmlXPathObjectPtr)
                   2189:                cache->booleanObjs->items[--cache->booleanObjs->number];
                   2190:            ret->type = XPATH_BOOLEAN;
                   2191:            ret->boolval = (val != 0);
                   2192: #ifdef XP_DEBUG_OBJ_USAGE
                   2193:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
                   2194: #endif
                   2195:            return(ret);
                   2196:        } else if ((cache->miscObjs != NULL) &&
                   2197:            (cache->miscObjs->number != 0))
                   2198:        {
                   2199:            xmlXPathObjectPtr ret;
                   2200: 
                   2201:            ret = (xmlXPathObjectPtr)
                   2202:                cache->miscObjs->items[--cache->miscObjs->number];
                   2203: 
                   2204:            ret->type = XPATH_BOOLEAN;
                   2205:            ret->boolval = (val != 0);
                   2206: #ifdef XP_DEBUG_OBJ_USAGE
                   2207:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
                   2208: #endif
                   2209:            return(ret);
                   2210:        }
                   2211:     }
                   2212:     return(xmlXPathNewBoolean(val));
                   2213: }
                   2214: 
                   2215: /**
                   2216:  * xmlXPathCacheNewFloat:
                   2217:  * @ctxt: the XPath context
                   2218:  * @val:  the double value
                   2219:  *
                   2220:  * This is the cached version of xmlXPathNewFloat().
                   2221:  * Acquires an xmlXPathObjectPtr of type double and of value @val
                   2222:  *
                   2223:  * Returns the created or reused object.
                   2224:  */
                   2225: static xmlXPathObjectPtr
                   2226: xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
                   2227: {
                   2228:      if ((ctxt != NULL) && (ctxt->cache)) {
                   2229:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2230: 
                   2231:        if ((cache->numberObjs != NULL) &&
                   2232:            (cache->numberObjs->number != 0))
                   2233:        {
                   2234:            xmlXPathObjectPtr ret;
                   2235: 
                   2236:            ret = (xmlXPathObjectPtr)
                   2237:                cache->numberObjs->items[--cache->numberObjs->number];
                   2238:            ret->type = XPATH_NUMBER;
                   2239:            ret->floatval = val;
                   2240: #ifdef XP_DEBUG_OBJ_USAGE
                   2241:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
                   2242: #endif
                   2243:            return(ret);
                   2244:        } else if ((cache->miscObjs != NULL) &&
                   2245:            (cache->miscObjs->number != 0))
                   2246:        {
                   2247:            xmlXPathObjectPtr ret;
                   2248: 
                   2249:            ret = (xmlXPathObjectPtr)
                   2250:                cache->miscObjs->items[--cache->miscObjs->number];
                   2251: 
                   2252:            ret->type = XPATH_NUMBER;
                   2253:            ret->floatval = val;
                   2254: #ifdef XP_DEBUG_OBJ_USAGE
                   2255:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
                   2256: #endif
                   2257:            return(ret);
                   2258:        }
                   2259:     }
                   2260:     return(xmlXPathNewFloat(val));
                   2261: }
                   2262: 
                   2263: /**
                   2264:  * xmlXPathCacheConvertString:
                   2265:  * @ctxt: the XPath context
                   2266:  * @val:  an XPath object
                   2267:  *
                   2268:  * This is the cached version of xmlXPathConvertString().
                   2269:  * Converts an existing object to its string() equivalent
                   2270:  *
                   2271:  * Returns a created or reused object, the old one is freed (cached)
                   2272:  *         (or the operation is done directly on @val)
                   2273:  */
                   2274: 
                   2275: static xmlXPathObjectPtr
                   2276: xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
                   2277:     xmlChar *res = NULL;
                   2278: 
                   2279:     if (val == NULL)
                   2280:        return(xmlXPathCacheNewCString(ctxt, ""));
                   2281: 
                   2282:     switch (val->type) {
                   2283:     case XPATH_UNDEFINED:
                   2284: #ifdef DEBUG_EXPR
                   2285:        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
                   2286: #endif
                   2287:        break;
                   2288:     case XPATH_NODESET:
                   2289:     case XPATH_XSLT_TREE:
                   2290:        res = xmlXPathCastNodeSetToString(val->nodesetval);
                   2291:        break;
                   2292:     case XPATH_STRING:
                   2293:        return(val);
                   2294:     case XPATH_BOOLEAN:
                   2295:        res = xmlXPathCastBooleanToString(val->boolval);
                   2296:        break;
                   2297:     case XPATH_NUMBER:
                   2298:        res = xmlXPathCastNumberToString(val->floatval);
                   2299:        break;
                   2300:     case XPATH_USERS:
                   2301:     case XPATH_POINT:
                   2302:     case XPATH_RANGE:
                   2303:     case XPATH_LOCATIONSET:
                   2304:        TODO;
                   2305:        break;
                   2306:     }
                   2307:     xmlXPathReleaseObject(ctxt, val);
                   2308:     if (res == NULL)
                   2309:        return(xmlXPathCacheNewCString(ctxt, ""));
                   2310:     return(xmlXPathCacheWrapString(ctxt, res));
                   2311: }
                   2312: 
                   2313: /**
                   2314:  * xmlXPathCacheObjectCopy:
                   2315:  * @ctxt: the XPath context
                   2316:  * @val:  the original object
                   2317:  *
                   2318:  * This is the cached version of xmlXPathObjectCopy().
                   2319:  * Acquire a copy of a given object
                   2320:  *
                   2321:  * Returns a created or reused created object.
                   2322:  */
                   2323: static xmlXPathObjectPtr
                   2324: xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
                   2325: {
                   2326:     if (val == NULL)
                   2327:        return(NULL);
                   2328: 
                   2329:     if (XP_HAS_CACHE(ctxt)) {
                   2330:        switch (val->type) {
                   2331:            case XPATH_NODESET:
                   2332:                return(xmlXPathCacheWrapNodeSet(ctxt,
                   2333:                    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
                   2334:            case XPATH_STRING:
                   2335:                return(xmlXPathCacheNewString(ctxt, val->stringval));
                   2336:            case XPATH_BOOLEAN:
                   2337:                return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
                   2338:            case XPATH_NUMBER:
                   2339:                return(xmlXPathCacheNewFloat(ctxt, val->floatval));
                   2340:            default:
                   2341:                break;
                   2342:        }
                   2343:     }
                   2344:     return(xmlXPathObjectCopy(val));
                   2345: }
                   2346: 
                   2347: /**
                   2348:  * xmlXPathCacheConvertBoolean:
                   2349:  * @ctxt: the XPath context
                   2350:  * @val:  an XPath object
                   2351:  *
                   2352:  * This is the cached version of xmlXPathConvertBoolean().
                   2353:  * Converts an existing object to its boolean() equivalent
                   2354:  *
                   2355:  * Returns a created or reused object, the old one is freed (or the operation
                   2356:  *         is done directly on @val)
                   2357:  */
                   2358: static xmlXPathObjectPtr
                   2359: xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
                   2360:     xmlXPathObjectPtr ret;
                   2361: 
                   2362:     if (val == NULL)
                   2363:        return(xmlXPathCacheNewBoolean(ctxt, 0));
                   2364:     if (val->type == XPATH_BOOLEAN)
                   2365:        return(val);
                   2366:     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
                   2367:     xmlXPathReleaseObject(ctxt, val);
                   2368:     return(ret);
                   2369: }
                   2370: 
                   2371: /**
                   2372:  * xmlXPathCacheConvertNumber:
                   2373:  * @ctxt: the XPath context
                   2374:  * @val:  an XPath object
                   2375:  *
                   2376:  * This is the cached version of xmlXPathConvertNumber().
                   2377:  * Converts an existing object to its number() equivalent
                   2378:  *
                   2379:  * Returns a created or reused object, the old one is freed (or the operation
                   2380:  *         is done directly on @val)
                   2381:  */
                   2382: static xmlXPathObjectPtr
                   2383: xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
                   2384:     xmlXPathObjectPtr ret;
                   2385: 
                   2386:     if (val == NULL)
                   2387:        return(xmlXPathCacheNewFloat(ctxt, 0.0));
                   2388:     if (val->type == XPATH_NUMBER)
                   2389:        return(val);
                   2390:     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
                   2391:     xmlXPathReleaseObject(ctxt, val);
                   2392:     return(ret);
                   2393: }
                   2394: 
                   2395: /************************************************************************
                   2396:  *                                                                     *
                   2397:  *             Parser stacks related functions and macros              *
                   2398:  *                                                                     *
                   2399:  ************************************************************************/
                   2400: 
                   2401: /**
1.1.1.2 ! misho    2402:  * xmlXPathSetFrame:
        !          2403:  * @ctxt: an XPath parser context
        !          2404:  *
        !          2405:  * Set the callee evaluation frame
        !          2406:  *
        !          2407:  * Returns the previous frame value to be restored once done
        !          2408:  */
        !          2409: static int
        !          2410: xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
        !          2411:     int ret;
        !          2412: 
        !          2413:     if (ctxt == NULL)
        !          2414:         return(0);
        !          2415:     ret = ctxt->valueFrame;
        !          2416:     ctxt->valueFrame = ctxt->valueNr;
        !          2417:     return(ret);
        !          2418: }
        !          2419: 
        !          2420: /**
        !          2421:  * xmlXPathPopFrame:
        !          2422:  * @ctxt: an XPath parser context
        !          2423:  * @frame: the previous frame value
        !          2424:  *
        !          2425:  * Remove the callee evaluation frame
        !          2426:  */
        !          2427: static void
        !          2428: xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
        !          2429:     if (ctxt == NULL)
        !          2430:         return;
        !          2431:     if (ctxt->valueNr < ctxt->valueFrame) {
        !          2432:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
        !          2433:     }
        !          2434:     ctxt->valueFrame = frame;
        !          2435: }
        !          2436: 
        !          2437: /**
1.1       misho    2438:  * valuePop:
                   2439:  * @ctxt: an XPath evaluation context
                   2440:  *
                   2441:  * Pops the top XPath object from the value stack
                   2442:  *
                   2443:  * Returns the XPath object just removed
                   2444:  */
                   2445: xmlXPathObjectPtr
                   2446: valuePop(xmlXPathParserContextPtr ctxt)
                   2447: {
                   2448:     xmlXPathObjectPtr ret;
                   2449: 
                   2450:     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
                   2451:         return (NULL);
1.1.1.2 ! misho    2452: 
        !          2453:     if (ctxt->valueNr <= ctxt->valueFrame) {
        !          2454:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
        !          2455:         return (NULL);
        !          2456:     }
        !          2457: 
1.1       misho    2458:     ctxt->valueNr--;
                   2459:     if (ctxt->valueNr > 0)
                   2460:         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
                   2461:     else
                   2462:         ctxt->value = NULL;
                   2463:     ret = ctxt->valueTab[ctxt->valueNr];
                   2464:     ctxt->valueTab[ctxt->valueNr] = NULL;
                   2465:     return (ret);
                   2466: }
                   2467: /**
                   2468:  * valuePush:
                   2469:  * @ctxt:  an XPath evaluation context
                   2470:  * @value:  the XPath object
                   2471:  *
                   2472:  * Pushes a new XPath object on top of the value stack
                   2473:  *
                   2474:  * returns the number of items on the value stack
                   2475:  */
                   2476: int
                   2477: valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
                   2478: {
                   2479:     if ((ctxt == NULL) || (value == NULL)) return(-1);
                   2480:     if (ctxt->valueNr >= ctxt->valueMax) {
                   2481:         xmlXPathObjectPtr *tmp;
                   2482: 
                   2483:         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
                   2484:                                              2 * ctxt->valueMax *
                   2485:                                              sizeof(ctxt->valueTab[0]));
                   2486:         if (tmp == NULL) {
                   2487:             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1.1.1.2 ! misho    2488:             ctxt->error = XPATH_MEMORY_ERROR;
1.1       misho    2489:             return (0);
                   2490:         }
                   2491:         ctxt->valueMax *= 2;
                   2492:        ctxt->valueTab = tmp;
                   2493:     }
                   2494:     ctxt->valueTab[ctxt->valueNr] = value;
                   2495:     ctxt->value = value;
                   2496:     return (ctxt->valueNr++);
                   2497: }
                   2498: 
                   2499: /**
                   2500:  * xmlXPathPopBoolean:
                   2501:  * @ctxt:  an XPath parser context
                   2502:  *
                   2503:  * Pops a boolean from the stack, handling conversion if needed.
                   2504:  * Check error with #xmlXPathCheckError.
                   2505:  *
                   2506:  * Returns the boolean
                   2507:  */
                   2508: int
                   2509: xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
                   2510:     xmlXPathObjectPtr obj;
                   2511:     int ret;
                   2512: 
                   2513:     obj = valuePop(ctxt);
                   2514:     if (obj == NULL) {
                   2515:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2516:        return(0);
                   2517:     }
                   2518:     if (obj->type != XPATH_BOOLEAN)
                   2519:        ret = xmlXPathCastToBoolean(obj);
                   2520:     else
                   2521:         ret = obj->boolval;
                   2522:     xmlXPathReleaseObject(ctxt->context, obj);
                   2523:     return(ret);
                   2524: }
                   2525: 
                   2526: /**
                   2527:  * xmlXPathPopNumber:
                   2528:  * @ctxt:  an XPath parser context
                   2529:  *
                   2530:  * Pops a number from the stack, handling conversion if needed.
                   2531:  * Check error with #xmlXPathCheckError.
                   2532:  *
                   2533:  * Returns the number
                   2534:  */
                   2535: double
                   2536: xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
                   2537:     xmlXPathObjectPtr obj;
                   2538:     double ret;
                   2539: 
                   2540:     obj = valuePop(ctxt);
                   2541:     if (obj == NULL) {
                   2542:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2543:        return(0);
                   2544:     }
                   2545:     if (obj->type != XPATH_NUMBER)
                   2546:        ret = xmlXPathCastToNumber(obj);
                   2547:     else
                   2548:         ret = obj->floatval;
                   2549:     xmlXPathReleaseObject(ctxt->context, obj);
                   2550:     return(ret);
                   2551: }
                   2552: 
                   2553: /**
                   2554:  * xmlXPathPopString:
                   2555:  * @ctxt:  an XPath parser context
                   2556:  *
                   2557:  * Pops a string from the stack, handling conversion if needed.
                   2558:  * Check error with #xmlXPathCheckError.
                   2559:  *
                   2560:  * Returns the string
                   2561:  */
                   2562: xmlChar *
                   2563: xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
                   2564:     xmlXPathObjectPtr obj;
                   2565:     xmlChar * ret;
                   2566: 
                   2567:     obj = valuePop(ctxt);
                   2568:     if (obj == NULL) {
                   2569:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2570:        return(NULL);
                   2571:     }
                   2572:     ret = xmlXPathCastToString(obj);   /* this does required strdup */
                   2573:     /* TODO: needs refactoring somewhere else */
                   2574:     if (obj->stringval == ret)
                   2575:        obj->stringval = NULL;
                   2576:     xmlXPathReleaseObject(ctxt->context, obj);
                   2577:     return(ret);
                   2578: }
                   2579: 
                   2580: /**
                   2581:  * xmlXPathPopNodeSet:
                   2582:  * @ctxt:  an XPath parser context
                   2583:  *
                   2584:  * Pops a node-set from the stack, handling conversion if needed.
                   2585:  * Check error with #xmlXPathCheckError.
                   2586:  *
                   2587:  * Returns the node-set
                   2588:  */
                   2589: xmlNodeSetPtr
                   2590: xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
                   2591:     xmlXPathObjectPtr obj;
                   2592:     xmlNodeSetPtr ret;
                   2593: 
                   2594:     if (ctxt == NULL) return(NULL);
                   2595:     if (ctxt->value == NULL) {
                   2596:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2597:        return(NULL);
                   2598:     }
                   2599:     if (!xmlXPathStackIsNodeSet(ctxt)) {
                   2600:        xmlXPathSetTypeError(ctxt);
                   2601:        return(NULL);
                   2602:     }
                   2603:     obj = valuePop(ctxt);
                   2604:     ret = obj->nodesetval;
                   2605: #if 0
                   2606:     /* to fix memory leak of not clearing obj->user */
                   2607:     if (obj->boolval && obj->user != NULL)
                   2608:         xmlFreeNodeList((xmlNodePtr) obj->user);
                   2609: #endif
                   2610:     obj->nodesetval = NULL;
                   2611:     xmlXPathReleaseObject(ctxt->context, obj);
                   2612:     return(ret);
                   2613: }
                   2614: 
                   2615: /**
                   2616:  * xmlXPathPopExternal:
                   2617:  * @ctxt:  an XPath parser context
                   2618:  *
                   2619:  * Pops an external object from the stack, handling conversion if needed.
                   2620:  * Check error with #xmlXPathCheckError.
                   2621:  *
                   2622:  * Returns the object
                   2623:  */
                   2624: void *
                   2625: xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
                   2626:     xmlXPathObjectPtr obj;
                   2627:     void * ret;
                   2628: 
                   2629:     if ((ctxt == NULL) || (ctxt->value == NULL)) {
                   2630:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2631:        return(NULL);
                   2632:     }
                   2633:     if (ctxt->value->type != XPATH_USERS) {
                   2634:        xmlXPathSetTypeError(ctxt);
                   2635:        return(NULL);
                   2636:     }
                   2637:     obj = valuePop(ctxt);
                   2638:     ret = obj->user;
                   2639:     obj->user = NULL;
                   2640:     xmlXPathReleaseObject(ctxt->context, obj);
                   2641:     return(ret);
                   2642: }
                   2643: 
                   2644: /*
                   2645:  * Macros for accessing the content. Those should be used only by the parser,
                   2646:  * and not exported.
                   2647:  *
                   2648:  * Dirty macros, i.e. one need to make assumption on the context to use them
                   2649:  *
                   2650:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
                   2651:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
                   2652:  *           in ISO-Latin or UTF-8.
                   2653:  *           This should be used internally by the parser
                   2654:  *           only to compare to ASCII values otherwise it would break when
                   2655:  *           running with UTF-8 encoding.
                   2656:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
                   2657:  *           to compare on ASCII based substring.
                   2658:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
                   2659:  *           strings within the parser.
                   2660:  *   CURRENT Returns the current char value, with the full decoding of
                   2661:  *           UTF-8 if we are using this mode. It returns an int.
                   2662:  *   NEXT    Skip to the next character, this does the proper decoding
                   2663:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
                   2664:  *           It returns the pointer to the current xmlChar.
                   2665:  */
                   2666: 
                   2667: #define CUR (*ctxt->cur)
                   2668: #define SKIP(val) ctxt->cur += (val)
                   2669: #define NXT(val) ctxt->cur[(val)]
                   2670: #define CUR_PTR ctxt->cur
                   2671: #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
                   2672: 
                   2673: #define COPY_BUF(l,b,i,v)                                              \
                   2674:     if (l == 1) b[i++] = (xmlChar) v;                                  \
                   2675:     else i += xmlCopyChar(l,&b[i],v)
                   2676: 
                   2677: #define NEXTL(l)  ctxt->cur += l
                   2678: 
                   2679: #define SKIP_BLANKS                                                    \
                   2680:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
                   2681: 
                   2682: #define CURRENT (*ctxt->cur)
                   2683: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
                   2684: 
                   2685: 
                   2686: #ifndef DBL_DIG
                   2687: #define DBL_DIG 16
                   2688: #endif
                   2689: #ifndef DBL_EPSILON
                   2690: #define DBL_EPSILON 1E-9
                   2691: #endif
                   2692: 
                   2693: #define UPPER_DOUBLE 1E9
                   2694: #define LOWER_DOUBLE 1E-5
                   2695: #define        LOWER_DOUBLE_EXP 5
                   2696: 
                   2697: #define INTEGER_DIGITS DBL_DIG
                   2698: #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
                   2699: #define EXPONENT_DIGITS (3 + 2)
                   2700: 
                   2701: /**
                   2702:  * xmlXPathFormatNumber:
                   2703:  * @number:     number to format
                   2704:  * @buffer:     output buffer
                   2705:  * @buffersize: size of output buffer
                   2706:  *
                   2707:  * Convert the number into a string representation.
                   2708:  */
                   2709: static void
                   2710: xmlXPathFormatNumber(double number, char buffer[], int buffersize)
                   2711: {
                   2712:     switch (xmlXPathIsInf(number)) {
                   2713:     case 1:
                   2714:        if (buffersize > (int)sizeof("Infinity"))
                   2715:            snprintf(buffer, buffersize, "Infinity");
                   2716:        break;
                   2717:     case -1:
                   2718:        if (buffersize > (int)sizeof("-Infinity"))
                   2719:            snprintf(buffer, buffersize, "-Infinity");
                   2720:        break;
                   2721:     default:
                   2722:        if (xmlXPathIsNaN(number)) {
                   2723:            if (buffersize > (int)sizeof("NaN"))
                   2724:                snprintf(buffer, buffersize, "NaN");
                   2725:        } else if (number == 0 && xmlXPathGetSign(number) != 0) {
                   2726:            snprintf(buffer, buffersize, "0");
                   2727:        } else if (number == ((int) number)) {
                   2728:            char work[30];
                   2729:            char *ptr, *cur;
                   2730:            int value = (int) number;
                   2731: 
                   2732:             ptr = &buffer[0];
                   2733:            if (value == 0) {
                   2734:                *ptr++ = '0';
                   2735:            } else {
                   2736:                snprintf(work, 29, "%d", value);
                   2737:                cur = &work[0];
                   2738:                while ((*cur) && (ptr - buffer < buffersize)) {
                   2739:                    *ptr++ = *cur++;
                   2740:                }
                   2741:            }
                   2742:            if (ptr - buffer < buffersize) {
                   2743:                *ptr = 0;
                   2744:            } else if (buffersize > 0) {
                   2745:                ptr--;
                   2746:                *ptr = 0;
                   2747:            }
                   2748:        } else {
                   2749:            /*
                   2750:              For the dimension of work,
                   2751:                  DBL_DIG is number of significant digits
                   2752:                  EXPONENT is only needed for "scientific notation"
                   2753:                  3 is sign, decimal point, and terminating zero
                   2754:                  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
                   2755:              Note that this dimension is slightly (a few characters)
                   2756:              larger than actually necessary.
                   2757:            */
                   2758:            char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
                   2759:            int integer_place, fraction_place;
                   2760:            char *ptr;
                   2761:            char *after_fraction;
                   2762:            double absolute_value;
                   2763:            int size;
                   2764: 
                   2765:            absolute_value = fabs(number);
                   2766: 
                   2767:            /*
                   2768:             * First choose format - scientific or regular floating point.
                   2769:             * In either case, result is in work, and after_fraction points
                   2770:             * just past the fractional part.
                   2771:            */
                   2772:            if ( ((absolute_value > UPPER_DOUBLE) ||
                   2773:                  (absolute_value < LOWER_DOUBLE)) &&
                   2774:                 (absolute_value != 0.0) ) {
                   2775:                /* Use scientific notation */
                   2776:                integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
                   2777:                fraction_place = DBL_DIG - 1;
                   2778:                size = snprintf(work, sizeof(work),"%*.*e",
                   2779:                         integer_place, fraction_place, number);
                   2780:                while ((size > 0) && (work[size] != 'e')) size--;
                   2781: 
                   2782:            }
                   2783:            else {
                   2784:                /* Use regular notation */
                   2785:                if (absolute_value > 0.0) {
                   2786:                    integer_place = (int)log10(absolute_value);
                   2787:                    if (integer_place > 0)
                   2788:                        fraction_place = DBL_DIG - integer_place - 1;
                   2789:                    else
                   2790:                        fraction_place = DBL_DIG - integer_place;
                   2791:                } else {
                   2792:                    fraction_place = 1;
                   2793:                }
                   2794:                size = snprintf(work, sizeof(work), "%0.*f",
                   2795:                                fraction_place, number);
                   2796:            }
                   2797: 
                   2798:            /* Remove fractional trailing zeroes */
                   2799:            after_fraction = work + size;
                   2800:            ptr = after_fraction;
                   2801:            while (*(--ptr) == '0')
                   2802:                ;
                   2803:            if (*ptr != '.')
                   2804:                ptr++;
                   2805:            while ((*ptr++ = *after_fraction++) != 0);
                   2806: 
                   2807:            /* Finally copy result back to caller */
                   2808:            size = strlen(work) + 1;
                   2809:            if (size > buffersize) {
                   2810:                work[buffersize - 1] = 0;
                   2811:                size = buffersize;
                   2812:            }
                   2813:            memmove(buffer, work, size);
                   2814:        }
                   2815:        break;
                   2816:     }
                   2817: }
                   2818: 
                   2819: 
                   2820: /************************************************************************
                   2821:  *                                                                     *
                   2822:  *                     Routines to handle NodeSets                     *
                   2823:  *                                                                     *
                   2824:  ************************************************************************/
                   2825: 
                   2826: /**
                   2827:  * xmlXPathOrderDocElems:
                   2828:  * @doc:  an input document
                   2829:  *
                   2830:  * Call this routine to speed up XPath computation on static documents.
                   2831:  * This stamps all the element nodes with the document order
                   2832:  * Like for line information, the order is kept in the element->content
                   2833:  * field, the value stored is actually - the node number (starting at -1)
                   2834:  * to be able to differentiate from line numbers.
                   2835:  *
                   2836:  * Returns the number of elements found in the document or -1 in case
                   2837:  *    of error.
                   2838:  */
                   2839: long
                   2840: xmlXPathOrderDocElems(xmlDocPtr doc) {
                   2841:     long count = 0;
                   2842:     xmlNodePtr cur;
                   2843: 
                   2844:     if (doc == NULL)
                   2845:        return(-1);
                   2846:     cur = doc->children;
                   2847:     while (cur != NULL) {
                   2848:        if (cur->type == XML_ELEMENT_NODE) {
                   2849:            cur->content = (void *) (-(++count));
                   2850:            if (cur->children != NULL) {
                   2851:                cur = cur->children;
                   2852:                continue;
                   2853:            }
                   2854:        }
                   2855:        if (cur->next != NULL) {
                   2856:            cur = cur->next;
                   2857:            continue;
                   2858:        }
                   2859:        do {
                   2860:            cur = cur->parent;
                   2861:            if (cur == NULL)
                   2862:                break;
                   2863:            if (cur == (xmlNodePtr) doc) {
                   2864:                cur = NULL;
                   2865:                break;
                   2866:            }
                   2867:            if (cur->next != NULL) {
                   2868:                cur = cur->next;
                   2869:                break;
                   2870:            }
                   2871:        } while (cur != NULL);
                   2872:     }
                   2873:     return(count);
                   2874: }
                   2875: 
                   2876: /**
                   2877:  * xmlXPathCmpNodes:
                   2878:  * @node1:  the first node
                   2879:  * @node2:  the second node
                   2880:  *
                   2881:  * Compare two nodes w.r.t document order
                   2882:  *
                   2883:  * Returns -2 in case of error 1 if first point < second point, 0 if
                   2884:  *         it's the same node, -1 otherwise
                   2885:  */
                   2886: int
                   2887: xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
                   2888:     int depth1, depth2;
                   2889:     int attr1 = 0, attr2 = 0;
                   2890:     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
                   2891:     xmlNodePtr cur, root;
                   2892: 
                   2893:     if ((node1 == NULL) || (node2 == NULL))
                   2894:        return(-2);
                   2895:     /*
                   2896:      * a couple of optimizations which will avoid computations in most cases
                   2897:      */
                   2898:     if (node1 == node2)                /* trivial case */
                   2899:        return(0);
                   2900:     if (node1->type == XML_ATTRIBUTE_NODE) {
                   2901:        attr1 = 1;
                   2902:        attrNode1 = node1;
                   2903:        node1 = node1->parent;
                   2904:     }
                   2905:     if (node2->type == XML_ATTRIBUTE_NODE) {
                   2906:        attr2 = 1;
                   2907:        attrNode2 = node2;
                   2908:        node2 = node2->parent;
                   2909:     }
                   2910:     if (node1 == node2) {
                   2911:        if (attr1 == attr2) {
                   2912:            /* not required, but we keep attributes in order */
                   2913:            if (attr1 != 0) {
                   2914:                cur = attrNode2->prev;
                   2915:                while (cur != NULL) {
                   2916:                    if (cur == attrNode1)
                   2917:                        return (1);
                   2918:                    cur = cur->prev;
                   2919:                }
                   2920:                return (-1);
                   2921:            }
                   2922:            return(0);
                   2923:        }
                   2924:        if (attr2 == 1)
                   2925:            return(1);
                   2926:        return(-1);
                   2927:     }
                   2928:     if ((node1->type == XML_NAMESPACE_DECL) ||
                   2929:         (node2->type == XML_NAMESPACE_DECL))
                   2930:        return(1);
                   2931:     if (node1 == node2->prev)
                   2932:        return(1);
                   2933:     if (node1 == node2->next)
                   2934:        return(-1);
                   2935: 
                   2936:     /*
                   2937:      * Speedup using document order if availble.
                   2938:      */
                   2939:     if ((node1->type == XML_ELEMENT_NODE) &&
                   2940:        (node2->type == XML_ELEMENT_NODE) &&
                   2941:        (0 > (long) node1->content) &&
                   2942:        (0 > (long) node2->content) &&
                   2943:        (node1->doc == node2->doc)) {
                   2944:        long l1, l2;
                   2945: 
                   2946:        l1 = -((long) node1->content);
                   2947:        l2 = -((long) node2->content);
                   2948:        if (l1 < l2)
                   2949:            return(1);
                   2950:        if (l1 > l2)
                   2951:            return(-1);
                   2952:     }
                   2953: 
                   2954:     /*
                   2955:      * compute depth to root
                   2956:      */
                   2957:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
                   2958:        if (cur == node1)
                   2959:            return(1);
                   2960:        depth2++;
                   2961:     }
                   2962:     root = cur;
                   2963:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
                   2964:        if (cur == node2)
                   2965:            return(-1);
                   2966:        depth1++;
                   2967:     }
                   2968:     /*
                   2969:      * Distinct document (or distinct entities :-( ) case.
                   2970:      */
                   2971:     if (root != cur) {
                   2972:        return(-2);
                   2973:     }
                   2974:     /*
                   2975:      * get the nearest common ancestor.
                   2976:      */
                   2977:     while (depth1 > depth2) {
                   2978:        depth1--;
                   2979:        node1 = node1->parent;
                   2980:     }
                   2981:     while (depth2 > depth1) {
                   2982:        depth2--;
                   2983:        node2 = node2->parent;
                   2984:     }
                   2985:     while (node1->parent != node2->parent) {
                   2986:        node1 = node1->parent;
                   2987:        node2 = node2->parent;
                   2988:        /* should not happen but just in case ... */
                   2989:        if ((node1 == NULL) || (node2 == NULL))
                   2990:            return(-2);
                   2991:     }
                   2992:     /*
                   2993:      * Find who's first.
                   2994:      */
                   2995:     if (node1 == node2->prev)
                   2996:        return(1);
                   2997:     if (node1 == node2->next)
                   2998:        return(-1);
                   2999:     /*
                   3000:      * Speedup using document order if availble.
                   3001:      */
                   3002:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3003:        (node2->type == XML_ELEMENT_NODE) &&
                   3004:        (0 > (long) node1->content) &&
                   3005:        (0 > (long) node2->content) &&
                   3006:        (node1->doc == node2->doc)) {
                   3007:        long l1, l2;
                   3008: 
                   3009:        l1 = -((long) node1->content);
                   3010:        l2 = -((long) node2->content);
                   3011:        if (l1 < l2)
                   3012:            return(1);
                   3013:        if (l1 > l2)
                   3014:            return(-1);
                   3015:     }
                   3016: 
                   3017:     for (cur = node1->next;cur != NULL;cur = cur->next)
                   3018:        if (cur == node2)
                   3019:            return(1);
                   3020:     return(-1); /* assume there is no sibling list corruption */
                   3021: }
                   3022: 
                   3023: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   3024: /**
                   3025:  * xmlXPathCmpNodesExt:
                   3026:  * @node1:  the first node
                   3027:  * @node2:  the second node
                   3028:  *
                   3029:  * Compare two nodes w.r.t document order.
                   3030:  * This one is optimized for handling of non-element nodes.
                   3031:  *
                   3032:  * Returns -2 in case of error 1 if first point < second point, 0 if
                   3033:  *         it's the same node, -1 otherwise
                   3034:  */
                   3035: static int
                   3036: xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
                   3037:     int depth1, depth2;
                   3038:     int misc = 0, precedence1 = 0, precedence2 = 0;
                   3039:     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
                   3040:     xmlNodePtr cur, root;
                   3041:     long l1, l2;
                   3042: 
                   3043:     if ((node1 == NULL) || (node2 == NULL))
                   3044:        return(-2);
                   3045: 
                   3046:     if (node1 == node2)
                   3047:        return(0);
                   3048: 
                   3049:     /*
                   3050:      * a couple of optimizations which will avoid computations in most cases
                   3051:      */
                   3052:     switch (node1->type) {
                   3053:        case XML_ELEMENT_NODE:
                   3054:            if (node2->type == XML_ELEMENT_NODE) {
                   3055:                if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
                   3056:                    (0 > (long) node2->content) &&
                   3057:                    (node1->doc == node2->doc))
                   3058:                {
                   3059:                    l1 = -((long) node1->content);
                   3060:                    l2 = -((long) node2->content);
                   3061:                    if (l1 < l2)
                   3062:                        return(1);
                   3063:                    if (l1 > l2)
                   3064:                        return(-1);
                   3065:                } else
                   3066:                    goto turtle_comparison;
                   3067:            }
                   3068:            break;
                   3069:        case XML_ATTRIBUTE_NODE:
                   3070:            precedence1 = 1; /* element is owner */
                   3071:            miscNode1 = node1;
                   3072:            node1 = node1->parent;
                   3073:            misc = 1;
                   3074:            break;
                   3075:        case XML_TEXT_NODE:
                   3076:        case XML_CDATA_SECTION_NODE:
                   3077:        case XML_COMMENT_NODE:
                   3078:        case XML_PI_NODE: {
                   3079:            miscNode1 = node1;
                   3080:            /*
                   3081:            * Find nearest element node.
                   3082:            */
                   3083:            if (node1->prev != NULL) {
                   3084:                do {
                   3085:                    node1 = node1->prev;
                   3086:                    if (node1->type == XML_ELEMENT_NODE) {
                   3087:                        precedence1 = 3; /* element in prev-sibl axis */
                   3088:                        break;
                   3089:                    }
                   3090:                    if (node1->prev == NULL) {
                   3091:                        precedence1 = 2; /* element is parent */
                   3092:                        /*
                   3093:                        * URGENT TODO: Are there any cases, where the
                   3094:                        * parent of such a node is not an element node?
                   3095:                        */
                   3096:                        node1 = node1->parent;
                   3097:                        break;
                   3098:                    }
                   3099:                } while (1);
                   3100:            } else {
                   3101:                precedence1 = 2; /* element is parent */
                   3102:                node1 = node1->parent;
                   3103:            }
                   3104:            if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
                   3105:                (0 <= (long) node1->content)) {
                   3106:                /*
                   3107:                * Fallback for whatever case.
                   3108:                */
                   3109:                node1 = miscNode1;
                   3110:                precedence1 = 0;
                   3111:            } else
                   3112:                misc = 1;
                   3113:        }
                   3114:            break;
                   3115:        case XML_NAMESPACE_DECL:
                   3116:            /*
                   3117:            * TODO: why do we return 1 for namespace nodes?
                   3118:            */
                   3119:            return(1);
                   3120:        default:
                   3121:            break;
                   3122:     }
                   3123:     switch (node2->type) {
                   3124:        case XML_ELEMENT_NODE:
                   3125:            break;
                   3126:        case XML_ATTRIBUTE_NODE:
                   3127:            precedence2 = 1; /* element is owner */
                   3128:            miscNode2 = node2;
                   3129:            node2 = node2->parent;
                   3130:            misc = 1;
                   3131:            break;
                   3132:        case XML_TEXT_NODE:
                   3133:        case XML_CDATA_SECTION_NODE:
                   3134:        case XML_COMMENT_NODE:
                   3135:        case XML_PI_NODE: {
                   3136:            miscNode2 = node2;
                   3137:            if (node2->prev != NULL) {
                   3138:                do {
                   3139:                    node2 = node2->prev;
                   3140:                    if (node2->type == XML_ELEMENT_NODE) {
                   3141:                        precedence2 = 3; /* element in prev-sibl axis */
                   3142:                        break;
                   3143:                    }
                   3144:                    if (node2->prev == NULL) {
                   3145:                        precedence2 = 2; /* element is parent */
                   3146:                        node2 = node2->parent;
                   3147:                        break;
                   3148:                    }
                   3149:                } while (1);
                   3150:            } else {
                   3151:                precedence2 = 2; /* element is parent */
                   3152:                node2 = node2->parent;
                   3153:            }
                   3154:            if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
                   3155:                (0 <= (long) node1->content))
                   3156:            {
                   3157:                node2 = miscNode2;
                   3158:                precedence2 = 0;
                   3159:            } else
                   3160:                misc = 1;
                   3161:        }
                   3162:            break;
                   3163:        case XML_NAMESPACE_DECL:
                   3164:            return(1);
                   3165:        default:
                   3166:            break;
                   3167:     }
                   3168:     if (misc) {
                   3169:        if (node1 == node2) {
                   3170:            if (precedence1 == precedence2) {
                   3171:                /*
                   3172:                * The ugly case; but normally there aren't many
                   3173:                * adjacent non-element nodes around.
                   3174:                */
                   3175:                cur = miscNode2->prev;
                   3176:                while (cur != NULL) {
                   3177:                    if (cur == miscNode1)
                   3178:                        return(1);
                   3179:                    if (cur->type == XML_ELEMENT_NODE)
                   3180:                        return(-1);
                   3181:                    cur = cur->prev;
                   3182:                }
                   3183:                return (-1);
                   3184:            } else {
                   3185:                /*
                   3186:                * Evaluate based on higher precedence wrt to the element.
                   3187:                * TODO: This assumes attributes are sorted before content.
                   3188:                *   Is this 100% correct?
                   3189:                */
                   3190:                if (precedence1 < precedence2)
                   3191:                    return(1);
                   3192:                else
                   3193:                    return(-1);
                   3194:            }
                   3195:        }
                   3196:        /*
                   3197:        * Special case: One of the helper-elements is contained by the other.
                   3198:        * <foo>
                   3199:        *   <node2>
                   3200:        *     <node1>Text-1(precedence1 == 2)</node1>
                   3201:        *   </node2>
                   3202:        *   Text-6(precedence2 == 3)
                   3203:        * </foo>
                   3204:        */
                   3205:        if ((precedence2 == 3) && (precedence1 > 1)) {
                   3206:            cur = node1->parent;
                   3207:            while (cur) {
                   3208:                if (cur == node2)
                   3209:                    return(1);
                   3210:                cur = cur->parent;
                   3211:            }
                   3212:        }
                   3213:        if ((precedence1 == 3) && (precedence2 > 1)) {
                   3214:            cur = node2->parent;
                   3215:            while (cur) {
                   3216:                if (cur == node1)
                   3217:                    return(-1);
                   3218:                cur = cur->parent;
                   3219:            }
                   3220:        }
                   3221:     }
                   3222: 
                   3223:     /*
                   3224:      * Speedup using document order if availble.
                   3225:      */
                   3226:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3227:        (node2->type == XML_ELEMENT_NODE) &&
                   3228:        (0 > (long) node1->content) &&
                   3229:        (0 > (long) node2->content) &&
                   3230:        (node1->doc == node2->doc)) {
                   3231: 
                   3232:        l1 = -((long) node1->content);
                   3233:        l2 = -((long) node2->content);
                   3234:        if (l1 < l2)
                   3235:            return(1);
                   3236:        if (l1 > l2)
                   3237:            return(-1);
                   3238:     }
                   3239: 
                   3240: turtle_comparison:
                   3241: 
                   3242:     if (node1 == node2->prev)
                   3243:        return(1);
                   3244:     if (node1 == node2->next)
                   3245:        return(-1);
                   3246:     /*
                   3247:      * compute depth to root
                   3248:      */
                   3249:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
                   3250:        if (cur == node1)
                   3251:            return(1);
                   3252:        depth2++;
                   3253:     }
                   3254:     root = cur;
                   3255:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
                   3256:        if (cur == node2)
                   3257:            return(-1);
                   3258:        depth1++;
                   3259:     }
                   3260:     /*
                   3261:      * Distinct document (or distinct entities :-( ) case.
                   3262:      */
                   3263:     if (root != cur) {
                   3264:        return(-2);
                   3265:     }
                   3266:     /*
                   3267:      * get the nearest common ancestor.
                   3268:      */
                   3269:     while (depth1 > depth2) {
                   3270:        depth1--;
                   3271:        node1 = node1->parent;
                   3272:     }
                   3273:     while (depth2 > depth1) {
                   3274:        depth2--;
                   3275:        node2 = node2->parent;
                   3276:     }
                   3277:     while (node1->parent != node2->parent) {
                   3278:        node1 = node1->parent;
                   3279:        node2 = node2->parent;
                   3280:        /* should not happen but just in case ... */
                   3281:        if ((node1 == NULL) || (node2 == NULL))
                   3282:            return(-2);
                   3283:     }
                   3284:     /*
                   3285:      * Find who's first.
                   3286:      */
                   3287:     if (node1 == node2->prev)
                   3288:        return(1);
                   3289:     if (node1 == node2->next)
                   3290:        return(-1);
                   3291:     /*
                   3292:      * Speedup using document order if availble.
                   3293:      */
                   3294:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3295:        (node2->type == XML_ELEMENT_NODE) &&
                   3296:        (0 > (long) node1->content) &&
                   3297:        (0 > (long) node2->content) &&
                   3298:        (node1->doc == node2->doc)) {
                   3299: 
                   3300:        l1 = -((long) node1->content);
                   3301:        l2 = -((long) node2->content);
                   3302:        if (l1 < l2)
                   3303:            return(1);
                   3304:        if (l1 > l2)
                   3305:            return(-1);
                   3306:     }
                   3307: 
                   3308:     for (cur = node1->next;cur != NULL;cur = cur->next)
                   3309:        if (cur == node2)
                   3310:            return(1);
                   3311:     return(-1); /* assume there is no sibling list corruption */
                   3312: }
                   3313: #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
                   3314: 
                   3315: /**
                   3316:  * xmlXPathNodeSetSort:
                   3317:  * @set:  the node set
                   3318:  *
                   3319:  * Sort the node set in document order
                   3320:  */
                   3321: void
                   3322: xmlXPathNodeSetSort(xmlNodeSetPtr set) {
                   3323:     int i, j, incr, len;
                   3324:     xmlNodePtr tmp;
                   3325: 
                   3326:     if (set == NULL)
                   3327:        return;
                   3328: 
                   3329:     /* Use Shell's sort to sort the node-set */
                   3330:     len = set->nodeNr;
                   3331:     for (incr = len / 2; incr > 0; incr /= 2) {
                   3332:        for (i = incr; i < len; i++) {
                   3333:            j = i - incr;
                   3334:            while (j >= 0) {
                   3335: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   3336:                if (xmlXPathCmpNodesExt(set->nodeTab[j],
                   3337:                        set->nodeTab[j + incr]) == -1)
                   3338: #else
                   3339:                if (xmlXPathCmpNodes(set->nodeTab[j],
                   3340:                        set->nodeTab[j + incr]) == -1)
                   3341: #endif
                   3342:                {
                   3343:                    tmp = set->nodeTab[j];
                   3344:                    set->nodeTab[j] = set->nodeTab[j + incr];
                   3345:                    set->nodeTab[j + incr] = tmp;
                   3346:                    j -= incr;
                   3347:                } else
                   3348:                    break;
                   3349:            }
                   3350:        }
                   3351:     }
                   3352: }
                   3353: 
                   3354: #define XML_NODESET_DEFAULT    10
                   3355: /**
                   3356:  * xmlXPathNodeSetDupNs:
                   3357:  * @node:  the parent node of the namespace XPath node
                   3358:  * @ns:  the libxml namespace declaration node.
                   3359:  *
                   3360:  * Namespace node in libxml don't match the XPath semantic. In a node set
                   3361:  * the namespace nodes are duplicated and the next pointer is set to the
                   3362:  * parent node in the XPath semantic.
                   3363:  *
                   3364:  * Returns the newly created object.
                   3365:  */
                   3366: static xmlNodePtr
                   3367: xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
                   3368:     xmlNsPtr cur;
                   3369: 
                   3370:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
                   3371:        return(NULL);
                   3372:     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
                   3373:        return((xmlNodePtr) ns);
                   3374: 
                   3375:     /*
                   3376:      * Allocate a new Namespace and fill the fields.
                   3377:      */
                   3378:     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
                   3379:     if (cur == NULL) {
                   3380:         xmlXPathErrMemory(NULL, "duplicating namespace\n");
                   3381:        return(NULL);
                   3382:     }
                   3383:     memset(cur, 0, sizeof(xmlNs));
                   3384:     cur->type = XML_NAMESPACE_DECL;
                   3385:     if (ns->href != NULL)
                   3386:        cur->href = xmlStrdup(ns->href);
                   3387:     if (ns->prefix != NULL)
                   3388:        cur->prefix = xmlStrdup(ns->prefix);
                   3389:     cur->next = (xmlNsPtr) node;
                   3390:     return((xmlNodePtr) cur);
                   3391: }
                   3392: 
                   3393: /**
                   3394:  * xmlXPathNodeSetFreeNs:
                   3395:  * @ns:  the XPath namespace node found in a nodeset.
                   3396:  *
                   3397:  * Namespace nodes in libxml don't match the XPath semantic. In a node set
                   3398:  * the namespace nodes are duplicated and the next pointer is set to the
                   3399:  * parent node in the XPath semantic. Check if such a node needs to be freed
                   3400:  */
                   3401: void
                   3402: xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
                   3403:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
                   3404:        return;
                   3405: 
                   3406:     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
                   3407:        if (ns->href != NULL)
                   3408:            xmlFree((xmlChar *)ns->href);
                   3409:        if (ns->prefix != NULL)
                   3410:            xmlFree((xmlChar *)ns->prefix);
                   3411:        xmlFree(ns);
                   3412:     }
                   3413: }
                   3414: 
                   3415: /**
                   3416:  * xmlXPathNodeSetCreate:
                   3417:  * @val:  an initial xmlNodePtr, or NULL
                   3418:  *
                   3419:  * Create a new xmlNodeSetPtr of type double and of value @val
                   3420:  *
                   3421:  * Returns the newly created object.
                   3422:  */
                   3423: xmlNodeSetPtr
                   3424: xmlXPathNodeSetCreate(xmlNodePtr val) {
                   3425:     xmlNodeSetPtr ret;
                   3426: 
                   3427:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
                   3428:     if (ret == NULL) {
                   3429:         xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3430:        return(NULL);
                   3431:     }
                   3432:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
                   3433:     if (val != NULL) {
                   3434:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3435:                                             sizeof(xmlNodePtr));
                   3436:        if (ret->nodeTab == NULL) {
                   3437:            xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3438:            xmlFree(ret);
                   3439:            return(NULL);
                   3440:        }
                   3441:        memset(ret->nodeTab, 0 ,
                   3442:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3443:         ret->nodeMax = XML_NODESET_DEFAULT;
                   3444:        if (val->type == XML_NAMESPACE_DECL) {
                   3445:            xmlNsPtr ns = (xmlNsPtr) val;
                   3446: 
                   3447:            ret->nodeTab[ret->nodeNr++] =
                   3448:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3449:        } else
                   3450:            ret->nodeTab[ret->nodeNr++] = val;
                   3451:     }
                   3452:     return(ret);
                   3453: }
                   3454: 
                   3455: /**
                   3456:  * xmlXPathNodeSetCreateSize:
                   3457:  * @size:  the initial size of the set
                   3458:  *
                   3459:  * Create a new xmlNodeSetPtr of type double and of value @val
                   3460:  *
                   3461:  * Returns the newly created object.
                   3462:  */
                   3463: static xmlNodeSetPtr
                   3464: xmlXPathNodeSetCreateSize(int size) {
                   3465:     xmlNodeSetPtr ret;
                   3466: 
                   3467:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
                   3468:     if (ret == NULL) {
                   3469:         xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3470:        return(NULL);
                   3471:     }
                   3472:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
                   3473:     if (size < XML_NODESET_DEFAULT)
                   3474:        size = XML_NODESET_DEFAULT;
                   3475:     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
                   3476:     if (ret->nodeTab == NULL) {
                   3477:        xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3478:        xmlFree(ret);
                   3479:        return(NULL);
                   3480:     }
                   3481:     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
                   3482:     ret->nodeMax = size;
                   3483:     return(ret);
                   3484: }
                   3485: 
                   3486: /**
                   3487:  * xmlXPathNodeSetContains:
                   3488:  * @cur:  the node-set
                   3489:  * @val:  the node
                   3490:  *
                   3491:  * checks whether @cur contains @val
                   3492:  *
                   3493:  * Returns true (1) if @cur contains @val, false (0) otherwise
                   3494:  */
                   3495: int
                   3496: xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
                   3497:     int i;
                   3498: 
                   3499:     if ((cur == NULL) || (val == NULL)) return(0);
                   3500:     if (val->type == XML_NAMESPACE_DECL) {
                   3501:        for (i = 0; i < cur->nodeNr; i++) {
                   3502:            if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
                   3503:                xmlNsPtr ns1, ns2;
                   3504: 
                   3505:                ns1 = (xmlNsPtr) val;
                   3506:                ns2 = (xmlNsPtr) cur->nodeTab[i];
                   3507:                if (ns1 == ns2)
                   3508:                    return(1);
                   3509:                if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
                   3510:                    (xmlStrEqual(ns1->prefix, ns2->prefix)))
                   3511:                    return(1);
                   3512:            }
                   3513:        }
                   3514:     } else {
                   3515:        for (i = 0; i < cur->nodeNr; i++) {
                   3516:            if (cur->nodeTab[i] == val)
                   3517:                return(1);
                   3518:        }
                   3519:     }
                   3520:     return(0);
                   3521: }
                   3522: 
                   3523: /**
                   3524:  * xmlXPathNodeSetAddNs:
                   3525:  * @cur:  the initial node set
                   3526:  * @node:  the hosting node
                   3527:  * @ns:  a the namespace node
                   3528:  *
                   3529:  * add a new namespace node to an existing NodeSet
                   3530:  */
                   3531: void
                   3532: xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
                   3533:     int i;
                   3534: 
                   3535: 
                   3536:     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
                   3537:         (ns->type != XML_NAMESPACE_DECL) ||
                   3538:        (node->type != XML_ELEMENT_NODE))
                   3539:        return;
                   3540: 
                   3541:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3542:     /*
                   3543:      * prevent duplicates
                   3544:      */
                   3545:     for (i = 0;i < cur->nodeNr;i++) {
                   3546:         if ((cur->nodeTab[i] != NULL) &&
                   3547:            (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
                   3548:            (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
                   3549:            (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
                   3550:            return;
                   3551:     }
                   3552: 
                   3553:     /*
                   3554:      * grow the nodeTab if needed
                   3555:      */
                   3556:     if (cur->nodeMax == 0) {
                   3557:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3558:                                             sizeof(xmlNodePtr));
                   3559:        if (cur->nodeTab == NULL) {
                   3560:            xmlXPathErrMemory(NULL, "growing nodeset\n");
                   3561:            return;
                   3562:        }
                   3563:        memset(cur->nodeTab, 0 ,
                   3564:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3565:         cur->nodeMax = XML_NODESET_DEFAULT;
                   3566:     } else if (cur->nodeNr == cur->nodeMax) {
                   3567:         xmlNodePtr *temp;
                   3568: 
1.1.1.2 ! misho    3569:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1       misho    3570:                                      sizeof(xmlNodePtr));
                   3571:        if (temp == NULL) {
                   3572:            xmlXPathErrMemory(NULL, "growing nodeset\n");
                   3573:            return;
                   3574:        }
1.1.1.2 ! misho    3575:         cur->nodeMax *= 2;
1.1       misho    3576:        cur->nodeTab = temp;
                   3577:     }
                   3578:     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
                   3579: }
                   3580: 
                   3581: /**
                   3582:  * xmlXPathNodeSetAdd:
                   3583:  * @cur:  the initial node set
                   3584:  * @val:  a new xmlNodePtr
                   3585:  *
                   3586:  * add a new xmlNodePtr to an existing NodeSet
                   3587:  */
                   3588: void
                   3589: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
                   3590:     int i;
                   3591: 
                   3592:     if ((cur == NULL) || (val == NULL)) return;
                   3593: 
                   3594: #if 0
                   3595:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
                   3596:        return; /* an XSLT fake node */
                   3597: #endif
                   3598: 
                   3599:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3600:     /*
                   3601:      * prevent duplcates
                   3602:      */
                   3603:     for (i = 0;i < cur->nodeNr;i++)
                   3604:         if (cur->nodeTab[i] == val) return;
                   3605: 
                   3606:     /*
                   3607:      * grow the nodeTab if needed
                   3608:      */
                   3609:     if (cur->nodeMax == 0) {
                   3610:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3611:                                             sizeof(xmlNodePtr));
                   3612:        if (cur->nodeTab == NULL) {
                   3613:            xmlXPathErrMemory(NULL, "growing nodeset\n");
                   3614:            return;
                   3615:        }
                   3616:        memset(cur->nodeTab, 0 ,
                   3617:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3618:         cur->nodeMax = XML_NODESET_DEFAULT;
                   3619:     } else if (cur->nodeNr == cur->nodeMax) {
                   3620:         xmlNodePtr *temp;
                   3621: 
1.1.1.2 ! misho    3622:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1       misho    3623:                                      sizeof(xmlNodePtr));
                   3624:        if (temp == NULL) {
                   3625:            xmlXPathErrMemory(NULL, "growing nodeset\n");
                   3626:            return;
                   3627:        }
1.1.1.2 ! misho    3628:         cur->nodeMax *= 2;
1.1       misho    3629:        cur->nodeTab = temp;
                   3630:     }
                   3631:     if (val->type == XML_NAMESPACE_DECL) {
                   3632:        xmlNsPtr ns = (xmlNsPtr) val;
                   3633: 
                   3634:        cur->nodeTab[cur->nodeNr++] =
                   3635:            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3636:     } else
                   3637:        cur->nodeTab[cur->nodeNr++] = val;
                   3638: }
                   3639: 
                   3640: /**
                   3641:  * xmlXPathNodeSetAddUnique:
                   3642:  * @cur:  the initial node set
                   3643:  * @val:  a new xmlNodePtr
                   3644:  *
                   3645:  * add a new xmlNodePtr to an existing NodeSet, optimized version
                   3646:  * when we are sure the node is not already in the set.
                   3647:  */
                   3648: void
                   3649: xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
                   3650:     if ((cur == NULL) || (val == NULL)) return;
                   3651: 
                   3652: #if 0
                   3653:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
                   3654:        return; /* an XSLT fake node */
                   3655: #endif
                   3656: 
                   3657:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3658:     /*
                   3659:      * grow the nodeTab if needed
                   3660:      */
                   3661:     if (cur->nodeMax == 0) {
                   3662:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3663:                                             sizeof(xmlNodePtr));
                   3664:        if (cur->nodeTab == NULL) {
                   3665:            xmlXPathErrMemory(NULL, "growing nodeset\n");
                   3666:            return;
                   3667:        }
                   3668:        memset(cur->nodeTab, 0 ,
                   3669:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3670:         cur->nodeMax = XML_NODESET_DEFAULT;
                   3671:     } else if (cur->nodeNr == cur->nodeMax) {
                   3672:         xmlNodePtr *temp;
                   3673: 
1.1.1.2 ! misho    3674:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1       misho    3675:                                      sizeof(xmlNodePtr));
                   3676:        if (temp == NULL) {
                   3677:            xmlXPathErrMemory(NULL, "growing nodeset\n");
                   3678:            return;
                   3679:        }
                   3680:        cur->nodeTab = temp;
1.1.1.2 ! misho    3681:         cur->nodeMax *= 2;
1.1       misho    3682:     }
                   3683:     if (val->type == XML_NAMESPACE_DECL) {
                   3684:        xmlNsPtr ns = (xmlNsPtr) val;
                   3685: 
                   3686:        cur->nodeTab[cur->nodeNr++] =
                   3687:            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3688:     } else
                   3689:        cur->nodeTab[cur->nodeNr++] = val;
                   3690: }
                   3691: 
                   3692: /**
                   3693:  * xmlXPathNodeSetMerge:
                   3694:  * @val1:  the first NodeSet or NULL
                   3695:  * @val2:  the second NodeSet
                   3696:  *
                   3697:  * Merges two nodesets, all nodes from @val2 are added to @val1
                   3698:  * if @val1 is NULL, a new set is created and copied from @val2
                   3699:  *
                   3700:  * Returns @val1 once extended or NULL in case of error.
                   3701:  */
                   3702: xmlNodeSetPtr
                   3703: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
                   3704:     int i, j, initNr, skip;
                   3705:     xmlNodePtr n1, n2;
                   3706: 
                   3707:     if (val2 == NULL) return(val1);
                   3708:     if (val1 == NULL) {
                   3709:        val1 = xmlXPathNodeSetCreate(NULL);
                   3710:     if (val1 == NULL)
                   3711:         return (NULL);
                   3712: #if 0
                   3713:        /*
                   3714:        * TODO: The optimization won't work in every case, since
                   3715:        *  those nasty namespace nodes need to be added with
                   3716:        *  xmlXPathNodeSetDupNs() to the set; thus a pure
                   3717:        *  memcpy is not possible.
                   3718:        *  If there was a flag on the nodesetval, indicating that
                   3719:        *  some temporary nodes are in, that would be helpfull.
                   3720:        */
                   3721:        /*
                   3722:        * Optimization: Create an equally sized node-set
                   3723:        * and memcpy the content.
                   3724:        */
                   3725:        val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
                   3726:        if (val1 == NULL)
                   3727:            return(NULL);
                   3728:        if (val2->nodeNr != 0) {
                   3729:            if (val2->nodeNr == 1)
                   3730:                *(val1->nodeTab) = *(val2->nodeTab);
                   3731:            else {
                   3732:                memcpy(val1->nodeTab, val2->nodeTab,
                   3733:                    val2->nodeNr * sizeof(xmlNodePtr));
                   3734:            }
                   3735:            val1->nodeNr = val2->nodeNr;
                   3736:        }
                   3737:        return(val1);
                   3738: #endif
                   3739:     }
                   3740: 
                   3741:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3742:     initNr = val1->nodeNr;
                   3743: 
                   3744:     for (i = 0;i < val2->nodeNr;i++) {
                   3745:        n2 = val2->nodeTab[i];
                   3746:        /*
                   3747:         * check against duplicates
                   3748:         */
                   3749:        skip = 0;
                   3750:        for (j = 0; j < initNr; j++) {
                   3751:            n1 = val1->nodeTab[j];
                   3752:            if (n1 == n2) {
                   3753:                skip = 1;
                   3754:                break;
                   3755:            } else if ((n1->type == XML_NAMESPACE_DECL) &&
                   3756:                       (n2->type == XML_NAMESPACE_DECL)) {
                   3757:                if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
                   3758:                    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
                   3759:                        ((xmlNsPtr) n2)->prefix)))
                   3760:                {
                   3761:                    skip = 1;
                   3762:                    break;
                   3763:                }
                   3764:            }
                   3765:        }
                   3766:        if (skip)
                   3767:            continue;
                   3768: 
                   3769:        /*
                   3770:         * grow the nodeTab if needed
                   3771:         */
                   3772:        if (val1->nodeMax == 0) {
                   3773:            val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3774:                                                    sizeof(xmlNodePtr));
                   3775:            if (val1->nodeTab == NULL) {
                   3776:                xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3777:                return(NULL);
                   3778:            }
                   3779:            memset(val1->nodeTab, 0 ,
                   3780:                   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3781:            val1->nodeMax = XML_NODESET_DEFAULT;
                   3782:        } else if (val1->nodeNr == val1->nodeMax) {
                   3783:            xmlNodePtr *temp;
                   3784: 
1.1.1.2 ! misho    3785:            temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
1.1       misho    3786:                                             sizeof(xmlNodePtr));
                   3787:            if (temp == NULL) {
                   3788:                xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3789:                return(NULL);
                   3790:            }
                   3791:            val1->nodeTab = temp;
1.1.1.2 ! misho    3792:            val1->nodeMax *= 2;
1.1       misho    3793:        }
                   3794:        if (n2->type == XML_NAMESPACE_DECL) {
                   3795:            xmlNsPtr ns = (xmlNsPtr) n2;
                   3796: 
                   3797:            val1->nodeTab[val1->nodeNr++] =
                   3798:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3799:        } else
                   3800:            val1->nodeTab[val1->nodeNr++] = n2;
                   3801:     }
                   3802: 
                   3803:     return(val1);
                   3804: }
                   3805: 
                   3806: #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
                   3807: /**
                   3808:  * xmlXPathNodeSetMergeUnique:
                   3809:  * @val1:  the first NodeSet or NULL
                   3810:  * @val2:  the second NodeSet
                   3811:  *
                   3812:  * Merges two nodesets, all nodes from @val2 are added to @val1
                   3813:  * if @val1 is NULL, a new set is created and copied from @val2
                   3814:  *
                   3815:  * Returns @val1 once extended or NULL in case of error.
                   3816:  */
                   3817: static xmlNodeSetPtr
                   3818: xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
                   3819:     int i;
                   3820: 
                   3821:     if (val2 == NULL) return(val1);
                   3822:     if (val1 == NULL) {
                   3823:        val1 = xmlXPathNodeSetCreate(NULL);
                   3824:     }
                   3825:     if (val1 == NULL)
                   3826:         return (NULL);
                   3827: 
                   3828:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3829: 
                   3830:     for (i = 0;i < val2->nodeNr;i++) {
                   3831:        /*
                   3832:         * grow the nodeTab if needed
                   3833:         */
                   3834:        if (val1->nodeMax == 0) {
                   3835:            val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3836:                                                    sizeof(xmlNodePtr));
                   3837:            if (val1->nodeTab == NULL) {
                   3838:                xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3839:                return(NULL);
                   3840:            }
                   3841:            memset(val1->nodeTab, 0 ,
                   3842:                   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3843:            val1->nodeMax = XML_NODESET_DEFAULT;
                   3844:        } else if (val1->nodeNr == val1->nodeMax) {
                   3845:            xmlNodePtr *temp;
                   3846: 
                   3847:            val1->nodeMax *= 2;
                   3848:            temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
                   3849:                                             sizeof(xmlNodePtr));
                   3850:            if (temp == NULL) {
                   3851:                xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3852:                return(NULL);
                   3853:            }
                   3854:            val1->nodeTab = temp;
                   3855:        }
                   3856:        if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
                   3857:            xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
                   3858: 
                   3859:            val1->nodeTab[val1->nodeNr++] =
                   3860:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3861:        } else
                   3862:            val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
                   3863:     }
                   3864: 
                   3865:     return(val1);
                   3866: }
                   3867: #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
                   3868: 
                   3869: /**
                   3870:  * xmlXPathNodeSetMergeAndClear:
                   3871:  * @set1:  the first NodeSet or NULL
                   3872:  * @set2:  the second NodeSet
                   3873:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
                   3874:  *
                   3875:  * Merges two nodesets, all nodes from @set2 are added to @set1
                   3876:  * if @set1 is NULL, a new set is created and copied from @set2.
                   3877:  * Checks for duplicate nodes. Clears set2.
                   3878:  *
                   3879:  * Returns @set1 once extended or NULL in case of error.
                   3880:  */
                   3881: static xmlNodeSetPtr
                   3882: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
                   3883:                             int hasNullEntries)
                   3884: {
                   3885:     if ((set1 == NULL) && (hasNullEntries == 0)) {
                   3886:        /*
                   3887:        * Note that doing a memcpy of the list, namespace nodes are
                   3888:        * just assigned to set1, since set2 is cleared anyway.
                   3889:        */
                   3890:        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
                   3891:        if (set1 == NULL)
                   3892:            return(NULL);
                   3893:        if (set2->nodeNr != 0) {
                   3894:            memcpy(set1->nodeTab, set2->nodeTab,
                   3895:                set2->nodeNr * sizeof(xmlNodePtr));
                   3896:            set1->nodeNr = set2->nodeNr;
                   3897:        }
                   3898:     } else {
                   3899:        int i, j, initNbSet1;
                   3900:        xmlNodePtr n1, n2;
                   3901: 
                   3902:        if (set1 == NULL)
                   3903:             set1 = xmlXPathNodeSetCreate(NULL);
                   3904:         if (set1 == NULL)
                   3905:             return (NULL);
                   3906: 
                   3907:        initNbSet1 = set1->nodeNr;
                   3908:        for (i = 0;i < set2->nodeNr;i++) {
                   3909:            n2 = set2->nodeTab[i];
                   3910:            /*
                   3911:            * Skip NULLed entries.
                   3912:            */
                   3913:            if (n2 == NULL)
                   3914:                continue;
                   3915:            /*
                   3916:            * Skip duplicates.
                   3917:            */
                   3918:            for (j = 0; j < initNbSet1; j++) {
                   3919:                n1 = set1->nodeTab[j];
                   3920:                if (n1 == n2) {
                   3921:                    goto skip_node;
                   3922:                } else if ((n1->type == XML_NAMESPACE_DECL) &&
                   3923:                    (n2->type == XML_NAMESPACE_DECL))
                   3924:                {
                   3925:                    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
                   3926:                        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
                   3927:                        ((xmlNsPtr) n2)->prefix)))
                   3928:                    {
                   3929:                        /*
                   3930:                        * Free the namespace node.
                   3931:                        */
                   3932:                        set2->nodeTab[i] = NULL;
                   3933:                        xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
                   3934:                        goto skip_node;
                   3935:                    }
                   3936:                }
                   3937:            }
                   3938:            /*
                   3939:            * grow the nodeTab if needed
                   3940:            */
                   3941:            if (set1->nodeMax == 0) {
                   3942:                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
                   3943:                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
                   3944:                if (set1->nodeTab == NULL) {
                   3945:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3946:                    return(NULL);
                   3947:                }
                   3948:                memset(set1->nodeTab, 0,
                   3949:                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3950:                set1->nodeMax = XML_NODESET_DEFAULT;
                   3951:            } else if (set1->nodeNr >= set1->nodeMax) {
                   3952:                xmlNodePtr *temp;
                   3953: 
                   3954:                temp = (xmlNodePtr *) xmlRealloc(
1.1.1.2 ! misho    3955:                    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
1.1       misho    3956:                if (temp == NULL) {
                   3957:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3958:                    return(NULL);
                   3959:                }
                   3960:                set1->nodeTab = temp;
1.1.1.2 ! misho    3961:                set1->nodeMax *= 2;
1.1       misho    3962:            }
                   3963:            if (n2->type == XML_NAMESPACE_DECL) {
                   3964:                xmlNsPtr ns = (xmlNsPtr) n2;
                   3965: 
                   3966:                set1->nodeTab[set1->nodeNr++] =
                   3967:                    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3968:            } else
                   3969:                set1->nodeTab[set1->nodeNr++] = n2;
                   3970: skip_node:
                   3971:            {}
                   3972:        }
                   3973:     }
                   3974:     set2->nodeNr = 0;
                   3975:     return(set1);
                   3976: }
                   3977: 
                   3978: /**
                   3979:  * xmlXPathNodeSetMergeAndClearNoDupls:
                   3980:  * @set1:  the first NodeSet or NULL
                   3981:  * @set2:  the second NodeSet
                   3982:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
                   3983:  *
                   3984:  * Merges two nodesets, all nodes from @set2 are added to @set1
                   3985:  * if @set1 is NULL, a new set is created and copied from @set2.
                   3986:  * Doesn't chack for duplicate nodes. Clears set2.
                   3987:  *
                   3988:  * Returns @set1 once extended or NULL in case of error.
                   3989:  */
                   3990: static xmlNodeSetPtr
                   3991: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
                   3992:                                    int hasNullEntries)
                   3993: {
                   3994:     if (set2 == NULL)
                   3995:        return(set1);
                   3996:     if ((set1 == NULL) && (hasNullEntries == 0)) {
                   3997:        /*
                   3998:        * Note that doing a memcpy of the list, namespace nodes are
                   3999:        * just assigned to set1, since set2 is cleared anyway.
                   4000:        */
                   4001:        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
                   4002:        if (set1 == NULL)
                   4003:            return(NULL);
                   4004:        if (set2->nodeNr != 0) {
                   4005:            memcpy(set1->nodeTab, set2->nodeTab,
                   4006:                set2->nodeNr * sizeof(xmlNodePtr));
                   4007:            set1->nodeNr = set2->nodeNr;
                   4008:        }
                   4009:     } else {
                   4010:        int i;
                   4011:        xmlNodePtr n2;
                   4012: 
                   4013:        if (set1 == NULL)
                   4014:            set1 = xmlXPathNodeSetCreate(NULL);
                   4015:         if (set1 == NULL)
                   4016:             return (NULL);
                   4017: 
                   4018:        for (i = 0;i < set2->nodeNr;i++) {
                   4019:            n2 = set2->nodeTab[i];
                   4020:            /*
                   4021:            * Skip NULLed entries.
                   4022:            */
                   4023:            if (n2 == NULL)
                   4024:                continue;
                   4025:            if (set1->nodeMax == 0) {
                   4026:                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
                   4027:                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
                   4028:                if (set1->nodeTab == NULL) {
                   4029:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   4030:                    return(NULL);
                   4031:                }
                   4032:                memset(set1->nodeTab, 0,
                   4033:                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   4034:                set1->nodeMax = XML_NODESET_DEFAULT;
                   4035:            } else if (set1->nodeNr >= set1->nodeMax) {
                   4036:                xmlNodePtr *temp;
                   4037: 
                   4038:                temp = (xmlNodePtr *) xmlRealloc(
1.1.1.2 ! misho    4039:                    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
1.1       misho    4040:                if (temp == NULL) {
                   4041:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   4042:                    return(NULL);
                   4043:                }
                   4044:                set1->nodeTab = temp;
1.1.1.2 ! misho    4045:                set1->nodeMax *= 2;
1.1       misho    4046:            }
                   4047:            set1->nodeTab[set1->nodeNr++] = n2;
                   4048:        }
                   4049:     }
                   4050:     set2->nodeNr = 0;
                   4051:     return(set1);
                   4052: }
                   4053: 
                   4054: /**
                   4055:  * xmlXPathNodeSetDel:
                   4056:  * @cur:  the initial node set
                   4057:  * @val:  an xmlNodePtr
                   4058:  *
                   4059:  * Removes an xmlNodePtr from an existing NodeSet
                   4060:  */
                   4061: void
                   4062: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
                   4063:     int i;
                   4064: 
                   4065:     if (cur == NULL) return;
                   4066:     if (val == NULL) return;
                   4067: 
                   4068:     /*
                   4069:      * find node in nodeTab
                   4070:      */
                   4071:     for (i = 0;i < cur->nodeNr;i++)
                   4072:         if (cur->nodeTab[i] == val) break;
                   4073: 
                   4074:     if (i >= cur->nodeNr) {    /* not found */
                   4075: #ifdef DEBUG
                   4076:         xmlGenericError(xmlGenericErrorContext,
                   4077:                "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
                   4078:                val->name);
                   4079: #endif
                   4080:         return;
                   4081:     }
                   4082:     if ((cur->nodeTab[i] != NULL) &&
                   4083:        (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
                   4084:        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
                   4085:     cur->nodeNr--;
                   4086:     for (;i < cur->nodeNr;i++)
                   4087:         cur->nodeTab[i] = cur->nodeTab[i + 1];
                   4088:     cur->nodeTab[cur->nodeNr] = NULL;
                   4089: }
                   4090: 
                   4091: /**
                   4092:  * xmlXPathNodeSetRemove:
                   4093:  * @cur:  the initial node set
                   4094:  * @val:  the index to remove
                   4095:  *
                   4096:  * Removes an entry from an existing NodeSet list.
                   4097:  */
                   4098: void
                   4099: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
                   4100:     if (cur == NULL) return;
                   4101:     if (val >= cur->nodeNr) return;
                   4102:     if ((cur->nodeTab[val] != NULL) &&
                   4103:        (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
                   4104:        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
                   4105:     cur->nodeNr--;
                   4106:     for (;val < cur->nodeNr;val++)
                   4107:         cur->nodeTab[val] = cur->nodeTab[val + 1];
                   4108:     cur->nodeTab[cur->nodeNr] = NULL;
                   4109: }
                   4110: 
                   4111: /**
                   4112:  * xmlXPathFreeNodeSet:
                   4113:  * @obj:  the xmlNodeSetPtr to free
                   4114:  *
                   4115:  * Free the NodeSet compound (not the actual nodes !).
                   4116:  */
                   4117: void
                   4118: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
                   4119:     if (obj == NULL) return;
                   4120:     if (obj->nodeTab != NULL) {
                   4121:        int i;
                   4122: 
                   4123:        /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   4124:        for (i = 0;i < obj->nodeNr;i++)
                   4125:            if ((obj->nodeTab[i] != NULL) &&
                   4126:                (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
                   4127:                xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
                   4128:        xmlFree(obj->nodeTab);
                   4129:     }
                   4130:     xmlFree(obj);
                   4131: }
                   4132: 
                   4133: /**
                   4134:  * xmlXPathNodeSetClear:
                   4135:  * @set:  the node set to clear
                   4136:  *
                   4137:  * Clears the list from all temporary XPath objects (e.g. namespace nodes
                   4138:  * are feed), but does *not* free the list itself. Sets the length of the
                   4139:  * list to 0.
                   4140:  */
                   4141: static void
                   4142: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
                   4143: {
                   4144:     if ((set == NULL) || (set->nodeNr <= 0))
                   4145:        return;
                   4146:     else if (hasNsNodes) {
                   4147:        int i;
                   4148:        xmlNodePtr node;
                   4149: 
                   4150:        for (i = 0; i < set->nodeNr; i++) {
                   4151:            node = set->nodeTab[i];
                   4152:            if ((node != NULL) &&
                   4153:                (node->type == XML_NAMESPACE_DECL))
                   4154:                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
                   4155:        }
                   4156:     }
                   4157:     set->nodeNr = 0;
                   4158: }
                   4159: 
                   4160: /**
                   4161:  * xmlXPathNodeSetClearFromPos:
                   4162:  * @set: the node set to be cleared
                   4163:  * @pos: the start position to clear from
                   4164:  *
                   4165:  * Clears the list from temporary XPath objects (e.g. namespace nodes
                   4166:  * are feed) starting with the entry at @pos, but does *not* free the list
                   4167:  * itself. Sets the length of the list to @pos.
                   4168:  */
                   4169: static void
                   4170: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
                   4171: {
                   4172:     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
                   4173:        return;
                   4174:     else if ((hasNsNodes)) {
                   4175:        int i;
                   4176:        xmlNodePtr node;
                   4177: 
                   4178:        for (i = pos; i < set->nodeNr; i++) {
                   4179:            node = set->nodeTab[i];
                   4180:            if ((node != NULL) &&
                   4181:                (node->type == XML_NAMESPACE_DECL))
                   4182:                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
                   4183:        }
                   4184:     }
                   4185:     set->nodeNr = pos;
                   4186: }
                   4187: 
                   4188: /**
                   4189:  * xmlXPathFreeValueTree:
                   4190:  * @obj:  the xmlNodeSetPtr to free
                   4191:  *
                   4192:  * Free the NodeSet compound and the actual tree, this is different
                   4193:  * from xmlXPathFreeNodeSet()
                   4194:  */
                   4195: static void
                   4196: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
                   4197:     int i;
                   4198: 
                   4199:     if (obj == NULL) return;
                   4200: 
                   4201:     if (obj->nodeTab != NULL) {
                   4202:        for (i = 0;i < obj->nodeNr;i++) {
                   4203:            if (obj->nodeTab[i] != NULL) {
                   4204:                if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
                   4205:                    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
                   4206:                } else {
                   4207:                    xmlFreeNodeList(obj->nodeTab[i]);
                   4208:                }
                   4209:            }
                   4210:        }
                   4211:        xmlFree(obj->nodeTab);
                   4212:     }
                   4213:     xmlFree(obj);
                   4214: }
                   4215: 
                   4216: #if defined(DEBUG) || defined(DEBUG_STEP)
                   4217: /**
                   4218:  * xmlGenericErrorContextNodeSet:
                   4219:  * @output:  a FILE * for the output
                   4220:  * @obj:  the xmlNodeSetPtr to display
                   4221:  *
                   4222:  * Quick display of a NodeSet
                   4223:  */
                   4224: void
                   4225: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
                   4226:     int i;
                   4227: 
                   4228:     if (output == NULL) output = xmlGenericErrorContext;
                   4229:     if (obj == NULL)  {
                   4230:         fprintf(output, "NodeSet == NULL !\n");
                   4231:        return;
                   4232:     }
                   4233:     if (obj->nodeNr == 0) {
                   4234:         fprintf(output, "NodeSet is empty\n");
                   4235:        return;
                   4236:     }
                   4237:     if (obj->nodeTab == NULL) {
                   4238:        fprintf(output, " nodeTab == NULL !\n");
                   4239:        return;
                   4240:     }
                   4241:     for (i = 0; i < obj->nodeNr; i++) {
                   4242:         if (obj->nodeTab[i] == NULL) {
                   4243:            fprintf(output, " NULL !\n");
                   4244:            return;
                   4245:         }
                   4246:        if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
                   4247:            (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
                   4248:            fprintf(output, " /");
                   4249:        else if (obj->nodeTab[i]->name == NULL)
                   4250:            fprintf(output, " noname!");
                   4251:        else fprintf(output, " %s", obj->nodeTab[i]->name);
                   4252:     }
                   4253:     fprintf(output, "\n");
                   4254: }
                   4255: #endif
                   4256: 
                   4257: /**
                   4258:  * xmlXPathNewNodeSet:
                   4259:  * @val:  the NodePtr value
                   4260:  *
                   4261:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
                   4262:  * it with the single Node @val
                   4263:  *
                   4264:  * Returns the newly created object.
                   4265:  */
                   4266: xmlXPathObjectPtr
                   4267: xmlXPathNewNodeSet(xmlNodePtr val) {
                   4268:     xmlXPathObjectPtr ret;
                   4269: 
                   4270:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   4271:     if (ret == NULL) {
                   4272:         xmlXPathErrMemory(NULL, "creating nodeset\n");
                   4273:        return(NULL);
                   4274:     }
                   4275:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   4276:     ret->type = XPATH_NODESET;
                   4277:     ret->boolval = 0;
                   4278:     ret->nodesetval = xmlXPathNodeSetCreate(val);
                   4279:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   4280: #ifdef XP_DEBUG_OBJ_USAGE
                   4281:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
                   4282: #endif
                   4283:     return(ret);
                   4284: }
                   4285: 
                   4286: /**
                   4287:  * xmlXPathNewValueTree:
                   4288:  * @val:  the NodePtr value
                   4289:  *
                   4290:  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
                   4291:  * it with the tree root @val
                   4292:  *
                   4293:  * Returns the newly created object.
                   4294:  */
                   4295: xmlXPathObjectPtr
                   4296: xmlXPathNewValueTree(xmlNodePtr val) {
                   4297:     xmlXPathObjectPtr ret;
                   4298: 
                   4299:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   4300:     if (ret == NULL) {
                   4301:         xmlXPathErrMemory(NULL, "creating result value tree\n");
                   4302:        return(NULL);
                   4303:     }
                   4304:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   4305:     ret->type = XPATH_XSLT_TREE;
                   4306:     ret->boolval = 1;
                   4307:     ret->user = (void *) val;
                   4308:     ret->nodesetval = xmlXPathNodeSetCreate(val);
                   4309: #ifdef XP_DEBUG_OBJ_USAGE
                   4310:     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
                   4311: #endif
                   4312:     return(ret);
                   4313: }
                   4314: 
                   4315: /**
                   4316:  * xmlXPathNewNodeSetList:
                   4317:  * @val:  an existing NodeSet
                   4318:  *
                   4319:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
                   4320:  * it with the Nodeset @val
                   4321:  *
                   4322:  * Returns the newly created object.
                   4323:  */
                   4324: xmlXPathObjectPtr
                   4325: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
                   4326: {
                   4327:     xmlXPathObjectPtr ret;
                   4328:     int i;
                   4329: 
                   4330:     if (val == NULL)
                   4331:         ret = NULL;
                   4332:     else if (val->nodeTab == NULL)
                   4333:         ret = xmlXPathNewNodeSet(NULL);
                   4334:     else {
                   4335:         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
                   4336:         if (ret)
                   4337:             for (i = 1; i < val->nodeNr; ++i)
                   4338:                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
                   4339:     }
                   4340: 
                   4341:     return (ret);
                   4342: }
                   4343: 
                   4344: /**
                   4345:  * xmlXPathWrapNodeSet:
                   4346:  * @val:  the NodePtr value
                   4347:  *
                   4348:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
                   4349:  *
                   4350:  * Returns the newly created object.
                   4351:  */
                   4352: xmlXPathObjectPtr
                   4353: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
                   4354:     xmlXPathObjectPtr ret;
                   4355: 
                   4356:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   4357:     if (ret == NULL) {
                   4358:         xmlXPathErrMemory(NULL, "creating node set object\n");
                   4359:        return(NULL);
                   4360:     }
                   4361:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   4362:     ret->type = XPATH_NODESET;
                   4363:     ret->nodesetval = val;
                   4364: #ifdef XP_DEBUG_OBJ_USAGE
                   4365:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
                   4366: #endif
                   4367:     return(ret);
                   4368: }
                   4369: 
                   4370: /**
                   4371:  * xmlXPathFreeNodeSetList:
                   4372:  * @obj:  an existing NodeSetList object
                   4373:  *
                   4374:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
                   4375:  * the list contrary to xmlXPathFreeObject().
                   4376:  */
                   4377: void
                   4378: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
                   4379:     if (obj == NULL) return;
                   4380: #ifdef XP_DEBUG_OBJ_USAGE
                   4381:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
                   4382: #endif
                   4383:     xmlFree(obj);
                   4384: }
                   4385: 
                   4386: /**
                   4387:  * xmlXPathDifference:
                   4388:  * @nodes1:  a node-set
                   4389:  * @nodes2:  a node-set
                   4390:  *
                   4391:  * Implements the EXSLT - Sets difference() function:
                   4392:  *    node-set set:difference (node-set, node-set)
                   4393:  *
                   4394:  * Returns the difference between the two node sets, or nodes1 if
                   4395:  *         nodes2 is empty
                   4396:  */
                   4397: xmlNodeSetPtr
                   4398: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4399:     xmlNodeSetPtr ret;
                   4400:     int i, l1;
                   4401:     xmlNodePtr cur;
                   4402: 
                   4403:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4404:        return(nodes1);
                   4405: 
                   4406:     ret = xmlXPathNodeSetCreate(NULL);
                   4407:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4408:        return(ret);
                   4409: 
                   4410:     l1 = xmlXPathNodeSetGetLength(nodes1);
                   4411: 
                   4412:     for (i = 0; i < l1; i++) {
                   4413:        cur = xmlXPathNodeSetItem(nodes1, i);
                   4414:        if (!xmlXPathNodeSetContains(nodes2, cur))
                   4415:            xmlXPathNodeSetAddUnique(ret, cur);
                   4416:     }
                   4417:     return(ret);
                   4418: }
                   4419: 
                   4420: /**
                   4421:  * xmlXPathIntersection:
                   4422:  * @nodes1:  a node-set
                   4423:  * @nodes2:  a node-set
                   4424:  *
                   4425:  * Implements the EXSLT - Sets intersection() function:
                   4426:  *    node-set set:intersection (node-set, node-set)
                   4427:  *
                   4428:  * Returns a node set comprising the nodes that are within both the
                   4429:  *         node sets passed as arguments
                   4430:  */
                   4431: xmlNodeSetPtr
                   4432: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4433:     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
                   4434:     int i, l1;
                   4435:     xmlNodePtr cur;
                   4436: 
                   4437:     if (ret == NULL)
                   4438:         return(ret);
                   4439:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4440:        return(ret);
                   4441:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4442:        return(ret);
                   4443: 
                   4444:     l1 = xmlXPathNodeSetGetLength(nodes1);
                   4445: 
                   4446:     for (i = 0; i < l1; i++) {
                   4447:        cur = xmlXPathNodeSetItem(nodes1, i);
                   4448:        if (xmlXPathNodeSetContains(nodes2, cur))
                   4449:            xmlXPathNodeSetAddUnique(ret, cur);
                   4450:     }
                   4451:     return(ret);
                   4452: }
                   4453: 
                   4454: /**
                   4455:  * xmlXPathDistinctSorted:
                   4456:  * @nodes:  a node-set, sorted by document order
                   4457:  *
                   4458:  * Implements the EXSLT - Sets distinct() function:
                   4459:  *    node-set set:distinct (node-set)
                   4460:  *
                   4461:  * Returns a subset of the nodes contained in @nodes, or @nodes if
                   4462:  *         it is empty
                   4463:  */
                   4464: xmlNodeSetPtr
                   4465: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
                   4466:     xmlNodeSetPtr ret;
                   4467:     xmlHashTablePtr hash;
                   4468:     int i, l;
                   4469:     xmlChar * strval;
                   4470:     xmlNodePtr cur;
                   4471: 
                   4472:     if (xmlXPathNodeSetIsEmpty(nodes))
                   4473:        return(nodes);
                   4474: 
                   4475:     ret = xmlXPathNodeSetCreate(NULL);
                   4476:     if (ret == NULL)
                   4477:         return(ret);
                   4478:     l = xmlXPathNodeSetGetLength(nodes);
                   4479:     hash = xmlHashCreate (l);
                   4480:     for (i = 0; i < l; i++) {
                   4481:        cur = xmlXPathNodeSetItem(nodes, i);
                   4482:        strval = xmlXPathCastNodeToString(cur);
                   4483:        if (xmlHashLookup(hash, strval) == NULL) {
                   4484:            xmlHashAddEntry(hash, strval, strval);
                   4485:            xmlXPathNodeSetAddUnique(ret, cur);
                   4486:        } else {
                   4487:            xmlFree(strval);
                   4488:        }
                   4489:     }
                   4490:     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
                   4491:     return(ret);
                   4492: }
                   4493: 
                   4494: /**
                   4495:  * xmlXPathDistinct:
                   4496:  * @nodes:  a node-set
                   4497:  *
                   4498:  * Implements the EXSLT - Sets distinct() function:
                   4499:  *    node-set set:distinct (node-set)
                   4500:  * @nodes is sorted by document order, then #exslSetsDistinctSorted
                   4501:  * is called with the sorted node-set
                   4502:  *
                   4503:  * Returns a subset of the nodes contained in @nodes, or @nodes if
                   4504:  *         it is empty
                   4505:  */
                   4506: xmlNodeSetPtr
                   4507: xmlXPathDistinct (xmlNodeSetPtr nodes) {
                   4508:     if (xmlXPathNodeSetIsEmpty(nodes))
                   4509:        return(nodes);
                   4510: 
                   4511:     xmlXPathNodeSetSort(nodes);
                   4512:     return(xmlXPathDistinctSorted(nodes));
                   4513: }
                   4514: 
                   4515: /**
                   4516:  * xmlXPathHasSameNodes:
                   4517:  * @nodes1:  a node-set
                   4518:  * @nodes2:  a node-set
                   4519:  *
                   4520:  * Implements the EXSLT - Sets has-same-nodes function:
                   4521:  *    boolean set:has-same-node(node-set, node-set)
                   4522:  *
                   4523:  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
                   4524:  *         otherwise
                   4525:  */
                   4526: int
                   4527: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4528:     int i, l;
                   4529:     xmlNodePtr cur;
                   4530: 
                   4531:     if (xmlXPathNodeSetIsEmpty(nodes1) ||
                   4532:        xmlXPathNodeSetIsEmpty(nodes2))
                   4533:        return(0);
                   4534: 
                   4535:     l = xmlXPathNodeSetGetLength(nodes1);
                   4536:     for (i = 0; i < l; i++) {
                   4537:        cur = xmlXPathNodeSetItem(nodes1, i);
                   4538:        if (xmlXPathNodeSetContains(nodes2, cur))
                   4539:            return(1);
                   4540:     }
                   4541:     return(0);
                   4542: }
                   4543: 
                   4544: /**
                   4545:  * xmlXPathNodeLeadingSorted:
                   4546:  * @nodes: a node-set, sorted by document order
                   4547:  * @node: a node
                   4548:  *
                   4549:  * Implements the EXSLT - Sets leading() function:
                   4550:  *    node-set set:leading (node-set, node-set)
                   4551:  *
                   4552:  * Returns the nodes in @nodes that precede @node in document order,
                   4553:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4554:  *         doesn't contain @node
                   4555:  */
                   4556: xmlNodeSetPtr
                   4557: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4558:     int i, l;
                   4559:     xmlNodePtr cur;
                   4560:     xmlNodeSetPtr ret;
                   4561: 
                   4562:     if (node == NULL)
                   4563:        return(nodes);
                   4564: 
                   4565:     ret = xmlXPathNodeSetCreate(NULL);
                   4566:     if (ret == NULL)
                   4567:         return(ret);
                   4568:     if (xmlXPathNodeSetIsEmpty(nodes) ||
                   4569:        (!xmlXPathNodeSetContains(nodes, node)))
                   4570:        return(ret);
                   4571: 
                   4572:     l = xmlXPathNodeSetGetLength(nodes);
                   4573:     for (i = 0; i < l; i++) {
                   4574:        cur = xmlXPathNodeSetItem(nodes, i);
                   4575:        if (cur == node)
                   4576:            break;
                   4577:        xmlXPathNodeSetAddUnique(ret, cur);
                   4578:     }
                   4579:     return(ret);
                   4580: }
                   4581: 
                   4582: /**
                   4583:  * xmlXPathNodeLeading:
                   4584:  * @nodes:  a node-set
                   4585:  * @node:  a node
                   4586:  *
                   4587:  * Implements the EXSLT - Sets leading() function:
                   4588:  *    node-set set:leading (node-set, node-set)
                   4589:  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
                   4590:  * is called.
                   4591:  *
                   4592:  * Returns the nodes in @nodes that precede @node in document order,
                   4593:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4594:  *         doesn't contain @node
                   4595:  */
                   4596: xmlNodeSetPtr
                   4597: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4598:     xmlXPathNodeSetSort(nodes);
                   4599:     return(xmlXPathNodeLeadingSorted(nodes, node));
                   4600: }
                   4601: 
                   4602: /**
                   4603:  * xmlXPathLeadingSorted:
                   4604:  * @nodes1:  a node-set, sorted by document order
                   4605:  * @nodes2:  a node-set, sorted by document order
                   4606:  *
                   4607:  * Implements the EXSLT - Sets leading() function:
                   4608:  *    node-set set:leading (node-set, node-set)
                   4609:  *
                   4610:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
                   4611:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4612:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4613:  */
                   4614: xmlNodeSetPtr
                   4615: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4616:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4617:        return(nodes1);
                   4618:     return(xmlXPathNodeLeadingSorted(nodes1,
                   4619:                                     xmlXPathNodeSetItem(nodes2, 1)));
                   4620: }
                   4621: 
                   4622: /**
                   4623:  * xmlXPathLeading:
                   4624:  * @nodes1:  a node-set
                   4625:  * @nodes2:  a node-set
                   4626:  *
                   4627:  * Implements the EXSLT - Sets leading() function:
                   4628:  *    node-set set:leading (node-set, node-set)
                   4629:  * @nodes1 and @nodes2 are sorted by document order, then
                   4630:  * #exslSetsLeadingSorted is called.
                   4631:  *
                   4632:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
                   4633:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4634:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4635:  */
                   4636: xmlNodeSetPtr
                   4637: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4638:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4639:        return(nodes1);
                   4640:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4641:        return(xmlXPathNodeSetCreate(NULL));
                   4642:     xmlXPathNodeSetSort(nodes1);
                   4643:     xmlXPathNodeSetSort(nodes2);
                   4644:     return(xmlXPathNodeLeadingSorted(nodes1,
                   4645:                                     xmlXPathNodeSetItem(nodes2, 1)));
                   4646: }
                   4647: 
                   4648: /**
                   4649:  * xmlXPathNodeTrailingSorted:
                   4650:  * @nodes: a node-set, sorted by document order
                   4651:  * @node: a node
                   4652:  *
                   4653:  * Implements the EXSLT - Sets trailing() function:
                   4654:  *    node-set set:trailing (node-set, node-set)
                   4655:  *
                   4656:  * Returns the nodes in @nodes that follow @node in document order,
                   4657:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4658:  *         doesn't contain @node
                   4659:  */
                   4660: xmlNodeSetPtr
                   4661: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4662:     int i, l;
                   4663:     xmlNodePtr cur;
                   4664:     xmlNodeSetPtr ret;
                   4665: 
                   4666:     if (node == NULL)
                   4667:        return(nodes);
                   4668: 
                   4669:     ret = xmlXPathNodeSetCreate(NULL);
                   4670:     if (ret == NULL)
                   4671:         return(ret);
                   4672:     if (xmlXPathNodeSetIsEmpty(nodes) ||
                   4673:        (!xmlXPathNodeSetContains(nodes, node)))
                   4674:        return(ret);
                   4675: 
                   4676:     l = xmlXPathNodeSetGetLength(nodes);
                   4677:     for (i = l - 1; i >= 0; i--) {
                   4678:        cur = xmlXPathNodeSetItem(nodes, i);
                   4679:        if (cur == node)
                   4680:            break;
                   4681:        xmlXPathNodeSetAddUnique(ret, cur);
                   4682:     }
                   4683:     xmlXPathNodeSetSort(ret);  /* bug 413451 */
                   4684:     return(ret);
                   4685: }
                   4686: 
                   4687: /**
                   4688:  * xmlXPathNodeTrailing:
                   4689:  * @nodes:  a node-set
                   4690:  * @node:  a node
                   4691:  *
                   4692:  * Implements the EXSLT - Sets trailing() function:
                   4693:  *    node-set set:trailing (node-set, node-set)
                   4694:  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
                   4695:  * is called.
                   4696:  *
                   4697:  * Returns the nodes in @nodes that follow @node in document order,
                   4698:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4699:  *         doesn't contain @node
                   4700:  */
                   4701: xmlNodeSetPtr
                   4702: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4703:     xmlXPathNodeSetSort(nodes);
                   4704:     return(xmlXPathNodeTrailingSorted(nodes, node));
                   4705: }
                   4706: 
                   4707: /**
                   4708:  * xmlXPathTrailingSorted:
                   4709:  * @nodes1:  a node-set, sorted by document order
                   4710:  * @nodes2:  a node-set, sorted by document order
                   4711:  *
                   4712:  * Implements the EXSLT - Sets trailing() function:
                   4713:  *    node-set set:trailing (node-set, node-set)
                   4714:  *
                   4715:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
                   4716:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4717:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4718:  */
                   4719: xmlNodeSetPtr
                   4720: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4721:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4722:        return(nodes1);
                   4723:     return(xmlXPathNodeTrailingSorted(nodes1,
                   4724:                                      xmlXPathNodeSetItem(nodes2, 0)));
                   4725: }
                   4726: 
                   4727: /**
                   4728:  * xmlXPathTrailing:
                   4729:  * @nodes1:  a node-set
                   4730:  * @nodes2:  a node-set
                   4731:  *
                   4732:  * Implements the EXSLT - Sets trailing() function:
                   4733:  *    node-set set:trailing (node-set, node-set)
                   4734:  * @nodes1 and @nodes2 are sorted by document order, then
                   4735:  * #xmlXPathTrailingSorted is called.
                   4736:  *
                   4737:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
                   4738:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4739:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4740:  */
                   4741: xmlNodeSetPtr
                   4742: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4743:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4744:        return(nodes1);
                   4745:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4746:        return(xmlXPathNodeSetCreate(NULL));
                   4747:     xmlXPathNodeSetSort(nodes1);
                   4748:     xmlXPathNodeSetSort(nodes2);
                   4749:     return(xmlXPathNodeTrailingSorted(nodes1,
                   4750:                                      xmlXPathNodeSetItem(nodes2, 0)));
                   4751: }
                   4752: 
                   4753: /************************************************************************
                   4754:  *                                                                     *
                   4755:  *             Routines to handle extra functions                      *
                   4756:  *                                                                     *
                   4757:  ************************************************************************/
                   4758: 
                   4759: /**
                   4760:  * xmlXPathRegisterFunc:
                   4761:  * @ctxt:  the XPath context
                   4762:  * @name:  the function name
                   4763:  * @f:  the function implementation or NULL
                   4764:  *
                   4765:  * Register a new function. If @f is NULL it unregisters the function
                   4766:  *
                   4767:  * Returns 0 in case of success, -1 in case of error
                   4768:  */
                   4769: int
                   4770: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4771:                     xmlXPathFunction f) {
                   4772:     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
                   4773: }
                   4774: 
                   4775: /**
                   4776:  * xmlXPathRegisterFuncNS:
                   4777:  * @ctxt:  the XPath context
                   4778:  * @name:  the function name
                   4779:  * @ns_uri:  the function namespace URI
                   4780:  * @f:  the function implementation or NULL
                   4781:  *
                   4782:  * Register a new function. If @f is NULL it unregisters the function
                   4783:  *
                   4784:  * Returns 0 in case of success, -1 in case of error
                   4785:  */
                   4786: int
                   4787: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4788:                       const xmlChar *ns_uri, xmlXPathFunction f) {
                   4789:     if (ctxt == NULL)
                   4790:        return(-1);
                   4791:     if (name == NULL)
                   4792:        return(-1);
                   4793: 
                   4794:     if (ctxt->funcHash == NULL)
                   4795:        ctxt->funcHash = xmlHashCreate(0);
                   4796:     if (ctxt->funcHash == NULL)
                   4797:        return(-1);
                   4798:     if (f == NULL)
                   4799:         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
                   4800:     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
                   4801: }
                   4802: 
                   4803: /**
                   4804:  * xmlXPathRegisterFuncLookup:
                   4805:  * @ctxt:  the XPath context
                   4806:  * @f:  the lookup function
                   4807:  * @funcCtxt:  the lookup data
                   4808:  *
                   4809:  * Registers an external mechanism to do function lookup.
                   4810:  */
                   4811: void
                   4812: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
                   4813:                            xmlXPathFuncLookupFunc f,
                   4814:                            void *funcCtxt) {
                   4815:     if (ctxt == NULL)
                   4816:        return;
                   4817:     ctxt->funcLookupFunc = f;
                   4818:     ctxt->funcLookupData = funcCtxt;
                   4819: }
                   4820: 
                   4821: /**
                   4822:  * xmlXPathFunctionLookup:
                   4823:  * @ctxt:  the XPath context
                   4824:  * @name:  the function name
                   4825:  *
                   4826:  * Search in the Function array of the context for the given
                   4827:  * function.
                   4828:  *
                   4829:  * Returns the xmlXPathFunction or NULL if not found
                   4830:  */
                   4831: xmlXPathFunction
                   4832: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
                   4833:     if (ctxt == NULL)
                   4834:        return (NULL);
                   4835: 
                   4836:     if (ctxt->funcLookupFunc != NULL) {
                   4837:        xmlXPathFunction ret;
                   4838:        xmlXPathFuncLookupFunc f;
                   4839: 
                   4840:        f = ctxt->funcLookupFunc;
                   4841:        ret = f(ctxt->funcLookupData, name, NULL);
                   4842:        if (ret != NULL)
                   4843:            return(ret);
                   4844:     }
                   4845:     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
                   4846: }
                   4847: 
                   4848: /**
                   4849:  * xmlXPathFunctionLookupNS:
                   4850:  * @ctxt:  the XPath context
                   4851:  * @name:  the function name
                   4852:  * @ns_uri:  the function namespace URI
                   4853:  *
                   4854:  * Search in the Function array of the context for the given
                   4855:  * function.
                   4856:  *
                   4857:  * Returns the xmlXPathFunction or NULL if not found
                   4858:  */
                   4859: xmlXPathFunction
                   4860: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4861:                         const xmlChar *ns_uri) {
                   4862:     xmlXPathFunction ret;
                   4863: 
                   4864:     if (ctxt == NULL)
                   4865:        return(NULL);
                   4866:     if (name == NULL)
                   4867:        return(NULL);
                   4868: 
                   4869:     if (ctxt->funcLookupFunc != NULL) {
                   4870:        xmlXPathFuncLookupFunc f;
                   4871: 
                   4872:        f = ctxt->funcLookupFunc;
                   4873:        ret = f(ctxt->funcLookupData, name, ns_uri);
                   4874:        if (ret != NULL)
                   4875:            return(ret);
                   4876:     }
                   4877: 
                   4878:     if (ctxt->funcHash == NULL)
                   4879:        return(NULL);
                   4880: 
                   4881:     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
                   4882:     return(ret);
                   4883: }
                   4884: 
                   4885: /**
                   4886:  * xmlXPathRegisteredFuncsCleanup:
                   4887:  * @ctxt:  the XPath context
                   4888:  *
                   4889:  * Cleanup the XPath context data associated to registered functions
                   4890:  */
                   4891: void
                   4892: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
                   4893:     if (ctxt == NULL)
                   4894:        return;
                   4895: 
                   4896:     xmlHashFree(ctxt->funcHash, NULL);
                   4897:     ctxt->funcHash = NULL;
                   4898: }
                   4899: 
                   4900: /************************************************************************
                   4901:  *                                                                     *
                   4902:  *                     Routines to handle Variables                    *
                   4903:  *                                                                     *
                   4904:  ************************************************************************/
                   4905: 
                   4906: /**
                   4907:  * xmlXPathRegisterVariable:
                   4908:  * @ctxt:  the XPath context
                   4909:  * @name:  the variable name
                   4910:  * @value:  the variable value or NULL
                   4911:  *
                   4912:  * Register a new variable value. If @value is NULL it unregisters
                   4913:  * the variable
                   4914:  *
                   4915:  * Returns 0 in case of success, -1 in case of error
                   4916:  */
                   4917: int
                   4918: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4919:                         xmlXPathObjectPtr value) {
                   4920:     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
                   4921: }
                   4922: 
                   4923: /**
                   4924:  * xmlXPathRegisterVariableNS:
                   4925:  * @ctxt:  the XPath context
                   4926:  * @name:  the variable name
                   4927:  * @ns_uri:  the variable namespace URI
                   4928:  * @value:  the variable value or NULL
                   4929:  *
                   4930:  * Register a new variable value. If @value is NULL it unregisters
                   4931:  * the variable
                   4932:  *
                   4933:  * Returns 0 in case of success, -1 in case of error
                   4934:  */
                   4935: int
                   4936: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4937:                           const xmlChar *ns_uri,
                   4938:                           xmlXPathObjectPtr value) {
                   4939:     if (ctxt == NULL)
                   4940:        return(-1);
                   4941:     if (name == NULL)
                   4942:        return(-1);
                   4943: 
                   4944:     if (ctxt->varHash == NULL)
                   4945:        ctxt->varHash = xmlHashCreate(0);
                   4946:     if (ctxt->varHash == NULL)
                   4947:        return(-1);
                   4948:     if (value == NULL)
                   4949:         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
                   4950:                                   (xmlHashDeallocator)xmlXPathFreeObject));
                   4951:     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
                   4952:                               (void *) value,
                   4953:                               (xmlHashDeallocator)xmlXPathFreeObject));
                   4954: }
                   4955: 
                   4956: /**
                   4957:  * xmlXPathRegisterVariableLookup:
                   4958:  * @ctxt:  the XPath context
                   4959:  * @f:  the lookup function
                   4960:  * @data:  the lookup data
                   4961:  *
                   4962:  * register an external mechanism to do variable lookup
                   4963:  */
                   4964: void
                   4965: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
                   4966:         xmlXPathVariableLookupFunc f, void *data) {
                   4967:     if (ctxt == NULL)
                   4968:        return;
                   4969:     ctxt->varLookupFunc = f;
                   4970:     ctxt->varLookupData = data;
                   4971: }
                   4972: 
                   4973: /**
                   4974:  * xmlXPathVariableLookup:
                   4975:  * @ctxt:  the XPath context
                   4976:  * @name:  the variable name
                   4977:  *
                   4978:  * Search in the Variable array of the context for the given
                   4979:  * variable value.
                   4980:  *
                   4981:  * Returns a copy of the value or NULL if not found
                   4982:  */
                   4983: xmlXPathObjectPtr
                   4984: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
                   4985:     if (ctxt == NULL)
                   4986:        return(NULL);
                   4987: 
                   4988:     if (ctxt->varLookupFunc != NULL) {
                   4989:        xmlXPathObjectPtr ret;
                   4990: 
                   4991:        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
                   4992:                (ctxt->varLookupData, name, NULL);
                   4993:        return(ret);
                   4994:     }
                   4995:     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
                   4996: }
                   4997: 
                   4998: /**
                   4999:  * xmlXPathVariableLookupNS:
                   5000:  * @ctxt:  the XPath context
                   5001:  * @name:  the variable name
                   5002:  * @ns_uri:  the variable namespace URI
                   5003:  *
                   5004:  * Search in the Variable array of the context for the given
                   5005:  * variable value.
                   5006:  *
                   5007:  * Returns the a copy of the value or NULL if not found
                   5008:  */
                   5009: xmlXPathObjectPtr
                   5010: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   5011:                         const xmlChar *ns_uri) {
                   5012:     if (ctxt == NULL)
                   5013:        return(NULL);
                   5014: 
                   5015:     if (ctxt->varLookupFunc != NULL) {
                   5016:        xmlXPathObjectPtr ret;
                   5017: 
                   5018:        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
                   5019:                (ctxt->varLookupData, name, ns_uri);
                   5020:        if (ret != NULL) return(ret);
                   5021:     }
                   5022: 
                   5023:     if (ctxt->varHash == NULL)
                   5024:        return(NULL);
                   5025:     if (name == NULL)
                   5026:        return(NULL);
                   5027: 
                   5028:     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
                   5029:                xmlHashLookup2(ctxt->varHash, name, ns_uri)));
                   5030: }
                   5031: 
                   5032: /**
                   5033:  * xmlXPathRegisteredVariablesCleanup:
                   5034:  * @ctxt:  the XPath context
                   5035:  *
                   5036:  * Cleanup the XPath context data associated to registered variables
                   5037:  */
                   5038: void
                   5039: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
                   5040:     if (ctxt == NULL)
                   5041:        return;
                   5042: 
                   5043:     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
                   5044:     ctxt->varHash = NULL;
                   5045: }
                   5046: 
                   5047: /**
                   5048:  * xmlXPathRegisterNs:
                   5049:  * @ctxt:  the XPath context
                   5050:  * @prefix:  the namespace prefix cannot be NULL or empty string
                   5051:  * @ns_uri:  the namespace name
                   5052:  *
                   5053:  * Register a new namespace. If @ns_uri is NULL it unregisters
                   5054:  * the namespace
                   5055:  *
                   5056:  * Returns 0 in case of success, -1 in case of error
                   5057:  */
                   5058: int
                   5059: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
                   5060:                           const xmlChar *ns_uri) {
                   5061:     if (ctxt == NULL)
                   5062:        return(-1);
                   5063:     if (prefix == NULL)
                   5064:        return(-1);
                   5065:     if (prefix[0] == 0)
                   5066:        return(-1);
                   5067: 
                   5068:     if (ctxt->nsHash == NULL)
                   5069:        ctxt->nsHash = xmlHashCreate(10);
                   5070:     if (ctxt->nsHash == NULL)
                   5071:        return(-1);
                   5072:     if (ns_uri == NULL)
                   5073:         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
                   5074:                                  (xmlHashDeallocator)xmlFree));
                   5075:     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
                   5076:                              (xmlHashDeallocator)xmlFree));
                   5077: }
                   5078: 
                   5079: /**
                   5080:  * xmlXPathNsLookup:
                   5081:  * @ctxt:  the XPath context
                   5082:  * @prefix:  the namespace prefix value
                   5083:  *
                   5084:  * Search in the namespace declaration array of the context for the given
                   5085:  * namespace name associated to the given prefix
                   5086:  *
                   5087:  * Returns the value or NULL if not found
                   5088:  */
                   5089: const xmlChar *
                   5090: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
                   5091:     if (ctxt == NULL)
                   5092:        return(NULL);
                   5093:     if (prefix == NULL)
                   5094:        return(NULL);
                   5095: 
                   5096: #ifdef XML_XML_NAMESPACE
                   5097:     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
                   5098:        return(XML_XML_NAMESPACE);
                   5099: #endif
                   5100: 
                   5101:     if (ctxt->namespaces != NULL) {
                   5102:        int i;
                   5103: 
                   5104:        for (i = 0;i < ctxt->nsNr;i++) {
                   5105:            if ((ctxt->namespaces[i] != NULL) &&
                   5106:                (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
                   5107:                return(ctxt->namespaces[i]->href);
                   5108:        }
                   5109:     }
                   5110: 
                   5111:     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
                   5112: }
                   5113: 
                   5114: /**
                   5115:  * xmlXPathRegisteredNsCleanup:
                   5116:  * @ctxt:  the XPath context
                   5117:  *
                   5118:  * Cleanup the XPath context data associated to registered variables
                   5119:  */
                   5120: void
                   5121: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
                   5122:     if (ctxt == NULL)
                   5123:        return;
                   5124: 
                   5125:     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
                   5126:     ctxt->nsHash = NULL;
                   5127: }
                   5128: 
                   5129: /************************************************************************
                   5130:  *                                                                     *
                   5131:  *                     Routines to handle Values                       *
                   5132:  *                                                                     *
                   5133:  ************************************************************************/
                   5134: 
                   5135: /* Allocations are terrible, one needs to optimize all this !!! */
                   5136: 
                   5137: /**
                   5138:  * xmlXPathNewFloat:
                   5139:  * @val:  the double value
                   5140:  *
                   5141:  * Create a new xmlXPathObjectPtr of type double and of value @val
                   5142:  *
                   5143:  * Returns the newly created object.
                   5144:  */
                   5145: xmlXPathObjectPtr
                   5146: xmlXPathNewFloat(double val) {
                   5147:     xmlXPathObjectPtr ret;
                   5148: 
                   5149:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5150:     if (ret == NULL) {
                   5151:         xmlXPathErrMemory(NULL, "creating float object\n");
                   5152:        return(NULL);
                   5153:     }
                   5154:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5155:     ret->type = XPATH_NUMBER;
                   5156:     ret->floatval = val;
                   5157: #ifdef XP_DEBUG_OBJ_USAGE
                   5158:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
                   5159: #endif
                   5160:     return(ret);
                   5161: }
                   5162: 
                   5163: /**
                   5164:  * xmlXPathNewBoolean:
                   5165:  * @val:  the boolean value
                   5166:  *
                   5167:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
                   5168:  *
                   5169:  * Returns the newly created object.
                   5170:  */
                   5171: xmlXPathObjectPtr
                   5172: xmlXPathNewBoolean(int val) {
                   5173:     xmlXPathObjectPtr ret;
                   5174: 
                   5175:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5176:     if (ret == NULL) {
                   5177:         xmlXPathErrMemory(NULL, "creating boolean object\n");
                   5178:        return(NULL);
                   5179:     }
                   5180:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5181:     ret->type = XPATH_BOOLEAN;
                   5182:     ret->boolval = (val != 0);
                   5183: #ifdef XP_DEBUG_OBJ_USAGE
                   5184:     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
                   5185: #endif
                   5186:     return(ret);
                   5187: }
                   5188: 
                   5189: /**
                   5190:  * xmlXPathNewString:
                   5191:  * @val:  the xmlChar * value
                   5192:  *
                   5193:  * Create a new xmlXPathObjectPtr of type string and of value @val
                   5194:  *
                   5195:  * Returns the newly created object.
                   5196:  */
                   5197: xmlXPathObjectPtr
                   5198: xmlXPathNewString(const xmlChar *val) {
                   5199:     xmlXPathObjectPtr ret;
                   5200: 
                   5201:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5202:     if (ret == NULL) {
                   5203:         xmlXPathErrMemory(NULL, "creating string object\n");
                   5204:        return(NULL);
                   5205:     }
                   5206:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5207:     ret->type = XPATH_STRING;
                   5208:     if (val != NULL)
                   5209:        ret->stringval = xmlStrdup(val);
                   5210:     else
                   5211:        ret->stringval = xmlStrdup((const xmlChar *)"");
                   5212: #ifdef XP_DEBUG_OBJ_USAGE
                   5213:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
                   5214: #endif
                   5215:     return(ret);
                   5216: }
                   5217: 
                   5218: /**
                   5219:  * xmlXPathWrapString:
                   5220:  * @val:  the xmlChar * value
                   5221:  *
                   5222:  * Wraps the @val string into an XPath object.
                   5223:  *
                   5224:  * Returns the newly created object.
                   5225:  */
                   5226: xmlXPathObjectPtr
                   5227: xmlXPathWrapString (xmlChar *val) {
                   5228:     xmlXPathObjectPtr ret;
                   5229: 
                   5230:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5231:     if (ret == NULL) {
                   5232:         xmlXPathErrMemory(NULL, "creating string object\n");
                   5233:        return(NULL);
                   5234:     }
                   5235:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5236:     ret->type = XPATH_STRING;
                   5237:     ret->stringval = val;
                   5238: #ifdef XP_DEBUG_OBJ_USAGE
                   5239:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
                   5240: #endif
                   5241:     return(ret);
                   5242: }
                   5243: 
                   5244: /**
                   5245:  * xmlXPathNewCString:
                   5246:  * @val:  the char * value
                   5247:  *
                   5248:  * Create a new xmlXPathObjectPtr of type string and of value @val
                   5249:  *
                   5250:  * Returns the newly created object.
                   5251:  */
                   5252: xmlXPathObjectPtr
                   5253: xmlXPathNewCString(const char *val) {
                   5254:     xmlXPathObjectPtr ret;
                   5255: 
                   5256:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5257:     if (ret == NULL) {
                   5258:         xmlXPathErrMemory(NULL, "creating string object\n");
                   5259:        return(NULL);
                   5260:     }
                   5261:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5262:     ret->type = XPATH_STRING;
                   5263:     ret->stringval = xmlStrdup(BAD_CAST val);
                   5264: #ifdef XP_DEBUG_OBJ_USAGE
                   5265:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
                   5266: #endif
                   5267:     return(ret);
                   5268: }
                   5269: 
                   5270: /**
                   5271:  * xmlXPathWrapCString:
                   5272:  * @val:  the char * value
                   5273:  *
                   5274:  * Wraps a string into an XPath object.
                   5275:  *
                   5276:  * Returns the newly created object.
                   5277:  */
                   5278: xmlXPathObjectPtr
                   5279: xmlXPathWrapCString (char * val) {
                   5280:     return(xmlXPathWrapString((xmlChar *)(val)));
                   5281: }
                   5282: 
                   5283: /**
                   5284:  * xmlXPathWrapExternal:
                   5285:  * @val:  the user data
                   5286:  *
                   5287:  * Wraps the @val data into an XPath object.
                   5288:  *
                   5289:  * Returns the newly created object.
                   5290:  */
                   5291: xmlXPathObjectPtr
                   5292: xmlXPathWrapExternal (void *val) {
                   5293:     xmlXPathObjectPtr ret;
                   5294: 
                   5295:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5296:     if (ret == NULL) {
                   5297:         xmlXPathErrMemory(NULL, "creating user object\n");
                   5298:        return(NULL);
                   5299:     }
                   5300:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5301:     ret->type = XPATH_USERS;
                   5302:     ret->user = val;
                   5303: #ifdef XP_DEBUG_OBJ_USAGE
                   5304:     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
                   5305: #endif
                   5306:     return(ret);
                   5307: }
                   5308: 
                   5309: /**
                   5310:  * xmlXPathObjectCopy:
                   5311:  * @val:  the original object
                   5312:  *
                   5313:  * allocate a new copy of a given object
                   5314:  *
                   5315:  * Returns the newly created object.
                   5316:  */
                   5317: xmlXPathObjectPtr
                   5318: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
                   5319:     xmlXPathObjectPtr ret;
                   5320: 
                   5321:     if (val == NULL)
                   5322:        return(NULL);
                   5323: 
                   5324:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5325:     if (ret == NULL) {
                   5326:         xmlXPathErrMemory(NULL, "copying object\n");
                   5327:        return(NULL);
                   5328:     }
                   5329:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
                   5330: #ifdef XP_DEBUG_OBJ_USAGE
                   5331:     xmlXPathDebugObjUsageRequested(NULL, val->type);
                   5332: #endif
                   5333:     switch (val->type) {
                   5334:        case XPATH_BOOLEAN:
                   5335:        case XPATH_NUMBER:
                   5336:        case XPATH_POINT:
                   5337:        case XPATH_RANGE:
                   5338:            break;
                   5339:        case XPATH_STRING:
                   5340:            ret->stringval = xmlStrdup(val->stringval);
                   5341:            break;
                   5342:        case XPATH_XSLT_TREE:
                   5343: #if 0
                   5344: /*
                   5345:   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
                   5346:   this previous handling is no longer correct, and can cause some serious
                   5347:   problems (ref. bug 145547)
                   5348: */
                   5349:            if ((val->nodesetval != NULL) &&
                   5350:                (val->nodesetval->nodeTab != NULL)) {
                   5351:                xmlNodePtr cur, tmp;
                   5352:                xmlDocPtr top;
                   5353: 
                   5354:                ret->boolval = 1;
                   5355:                top =  xmlNewDoc(NULL);
                   5356:                top->name = (char *)
                   5357:                    xmlStrdup(val->nodesetval->nodeTab[0]->name);
                   5358:                ret->user = top;
                   5359:                if (top != NULL) {
                   5360:                    top->doc = top;
                   5361:                    cur = val->nodesetval->nodeTab[0]->children;
                   5362:                    while (cur != NULL) {
                   5363:                        tmp = xmlDocCopyNode(cur, top, 1);
                   5364:                        xmlAddChild((xmlNodePtr) top, tmp);
                   5365:                        cur = cur->next;
                   5366:                    }
                   5367:                }
                   5368: 
                   5369:                ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
                   5370:            } else
                   5371:                ret->nodesetval = xmlXPathNodeSetCreate(NULL);
                   5372:            /* Deallocate the copied tree value */
                   5373:            break;
                   5374: #endif
                   5375:        case XPATH_NODESET:
                   5376:            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
                   5377:            /* Do not deallocate the copied tree value */
                   5378:            ret->boolval = 0;
                   5379:            break;
                   5380:        case XPATH_LOCATIONSET:
                   5381: #ifdef LIBXML_XPTR_ENABLED
                   5382:        {
                   5383:            xmlLocationSetPtr loc = val->user;
                   5384:            ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
                   5385:            break;
                   5386:        }
                   5387: #endif
                   5388:         case XPATH_USERS:
                   5389:            ret->user = val->user;
                   5390:            break;
                   5391:         case XPATH_UNDEFINED:
                   5392:            xmlGenericError(xmlGenericErrorContext,
                   5393:                    "xmlXPathObjectCopy: unsupported type %d\n",
                   5394:                    val->type);
                   5395:            break;
                   5396:     }
                   5397:     return(ret);
                   5398: }
                   5399: 
                   5400: /**
                   5401:  * xmlXPathFreeObject:
                   5402:  * @obj:  the object to free
                   5403:  *
                   5404:  * Free up an xmlXPathObjectPtr object.
                   5405:  */
                   5406: void
                   5407: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
                   5408:     if (obj == NULL) return;
                   5409:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
                   5410:        if (obj->boolval) {
                   5411: #if 0
                   5412:            if (obj->user != NULL) {
                   5413:                 xmlXPathFreeNodeSet(obj->nodesetval);
                   5414:                xmlFreeNodeList((xmlNodePtr) obj->user);
                   5415:            } else
                   5416: #endif
                   5417:            obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
                   5418:            if (obj->nodesetval != NULL)
                   5419:                xmlXPathFreeValueTree(obj->nodesetval);
                   5420:        } else {
                   5421:            if (obj->nodesetval != NULL)
                   5422:                xmlXPathFreeNodeSet(obj->nodesetval);
                   5423:        }
                   5424: #ifdef LIBXML_XPTR_ENABLED
                   5425:     } else if (obj->type == XPATH_LOCATIONSET) {
                   5426:        if (obj->user != NULL)
                   5427:            xmlXPtrFreeLocationSet(obj->user);
                   5428: #endif
                   5429:     } else if (obj->type == XPATH_STRING) {
                   5430:        if (obj->stringval != NULL)
                   5431:            xmlFree(obj->stringval);
                   5432:     }
                   5433: #ifdef XP_DEBUG_OBJ_USAGE
                   5434:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
                   5435: #endif
                   5436:     xmlFree(obj);
                   5437: }
                   5438: 
                   5439: /**
                   5440:  * xmlXPathReleaseObject:
                   5441:  * @obj:  the xmlXPathObjectPtr to free or to cache
                   5442:  *
                   5443:  * Depending on the state of the cache this frees the given
                   5444:  * XPath object or stores it in the cache.
                   5445:  */
                   5446: static void
                   5447: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
                   5448: {
                   5449: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
                   5450:        sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
                   5451:     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
                   5452: 
                   5453: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
                   5454: 
                   5455:     if (obj == NULL)
                   5456:        return;
                   5457:     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
                   5458:         xmlXPathFreeObject(obj);
                   5459:     } else {
                   5460:        xmlXPathContextCachePtr cache =
                   5461:            (xmlXPathContextCachePtr) ctxt->cache;
                   5462: 
                   5463:        switch (obj->type) {
                   5464:            case XPATH_NODESET:
                   5465:            case XPATH_XSLT_TREE:
                   5466:                if (obj->nodesetval != NULL) {
                   5467:                    if (obj->boolval) {
                   5468:                        /*
                   5469:                        * It looks like the @boolval is used for
                   5470:                        * evaluation if this an XSLT Result Tree Fragment.
                   5471:                        * TODO: Check if this assumption is correct.
                   5472:                        */
                   5473:                        obj->type = XPATH_XSLT_TREE; /* just for debugging */
                   5474:                        xmlXPathFreeValueTree(obj->nodesetval);
                   5475:                        obj->nodesetval = NULL;
                   5476:                    } else if ((obj->nodesetval->nodeMax <= 40) &&
                   5477:                        (XP_CACHE_WANTS(cache->nodesetObjs,
                   5478:                                        cache->maxNodeset)))
                   5479:                    {
                   5480:                        XP_CACHE_ADD(cache->nodesetObjs, obj);
                   5481:                        goto obj_cached;
                   5482:                    } else {
                   5483:                        xmlXPathFreeNodeSet(obj->nodesetval);
                   5484:                        obj->nodesetval = NULL;
                   5485:                    }
                   5486:                }
                   5487:                break;
                   5488:            case XPATH_STRING:
                   5489:                if (obj->stringval != NULL)
                   5490:                    xmlFree(obj->stringval);
                   5491: 
                   5492:                if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
                   5493:                    XP_CACHE_ADD(cache->stringObjs, obj);
                   5494:                    goto obj_cached;
                   5495:                }
                   5496:                break;
                   5497:            case XPATH_BOOLEAN:
                   5498:                if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
                   5499:                    XP_CACHE_ADD(cache->booleanObjs, obj);
                   5500:                    goto obj_cached;
                   5501:                }
                   5502:                break;
                   5503:            case XPATH_NUMBER:
                   5504:                if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
                   5505:                    XP_CACHE_ADD(cache->numberObjs, obj);
                   5506:                    goto obj_cached;
                   5507:                }
                   5508:                break;
                   5509: #ifdef LIBXML_XPTR_ENABLED
                   5510:            case XPATH_LOCATIONSET:
                   5511:                if (obj->user != NULL) {
                   5512:                    xmlXPtrFreeLocationSet(obj->user);
                   5513:                }
                   5514:                goto free_obj;
                   5515: #endif
                   5516:            default:
                   5517:                goto free_obj;
                   5518:        }
                   5519: 
                   5520:        /*
                   5521:        * Fallback to adding to the misc-objects slot.
                   5522:        */
                   5523:        if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
                   5524:            XP_CACHE_ADD(cache->miscObjs, obj);
                   5525:        } else
                   5526:            goto free_obj;
                   5527: 
                   5528: obj_cached:
                   5529: 
                   5530: #ifdef XP_DEBUG_OBJ_USAGE
                   5531:        xmlXPathDebugObjUsageReleased(ctxt, obj->type);
                   5532: #endif
                   5533: 
                   5534:        if (obj->nodesetval != NULL) {
                   5535:            xmlNodeSetPtr tmpset = obj->nodesetval;
                   5536: 
                   5537:            /*
                   5538:            * TODO: Due to those nasty ns-nodes, we need to traverse
                   5539:            *  the list and free the ns-nodes.
                   5540:            * URGENT TODO: Check if it's actually slowing things down.
                   5541:            *  Maybe we shouldn't try to preserve the list.
                   5542:            */
                   5543:            if (tmpset->nodeNr > 1) {
                   5544:                int i;
                   5545:                xmlNodePtr node;
                   5546: 
                   5547:                for (i = 0; i < tmpset->nodeNr; i++) {
                   5548:                    node = tmpset->nodeTab[i];
                   5549:                    if ((node != NULL) &&
                   5550:                        (node->type == XML_NAMESPACE_DECL))
                   5551:                    {
                   5552:                        xmlXPathNodeSetFreeNs((xmlNsPtr) node);
                   5553:                    }
                   5554:                }
                   5555:            } else if (tmpset->nodeNr == 1) {
                   5556:                if ((tmpset->nodeTab[0] != NULL) &&
                   5557:                    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
                   5558:                    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
                   5559:            }
                   5560:            tmpset->nodeNr = 0;
                   5561:            memset(obj, 0, sizeof(xmlXPathObject));
                   5562:            obj->nodesetval = tmpset;
                   5563:        } else
                   5564:            memset(obj, 0, sizeof(xmlXPathObject));
                   5565: 
                   5566:        return;
                   5567: 
                   5568: free_obj:
                   5569:        /*
                   5570:        * Cache is full; free the object.
                   5571:        */
                   5572:        if (obj->nodesetval != NULL)
                   5573:            xmlXPathFreeNodeSet(obj->nodesetval);
                   5574: #ifdef XP_DEBUG_OBJ_USAGE
                   5575:        xmlXPathDebugObjUsageReleased(NULL, obj->type);
                   5576: #endif
                   5577:        xmlFree(obj);
                   5578:     }
                   5579:     return;
                   5580: }
                   5581: 
                   5582: 
                   5583: /************************************************************************
                   5584:  *                                                                     *
                   5585:  *                     Type Casting Routines                           *
                   5586:  *                                                                     *
                   5587:  ************************************************************************/
                   5588: 
                   5589: /**
                   5590:  * xmlXPathCastBooleanToString:
                   5591:  * @val:  a boolean
                   5592:  *
                   5593:  * Converts a boolean to its string value.
                   5594:  *
                   5595:  * Returns a newly allocated string.
                   5596:  */
                   5597: xmlChar *
                   5598: xmlXPathCastBooleanToString (int val) {
                   5599:     xmlChar *ret;
                   5600:     if (val)
                   5601:        ret = xmlStrdup((const xmlChar *) "true");
                   5602:     else
                   5603:        ret = xmlStrdup((const xmlChar *) "false");
                   5604:     return(ret);
                   5605: }
                   5606: 
                   5607: /**
                   5608:  * xmlXPathCastNumberToString:
                   5609:  * @val:  a number
                   5610:  *
                   5611:  * Converts a number to its string value.
                   5612:  *
                   5613:  * Returns a newly allocated string.
                   5614:  */
                   5615: xmlChar *
                   5616: xmlXPathCastNumberToString (double val) {
                   5617:     xmlChar *ret;
                   5618:     switch (xmlXPathIsInf(val)) {
                   5619:     case 1:
                   5620:        ret = xmlStrdup((const xmlChar *) "Infinity");
                   5621:        break;
                   5622:     case -1:
                   5623:        ret = xmlStrdup((const xmlChar *) "-Infinity");
                   5624:        break;
                   5625:     default:
                   5626:        if (xmlXPathIsNaN(val)) {
                   5627:            ret = xmlStrdup((const xmlChar *) "NaN");
                   5628:        } else if (val == 0 && xmlXPathGetSign(val) != 0) {
                   5629:            ret = xmlStrdup((const xmlChar *) "0");
                   5630:        } else {
                   5631:            /* could be improved */
                   5632:            char buf[100];
                   5633:            xmlXPathFormatNumber(val, buf, 99);
                   5634:            buf[99] = 0;
                   5635:            ret = xmlStrdup((const xmlChar *) buf);
                   5636:        }
                   5637:     }
                   5638:     return(ret);
                   5639: }
                   5640: 
                   5641: /**
                   5642:  * xmlXPathCastNodeToString:
                   5643:  * @node:  a node
                   5644:  *
                   5645:  * Converts a node to its string value.
                   5646:  *
                   5647:  * Returns a newly allocated string.
                   5648:  */
                   5649: xmlChar *
                   5650: xmlXPathCastNodeToString (xmlNodePtr node) {
                   5651: xmlChar *ret;
                   5652:     if ((ret = xmlNodeGetContent(node)) == NULL)
                   5653:        ret = xmlStrdup((const xmlChar *) "");
                   5654:     return(ret);
                   5655: }
                   5656: 
                   5657: /**
                   5658:  * xmlXPathCastNodeSetToString:
                   5659:  * @ns:  a node-set
                   5660:  *
                   5661:  * Converts a node-set to its string value.
                   5662:  *
                   5663:  * Returns a newly allocated string.
                   5664:  */
                   5665: xmlChar *
                   5666: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
                   5667:     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
                   5668:        return(xmlStrdup((const xmlChar *) ""));
                   5669: 
                   5670:     if (ns->nodeNr > 1)
                   5671:        xmlXPathNodeSetSort(ns);
                   5672:     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
                   5673: }
                   5674: 
                   5675: /**
                   5676:  * xmlXPathCastToString:
                   5677:  * @val:  an XPath object
                   5678:  *
                   5679:  * Converts an existing object to its string() equivalent
                   5680:  *
                   5681:  * Returns the allocated string value of the object, NULL in case of error.
                   5682:  *         It's up to the caller to free the string memory with xmlFree().
                   5683:  */
                   5684: xmlChar *
                   5685: xmlXPathCastToString(xmlXPathObjectPtr val) {
                   5686:     xmlChar *ret = NULL;
                   5687: 
                   5688:     if (val == NULL)
                   5689:        return(xmlStrdup((const xmlChar *) ""));
                   5690:     switch (val->type) {
                   5691:        case XPATH_UNDEFINED:
                   5692: #ifdef DEBUG_EXPR
                   5693:            xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
                   5694: #endif
                   5695:            ret = xmlStrdup((const xmlChar *) "");
                   5696:            break;
                   5697:         case XPATH_NODESET:
                   5698:         case XPATH_XSLT_TREE:
                   5699:            ret = xmlXPathCastNodeSetToString(val->nodesetval);
                   5700:            break;
                   5701:        case XPATH_STRING:
                   5702:            return(xmlStrdup(val->stringval));
                   5703:         case XPATH_BOOLEAN:
                   5704:            ret = xmlXPathCastBooleanToString(val->boolval);
                   5705:            break;
                   5706:        case XPATH_NUMBER: {
                   5707:            ret = xmlXPathCastNumberToString(val->floatval);
                   5708:            break;
                   5709:        }
                   5710:        case XPATH_USERS:
                   5711:        case XPATH_POINT:
                   5712:        case XPATH_RANGE:
                   5713:        case XPATH_LOCATIONSET:
                   5714:            TODO
                   5715:            ret = xmlStrdup((const xmlChar *) "");
                   5716:            break;
                   5717:     }
                   5718:     return(ret);
                   5719: }
                   5720: 
                   5721: /**
                   5722:  * xmlXPathConvertString:
                   5723:  * @val:  an XPath object
                   5724:  *
                   5725:  * Converts an existing object to its string() equivalent
                   5726:  *
                   5727:  * Returns the new object, the old one is freed (or the operation
                   5728:  *         is done directly on @val)
                   5729:  */
                   5730: xmlXPathObjectPtr
                   5731: xmlXPathConvertString(xmlXPathObjectPtr val) {
                   5732:     xmlChar *res = NULL;
                   5733: 
                   5734:     if (val == NULL)
                   5735:        return(xmlXPathNewCString(""));
                   5736: 
                   5737:     switch (val->type) {
                   5738:     case XPATH_UNDEFINED:
                   5739: #ifdef DEBUG_EXPR
                   5740:        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
                   5741: #endif
                   5742:        break;
                   5743:     case XPATH_NODESET:
                   5744:     case XPATH_XSLT_TREE:
                   5745:        res = xmlXPathCastNodeSetToString(val->nodesetval);
                   5746:        break;
                   5747:     case XPATH_STRING:
                   5748:        return(val);
                   5749:     case XPATH_BOOLEAN:
                   5750:        res = xmlXPathCastBooleanToString(val->boolval);
                   5751:        break;
                   5752:     case XPATH_NUMBER:
                   5753:        res = xmlXPathCastNumberToString(val->floatval);
                   5754:        break;
                   5755:     case XPATH_USERS:
                   5756:     case XPATH_POINT:
                   5757:     case XPATH_RANGE:
                   5758:     case XPATH_LOCATIONSET:
                   5759:        TODO;
                   5760:        break;
                   5761:     }
                   5762:     xmlXPathFreeObject(val);
                   5763:     if (res == NULL)
                   5764:        return(xmlXPathNewCString(""));
                   5765:     return(xmlXPathWrapString(res));
                   5766: }
                   5767: 
                   5768: /**
                   5769:  * xmlXPathCastBooleanToNumber:
                   5770:  * @val:  a boolean
                   5771:  *
                   5772:  * Converts a boolean to its number value
                   5773:  *
                   5774:  * Returns the number value
                   5775:  */
                   5776: double
                   5777: xmlXPathCastBooleanToNumber(int val) {
                   5778:     if (val)
                   5779:        return(1.0);
                   5780:     return(0.0);
                   5781: }
                   5782: 
                   5783: /**
                   5784:  * xmlXPathCastStringToNumber:
                   5785:  * @val:  a string
                   5786:  *
                   5787:  * Converts a string to its number value
                   5788:  *
                   5789:  * Returns the number value
                   5790:  */
                   5791: double
                   5792: xmlXPathCastStringToNumber(const xmlChar * val) {
                   5793:     return(xmlXPathStringEvalNumber(val));
                   5794: }
                   5795: 
                   5796: /**
                   5797:  * xmlXPathCastNodeToNumber:
                   5798:  * @node:  a node
                   5799:  *
                   5800:  * Converts a node to its number value
                   5801:  *
                   5802:  * Returns the number value
                   5803:  */
                   5804: double
                   5805: xmlXPathCastNodeToNumber (xmlNodePtr node) {
                   5806:     xmlChar *strval;
                   5807:     double ret;
                   5808: 
                   5809:     if (node == NULL)
                   5810:        return(xmlXPathNAN);
                   5811:     strval = xmlXPathCastNodeToString(node);
                   5812:     if (strval == NULL)
                   5813:        return(xmlXPathNAN);
                   5814:     ret = xmlXPathCastStringToNumber(strval);
                   5815:     xmlFree(strval);
                   5816: 
                   5817:     return(ret);
                   5818: }
                   5819: 
                   5820: /**
                   5821:  * xmlXPathCastNodeSetToNumber:
                   5822:  * @ns:  a node-set
                   5823:  *
                   5824:  * Converts a node-set to its number value
                   5825:  *
                   5826:  * Returns the number value
                   5827:  */
                   5828: double
                   5829: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
                   5830:     xmlChar *str;
                   5831:     double ret;
                   5832: 
                   5833:     if (ns == NULL)
                   5834:        return(xmlXPathNAN);
                   5835:     str = xmlXPathCastNodeSetToString(ns);
                   5836:     ret = xmlXPathCastStringToNumber(str);
                   5837:     xmlFree(str);
                   5838:     return(ret);
                   5839: }
                   5840: 
                   5841: /**
                   5842:  * xmlXPathCastToNumber:
                   5843:  * @val:  an XPath object
                   5844:  *
                   5845:  * Converts an XPath object to its number value
                   5846:  *
                   5847:  * Returns the number value
                   5848:  */
                   5849: double
                   5850: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
                   5851:     double ret = 0.0;
                   5852: 
                   5853:     if (val == NULL)
                   5854:        return(xmlXPathNAN);
                   5855:     switch (val->type) {
                   5856:     case XPATH_UNDEFINED:
                   5857: #ifdef DEGUB_EXPR
                   5858:        xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
                   5859: #endif
                   5860:        ret = xmlXPathNAN;
                   5861:        break;
                   5862:     case XPATH_NODESET:
                   5863:     case XPATH_XSLT_TREE:
                   5864:        ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
                   5865:        break;
                   5866:     case XPATH_STRING:
                   5867:        ret = xmlXPathCastStringToNumber(val->stringval);
                   5868:        break;
                   5869:     case XPATH_NUMBER:
                   5870:        ret = val->floatval;
                   5871:        break;
                   5872:     case XPATH_BOOLEAN:
                   5873:        ret = xmlXPathCastBooleanToNumber(val->boolval);
                   5874:        break;
                   5875:     case XPATH_USERS:
                   5876:     case XPATH_POINT:
                   5877:     case XPATH_RANGE:
                   5878:     case XPATH_LOCATIONSET:
                   5879:        TODO;
                   5880:        ret = xmlXPathNAN;
                   5881:        break;
                   5882:     }
                   5883:     return(ret);
                   5884: }
                   5885: 
                   5886: /**
                   5887:  * xmlXPathConvertNumber:
                   5888:  * @val:  an XPath object
                   5889:  *
                   5890:  * Converts an existing object to its number() equivalent
                   5891:  *
                   5892:  * Returns the new object, the old one is freed (or the operation
                   5893:  *         is done directly on @val)
                   5894:  */
                   5895: xmlXPathObjectPtr
                   5896: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
                   5897:     xmlXPathObjectPtr ret;
                   5898: 
                   5899:     if (val == NULL)
                   5900:        return(xmlXPathNewFloat(0.0));
                   5901:     if (val->type == XPATH_NUMBER)
                   5902:        return(val);
                   5903:     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
                   5904:     xmlXPathFreeObject(val);
                   5905:     return(ret);
                   5906: }
                   5907: 
                   5908: /**
                   5909:  * xmlXPathCastNumberToBoolean:
                   5910:  * @val:  a number
                   5911:  *
                   5912:  * Converts a number to its boolean value
                   5913:  *
                   5914:  * Returns the boolean value
                   5915:  */
                   5916: int
                   5917: xmlXPathCastNumberToBoolean (double val) {
                   5918:      if (xmlXPathIsNaN(val) || (val == 0.0))
                   5919:         return(0);
                   5920:      return(1);
                   5921: }
                   5922: 
                   5923: /**
                   5924:  * xmlXPathCastStringToBoolean:
                   5925:  * @val:  a string
                   5926:  *
                   5927:  * Converts a string to its boolean value
                   5928:  *
                   5929:  * Returns the boolean value
                   5930:  */
                   5931: int
                   5932: xmlXPathCastStringToBoolean (const xmlChar *val) {
                   5933:     if ((val == NULL) || (xmlStrlen(val) == 0))
                   5934:        return(0);
                   5935:     return(1);
                   5936: }
                   5937: 
                   5938: /**
                   5939:  * xmlXPathCastNodeSetToBoolean:
                   5940:  * @ns:  a node-set
                   5941:  *
                   5942:  * Converts a node-set to its boolean value
                   5943:  *
                   5944:  * Returns the boolean value
                   5945:  */
                   5946: int
                   5947: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
                   5948:     if ((ns == NULL) || (ns->nodeNr == 0))
                   5949:        return(0);
                   5950:     return(1);
                   5951: }
                   5952: 
                   5953: /**
                   5954:  * xmlXPathCastToBoolean:
                   5955:  * @val:  an XPath object
                   5956:  *
                   5957:  * Converts an XPath object to its boolean value
                   5958:  *
                   5959:  * Returns the boolean value
                   5960:  */
                   5961: int
                   5962: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
                   5963:     int ret = 0;
                   5964: 
                   5965:     if (val == NULL)
                   5966:        return(0);
                   5967:     switch (val->type) {
                   5968:     case XPATH_UNDEFINED:
                   5969: #ifdef DEBUG_EXPR
                   5970:        xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
                   5971: #endif
                   5972:        ret = 0;
                   5973:        break;
                   5974:     case XPATH_NODESET:
                   5975:     case XPATH_XSLT_TREE:
                   5976:        ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
                   5977:        break;
                   5978:     case XPATH_STRING:
                   5979:        ret = xmlXPathCastStringToBoolean(val->stringval);
                   5980:        break;
                   5981:     case XPATH_NUMBER:
                   5982:        ret = xmlXPathCastNumberToBoolean(val->floatval);
                   5983:        break;
                   5984:     case XPATH_BOOLEAN:
                   5985:        ret = val->boolval;
                   5986:        break;
                   5987:     case XPATH_USERS:
                   5988:     case XPATH_POINT:
                   5989:     case XPATH_RANGE:
                   5990:     case XPATH_LOCATIONSET:
                   5991:        TODO;
                   5992:        ret = 0;
                   5993:        break;
                   5994:     }
                   5995:     return(ret);
                   5996: }
                   5997: 
                   5998: 
                   5999: /**
                   6000:  * xmlXPathConvertBoolean:
                   6001:  * @val:  an XPath object
                   6002:  *
                   6003:  * Converts an existing object to its boolean() equivalent
                   6004:  *
                   6005:  * Returns the new object, the old one is freed (or the operation
                   6006:  *         is done directly on @val)
                   6007:  */
                   6008: xmlXPathObjectPtr
                   6009: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
                   6010:     xmlXPathObjectPtr ret;
                   6011: 
                   6012:     if (val == NULL)
                   6013:        return(xmlXPathNewBoolean(0));
                   6014:     if (val->type == XPATH_BOOLEAN)
                   6015:        return(val);
                   6016:     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
                   6017:     xmlXPathFreeObject(val);
                   6018:     return(ret);
                   6019: }
                   6020: 
                   6021: /************************************************************************
                   6022:  *                                                                     *
                   6023:  *             Routines to handle XPath contexts                       *
                   6024:  *                                                                     *
                   6025:  ************************************************************************/
                   6026: 
                   6027: /**
                   6028:  * xmlXPathNewContext:
                   6029:  * @doc:  the XML document
                   6030:  *
                   6031:  * Create a new xmlXPathContext
                   6032:  *
                   6033:  * Returns the xmlXPathContext just allocated. The caller will need to free it.
                   6034:  */
                   6035: xmlXPathContextPtr
                   6036: xmlXPathNewContext(xmlDocPtr doc) {
                   6037:     xmlXPathContextPtr ret;
                   6038: 
                   6039:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
                   6040:     if (ret == NULL) {
                   6041:         xmlXPathErrMemory(NULL, "creating context\n");
                   6042:        return(NULL);
                   6043:     }
                   6044:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
                   6045:     ret->doc = doc;
                   6046:     ret->node = NULL;
                   6047: 
                   6048:     ret->varHash = NULL;
                   6049: 
                   6050:     ret->nb_types = 0;
                   6051:     ret->max_types = 0;
                   6052:     ret->types = NULL;
                   6053: 
                   6054:     ret->funcHash = xmlHashCreate(0);
                   6055: 
                   6056:     ret->nb_axis = 0;
                   6057:     ret->max_axis = 0;
                   6058:     ret->axis = NULL;
                   6059: 
                   6060:     ret->nsHash = NULL;
                   6061:     ret->user = NULL;
                   6062: 
                   6063:     ret->contextSize = -1;
                   6064:     ret->proximityPosition = -1;
                   6065: 
                   6066: #ifdef XP_DEFAULT_CACHE_ON
                   6067:     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
                   6068:        xmlXPathFreeContext(ret);
                   6069:        return(NULL);
                   6070:     }
                   6071: #endif
                   6072: 
                   6073:     xmlXPathRegisterAllFunctions(ret);
                   6074: 
                   6075:     return(ret);
                   6076: }
                   6077: 
                   6078: /**
                   6079:  * xmlXPathFreeContext:
                   6080:  * @ctxt:  the context to free
                   6081:  *
                   6082:  * Free up an xmlXPathContext
                   6083:  */
                   6084: void
                   6085: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
                   6086:     if (ctxt == NULL) return;
                   6087: 
                   6088:     if (ctxt->cache != NULL)
                   6089:        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
                   6090:     xmlXPathRegisteredNsCleanup(ctxt);
                   6091:     xmlXPathRegisteredFuncsCleanup(ctxt);
                   6092:     xmlXPathRegisteredVariablesCleanup(ctxt);
                   6093:     xmlResetError(&ctxt->lastError);
                   6094:     xmlFree(ctxt);
                   6095: }
                   6096: 
                   6097: /************************************************************************
                   6098:  *                                                                     *
                   6099:  *             Routines to handle XPath parser contexts                *
                   6100:  *                                                                     *
                   6101:  ************************************************************************/
                   6102: 
                   6103: #define CHECK_CTXT(ctxt)                                               \
                   6104:     if (ctxt == NULL) {                                                \
                   6105:        __xmlRaiseError(NULL, NULL, NULL,                               \
                   6106:                NULL, NULL, XML_FROM_XPATH,                             \
                   6107:                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
                   6108:                __FILE__, __LINE__,                                     \
                   6109:                NULL, NULL, NULL, 0, 0,                                 \
                   6110:                "NULL context pointer\n");                              \
                   6111:        return(NULL);                                                   \
                   6112:     }                                                                  \
                   6113: 
                   6114: #define CHECK_CTXT_NEG(ctxt)                                           \
                   6115:     if (ctxt == NULL) {                                                \
                   6116:        __xmlRaiseError(NULL, NULL, NULL,                               \
                   6117:                NULL, NULL, XML_FROM_XPATH,                             \
                   6118:                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
                   6119:                __FILE__, __LINE__,                                     \
                   6120:                NULL, NULL, NULL, 0, 0,                                 \
                   6121:                "NULL context pointer\n");                              \
                   6122:        return(-1);                                                     \
                   6123:     }                                                                  \
                   6124: 
                   6125: 
                   6126: #define CHECK_CONTEXT(ctxt)                                            \
                   6127:     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                       \
                   6128:         (ctxt->doc->children == NULL)) {                               \
                   6129:        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
                   6130:        return(NULL);                                                   \
                   6131:     }
                   6132: 
                   6133: 
                   6134: /**
                   6135:  * xmlXPathNewParserContext:
                   6136:  * @str:  the XPath expression
                   6137:  * @ctxt:  the XPath context
                   6138:  *
                   6139:  * Create a new xmlXPathParserContext
                   6140:  *
                   6141:  * Returns the xmlXPathParserContext just allocated.
                   6142:  */
                   6143: xmlXPathParserContextPtr
                   6144: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
                   6145:     xmlXPathParserContextPtr ret;
                   6146: 
                   6147:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
                   6148:     if (ret == NULL) {
                   6149:         xmlXPathErrMemory(ctxt, "creating parser context\n");
                   6150:        return(NULL);
                   6151:     }
                   6152:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
                   6153:     ret->cur = ret->base = str;
                   6154:     ret->context = ctxt;
                   6155: 
                   6156:     ret->comp = xmlXPathNewCompExpr();
                   6157:     if (ret->comp == NULL) {
                   6158:        xmlFree(ret->valueTab);
                   6159:        xmlFree(ret);
                   6160:        return(NULL);
                   6161:     }
                   6162:     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
                   6163:         ret->comp->dict = ctxt->dict;
                   6164:        xmlDictReference(ret->comp->dict);
                   6165:     }
                   6166: 
                   6167:     return(ret);
                   6168: }
                   6169: 
                   6170: /**
                   6171:  * xmlXPathCompParserContext:
                   6172:  * @comp:  the XPath compiled expression
                   6173:  * @ctxt:  the XPath context
                   6174:  *
                   6175:  * Create a new xmlXPathParserContext when processing a compiled expression
                   6176:  *
                   6177:  * Returns the xmlXPathParserContext just allocated.
                   6178:  */
                   6179: static xmlXPathParserContextPtr
                   6180: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
                   6181:     xmlXPathParserContextPtr ret;
                   6182: 
                   6183:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
                   6184:     if (ret == NULL) {
                   6185:         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
                   6186:        return(NULL);
                   6187:     }
                   6188:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
                   6189: 
                   6190:     /* Allocate the value stack */
                   6191:     ret->valueTab = (xmlXPathObjectPtr *)
                   6192:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
                   6193:     if (ret->valueTab == NULL) {
                   6194:        xmlFree(ret);
                   6195:        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
                   6196:        return(NULL);
                   6197:     }
                   6198:     ret->valueNr = 0;
                   6199:     ret->valueMax = 10;
                   6200:     ret->value = NULL;
1.1.1.2 ! misho    6201:     ret->valueFrame = 0;
1.1       misho    6202: 
                   6203:     ret->context = ctxt;
                   6204:     ret->comp = comp;
                   6205: 
                   6206:     return(ret);
                   6207: }
                   6208: 
                   6209: /**
                   6210:  * xmlXPathFreeParserContext:
                   6211:  * @ctxt:  the context to free
                   6212:  *
                   6213:  * Free up an xmlXPathParserContext
                   6214:  */
                   6215: void
                   6216: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
                   6217:     if (ctxt->valueTab != NULL) {
                   6218:         xmlFree(ctxt->valueTab);
                   6219:     }
                   6220:     if (ctxt->comp != NULL) {
                   6221: #ifdef XPATH_STREAMING
                   6222:        if (ctxt->comp->stream != NULL) {
                   6223:            xmlFreePatternList(ctxt->comp->stream);
                   6224:            ctxt->comp->stream = NULL;
                   6225:        }
                   6226: #endif
                   6227:        xmlXPathFreeCompExpr(ctxt->comp);
                   6228:     }
                   6229:     xmlFree(ctxt);
                   6230: }
                   6231: 
                   6232: /************************************************************************
                   6233:  *                                                                     *
                   6234:  *             The implicit core function library                      *
                   6235:  *                                                                     *
                   6236:  ************************************************************************/
                   6237: 
                   6238: /**
                   6239:  * xmlXPathNodeValHash:
                   6240:  * @node:  a node pointer
                   6241:  *
                   6242:  * Function computing the beginning of the string value of the node,
                   6243:  * used to speed up comparisons
                   6244:  *
                   6245:  * Returns an int usable as a hash
                   6246:  */
                   6247: static unsigned int
                   6248: xmlXPathNodeValHash(xmlNodePtr node) {
                   6249:     int len = 2;
                   6250:     const xmlChar * string = NULL;
                   6251:     xmlNodePtr tmp = NULL;
                   6252:     unsigned int ret = 0;
                   6253: 
                   6254:     if (node == NULL)
                   6255:        return(0);
                   6256: 
                   6257:     if (node->type == XML_DOCUMENT_NODE) {
                   6258:        tmp = xmlDocGetRootElement((xmlDocPtr) node);
                   6259:        if (tmp == NULL)
                   6260:            node = node->children;
                   6261:        else
                   6262:            node = tmp;
                   6263: 
                   6264:        if (node == NULL)
                   6265:            return(0);
                   6266:     }
                   6267: 
                   6268:     switch (node->type) {
                   6269:        case XML_COMMENT_NODE:
                   6270:        case XML_PI_NODE:
                   6271:        case XML_CDATA_SECTION_NODE:
                   6272:        case XML_TEXT_NODE:
                   6273:            string = node->content;
                   6274:            if (string == NULL)
                   6275:                return(0);
                   6276:            if (string[0] == 0)
                   6277:                return(0);
                   6278:            return(((unsigned int) string[0]) +
                   6279:                   (((unsigned int) string[1]) << 8));
                   6280:        case XML_NAMESPACE_DECL:
                   6281:            string = ((xmlNsPtr)node)->href;
                   6282:            if (string == NULL)
                   6283:                return(0);
                   6284:            if (string[0] == 0)
                   6285:                return(0);
                   6286:            return(((unsigned int) string[0]) +
                   6287:                   (((unsigned int) string[1]) << 8));
                   6288:        case XML_ATTRIBUTE_NODE:
                   6289:            tmp = ((xmlAttrPtr) node)->children;
                   6290:            break;
                   6291:        case XML_ELEMENT_NODE:
                   6292:            tmp = node->children;
                   6293:            break;
                   6294:        default:
                   6295:            return(0);
                   6296:     }
                   6297:     while (tmp != NULL) {
                   6298:        switch (tmp->type) {
                   6299:            case XML_COMMENT_NODE:
                   6300:            case XML_PI_NODE:
                   6301:            case XML_CDATA_SECTION_NODE:
                   6302:            case XML_TEXT_NODE:
                   6303:                string = tmp->content;
                   6304:                break;
                   6305:            case XML_NAMESPACE_DECL:
                   6306:                string = ((xmlNsPtr)tmp)->href;
                   6307:                break;
                   6308:            default:
                   6309:                break;
                   6310:        }
                   6311:        if ((string != NULL) && (string[0] != 0)) {
                   6312:            if (len == 1) {
                   6313:                return(ret + (((unsigned int) string[0]) << 8));
                   6314:            }
                   6315:            if (string[1] == 0) {
                   6316:                len = 1;
                   6317:                ret = (unsigned int) string[0];
                   6318:            } else {
                   6319:                return(((unsigned int) string[0]) +
                   6320:                       (((unsigned int) string[1]) << 8));
                   6321:            }
                   6322:        }
                   6323:        /*
                   6324:         * Skip to next node
                   6325:         */
                   6326:        if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
                   6327:            if (tmp->children->type != XML_ENTITY_DECL) {
                   6328:                tmp = tmp->children;
                   6329:                continue;
                   6330:            }
                   6331:        }
                   6332:        if (tmp == node)
                   6333:            break;
                   6334: 
                   6335:        if (tmp->next != NULL) {
                   6336:            tmp = tmp->next;
                   6337:            continue;
                   6338:        }
                   6339: 
                   6340:        do {
                   6341:            tmp = tmp->parent;
                   6342:            if (tmp == NULL)
                   6343:                break;
                   6344:            if (tmp == node) {
                   6345:                tmp = NULL;
                   6346:                break;
                   6347:            }
                   6348:            if (tmp->next != NULL) {
                   6349:                tmp = tmp->next;
                   6350:                break;
                   6351:            }
                   6352:        } while (tmp != NULL);
                   6353:     }
                   6354:     return(ret);
                   6355: }
                   6356: 
                   6357: /**
                   6358:  * xmlXPathStringHash:
                   6359:  * @string:  a string
                   6360:  *
                   6361:  * Function computing the beginning of the string value of the node,
                   6362:  * used to speed up comparisons
                   6363:  *
                   6364:  * Returns an int usable as a hash
                   6365:  */
                   6366: static unsigned int
                   6367: xmlXPathStringHash(const xmlChar * string) {
                   6368:     if (string == NULL)
                   6369:        return((unsigned int) 0);
                   6370:     if (string[0] == 0)
                   6371:        return(0);
                   6372:     return(((unsigned int) string[0]) +
                   6373:           (((unsigned int) string[1]) << 8));
                   6374: }
                   6375: 
                   6376: /**
                   6377:  * xmlXPathCompareNodeSetFloat:
                   6378:  * @ctxt:  the XPath Parser context
                   6379:  * @inf:  less than (1) or greater than (0)
                   6380:  * @strict:  is the comparison strict
                   6381:  * @arg:  the node set
                   6382:  * @f:  the value
                   6383:  *
                   6384:  * Implement the compare operation between a nodeset and a number
                   6385:  *     @ns < @val    (1, 1, ...
                   6386:  *     @ns <= @val   (1, 0, ...
                   6387:  *     @ns > @val    (0, 1, ...
                   6388:  *     @ns >= @val   (0, 0, ...
                   6389:  *
                   6390:  * If one object to be compared is a node-set and the other is a number,
                   6391:  * then the comparison will be true if and only if there is a node in the
                   6392:  * node-set such that the result of performing the comparison on the number
                   6393:  * to be compared and on the result of converting the string-value of that
                   6394:  * node to a number using the number function is true.
                   6395:  *
                   6396:  * Returns 0 or 1 depending on the results of the test.
                   6397:  */
                   6398: static int
                   6399: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
                   6400:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
                   6401:     int i, ret = 0;
                   6402:     xmlNodeSetPtr ns;
                   6403:     xmlChar *str2;
                   6404: 
                   6405:     if ((f == NULL) || (arg == NULL) ||
                   6406:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
                   6407:        xmlXPathReleaseObject(ctxt->context, arg);
                   6408:        xmlXPathReleaseObject(ctxt->context, f);
                   6409:         return(0);
                   6410:     }
                   6411:     ns = arg->nodesetval;
                   6412:     if (ns != NULL) {
                   6413:        for (i = 0;i < ns->nodeNr;i++) {
                   6414:             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
                   6415:             if (str2 != NULL) {
                   6416:                 valuePush(ctxt,
                   6417:                           xmlXPathCacheNewString(ctxt->context, str2));
                   6418:                 xmlFree(str2);
                   6419:                 xmlXPathNumberFunction(ctxt, 1);
                   6420:                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
                   6421:                 ret = xmlXPathCompareValues(ctxt, inf, strict);
                   6422:                 if (ret)
                   6423:                     break;
                   6424:             }
                   6425:        }
                   6426:     }
                   6427:     xmlXPathReleaseObject(ctxt->context, arg);
                   6428:     xmlXPathReleaseObject(ctxt->context, f);
                   6429:     return(ret);
                   6430: }
                   6431: 
                   6432: /**
                   6433:  * xmlXPathCompareNodeSetString:
                   6434:  * @ctxt:  the XPath Parser context
                   6435:  * @inf:  less than (1) or greater than (0)
                   6436:  * @strict:  is the comparison strict
                   6437:  * @arg:  the node set
                   6438:  * @s:  the value
                   6439:  *
                   6440:  * Implement the compare operation between a nodeset and a string
                   6441:  *     @ns < @val    (1, 1, ...
                   6442:  *     @ns <= @val   (1, 0, ...
                   6443:  *     @ns > @val    (0, 1, ...
                   6444:  *     @ns >= @val   (0, 0, ...
                   6445:  *
                   6446:  * If one object to be compared is a node-set and the other is a string,
                   6447:  * then the comparison will be true if and only if there is a node in
                   6448:  * the node-set such that the result of performing the comparison on the
                   6449:  * string-value of the node and the other string is true.
                   6450:  *
                   6451:  * Returns 0 or 1 depending on the results of the test.
                   6452:  */
                   6453: static int
                   6454: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
                   6455:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
                   6456:     int i, ret = 0;
                   6457:     xmlNodeSetPtr ns;
                   6458:     xmlChar *str2;
                   6459: 
                   6460:     if ((s == NULL) || (arg == NULL) ||
                   6461:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
                   6462:        xmlXPathReleaseObject(ctxt->context, arg);
                   6463:        xmlXPathReleaseObject(ctxt->context, s);
                   6464:         return(0);
                   6465:     }
                   6466:     ns = arg->nodesetval;
                   6467:     if (ns != NULL) {
                   6468:        for (i = 0;i < ns->nodeNr;i++) {
                   6469:             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
                   6470:             if (str2 != NULL) {
                   6471:                 valuePush(ctxt,
                   6472:                           xmlXPathCacheNewString(ctxt->context, str2));
                   6473:                 xmlFree(str2);
                   6474:                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
                   6475:                 ret = xmlXPathCompareValues(ctxt, inf, strict);
                   6476:                 if (ret)
                   6477:                     break;
                   6478:             }
                   6479:        }
                   6480:     }
                   6481:     xmlXPathReleaseObject(ctxt->context, arg);
                   6482:     xmlXPathReleaseObject(ctxt->context, s);
                   6483:     return(ret);
                   6484: }
                   6485: 
                   6486: /**
                   6487:  * xmlXPathCompareNodeSets:
                   6488:  * @inf:  less than (1) or greater than (0)
                   6489:  * @strict:  is the comparison strict
                   6490:  * @arg1:  the first node set object
                   6491:  * @arg2:  the second node set object
                   6492:  *
                   6493:  * Implement the compare operation on nodesets:
                   6494:  *
                   6495:  * If both objects to be compared are node-sets, then the comparison
                   6496:  * will be true if and only if there is a node in the first node-set
                   6497:  * and a node in the second node-set such that the result of performing
                   6498:  * the comparison on the string-values of the two nodes is true.
                   6499:  * ....
                   6500:  * When neither object to be compared is a node-set and the operator
                   6501:  * is <=, <, >= or >, then the objects are compared by converting both
                   6502:  * objects to numbers and comparing the numbers according to IEEE 754.
                   6503:  * ....
                   6504:  * The number function converts its argument to a number as follows:
                   6505:  *  - a string that consists of optional whitespace followed by an
                   6506:  *    optional minus sign followed by a Number followed by whitespace
                   6507:  *    is converted to the IEEE 754 number that is nearest (according
                   6508:  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
                   6509:  *    represented by the string; any other string is converted to NaN
                   6510:  *
                   6511:  * Conclusion all nodes need to be converted first to their string value
                   6512:  * and then the comparison must be done when possible
                   6513:  */
                   6514: static int
                   6515: xmlXPathCompareNodeSets(int inf, int strict,
                   6516:                        xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
                   6517:     int i, j, init = 0;
                   6518:     double val1;
                   6519:     double *values2;
                   6520:     int ret = 0;
                   6521:     xmlNodeSetPtr ns1;
                   6522:     xmlNodeSetPtr ns2;
                   6523: 
                   6524:     if ((arg1 == NULL) ||
                   6525:        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
                   6526:        xmlXPathFreeObject(arg2);
                   6527:         return(0);
                   6528:     }
                   6529:     if ((arg2 == NULL) ||
                   6530:        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
                   6531:        xmlXPathFreeObject(arg1);
                   6532:        xmlXPathFreeObject(arg2);
                   6533:         return(0);
                   6534:     }
                   6535: 
                   6536:     ns1 = arg1->nodesetval;
                   6537:     ns2 = arg2->nodesetval;
                   6538: 
                   6539:     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
                   6540:        xmlXPathFreeObject(arg1);
                   6541:        xmlXPathFreeObject(arg2);
                   6542:        return(0);
                   6543:     }
                   6544:     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
                   6545:        xmlXPathFreeObject(arg1);
                   6546:        xmlXPathFreeObject(arg2);
                   6547:        return(0);
                   6548:     }
                   6549: 
                   6550:     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
                   6551:     if (values2 == NULL) {
                   6552:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6553:        xmlXPathFreeObject(arg1);
                   6554:        xmlXPathFreeObject(arg2);
                   6555:        return(0);
                   6556:     }
                   6557:     for (i = 0;i < ns1->nodeNr;i++) {
                   6558:        val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
                   6559:        if (xmlXPathIsNaN(val1))
                   6560:            continue;
                   6561:        for (j = 0;j < ns2->nodeNr;j++) {
                   6562:            if (init == 0) {
                   6563:                values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
                   6564:            }
                   6565:            if (xmlXPathIsNaN(values2[j]))
                   6566:                continue;
                   6567:            if (inf && strict)
                   6568:                ret = (val1 < values2[j]);
                   6569:            else if (inf && !strict)
                   6570:                ret = (val1 <= values2[j]);
                   6571:            else if (!inf && strict)
                   6572:                ret = (val1 > values2[j]);
                   6573:            else if (!inf && !strict)
                   6574:                ret = (val1 >= values2[j]);
                   6575:            if (ret)
                   6576:                break;
                   6577:        }
                   6578:        if (ret)
                   6579:            break;
                   6580:        init = 1;
                   6581:     }
                   6582:     xmlFree(values2);
                   6583:     xmlXPathFreeObject(arg1);
                   6584:     xmlXPathFreeObject(arg2);
                   6585:     return(ret);
                   6586: }
                   6587: 
                   6588: /**
                   6589:  * xmlXPathCompareNodeSetValue:
                   6590:  * @ctxt:  the XPath Parser context
                   6591:  * @inf:  less than (1) or greater than (0)
                   6592:  * @strict:  is the comparison strict
                   6593:  * @arg:  the node set
                   6594:  * @val:  the value
                   6595:  *
                   6596:  * Implement the compare operation between a nodeset and a value
                   6597:  *     @ns < @val    (1, 1, ...
                   6598:  *     @ns <= @val   (1, 0, ...
                   6599:  *     @ns > @val    (0, 1, ...
                   6600:  *     @ns >= @val   (0, 0, ...
                   6601:  *
                   6602:  * If one object to be compared is a node-set and the other is a boolean,
                   6603:  * then the comparison will be true if and only if the result of performing
                   6604:  * the comparison on the boolean and on the result of converting
                   6605:  * the node-set to a boolean using the boolean function is true.
                   6606:  *
                   6607:  * Returns 0 or 1 depending on the results of the test.
                   6608:  */
                   6609: static int
                   6610: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
                   6611:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
                   6612:     if ((val == NULL) || (arg == NULL) ||
                   6613:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
                   6614:         return(0);
                   6615: 
                   6616:     switch(val->type) {
                   6617:         case XPATH_NUMBER:
                   6618:            return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
                   6619:         case XPATH_NODESET:
                   6620:         case XPATH_XSLT_TREE:
                   6621:            return(xmlXPathCompareNodeSets(inf, strict, arg, val));
                   6622:         case XPATH_STRING:
                   6623:            return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
                   6624:         case XPATH_BOOLEAN:
                   6625:            valuePush(ctxt, arg);
                   6626:            xmlXPathBooleanFunction(ctxt, 1);
                   6627:            valuePush(ctxt, val);
                   6628:            return(xmlXPathCompareValues(ctxt, inf, strict));
                   6629:        default:
                   6630:            TODO
                   6631:     }
                   6632:     return(0);
                   6633: }
                   6634: 
                   6635: /**
                   6636:  * xmlXPathEqualNodeSetString:
                   6637:  * @arg:  the nodeset object argument
                   6638:  * @str:  the string to compare to.
                   6639:  * @neq:  flag to show whether for '=' (0) or '!=' (1)
                   6640:  *
                   6641:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   6642:  * If one object to be compared is a node-set and the other is a string,
                   6643:  * then the comparison will be true if and only if there is a node in
                   6644:  * the node-set such that the result of performing the comparison on the
                   6645:  * string-value of the node and the other string is true.
                   6646:  *
                   6647:  * Returns 0 or 1 depending on the results of the test.
                   6648:  */
                   6649: static int
                   6650: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
                   6651: {
                   6652:     int i;
                   6653:     xmlNodeSetPtr ns;
                   6654:     xmlChar *str2;
                   6655:     unsigned int hash;
                   6656: 
                   6657:     if ((str == NULL) || (arg == NULL) ||
                   6658:         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
                   6659:         return (0);
                   6660:     ns = arg->nodesetval;
                   6661:     /*
                   6662:      * A NULL nodeset compared with a string is always false
                   6663:      * (since there is no node equal, and no node not equal)
                   6664:      */
                   6665:     if ((ns == NULL) || (ns->nodeNr <= 0) )
                   6666:         return (0);
                   6667:     hash = xmlXPathStringHash(str);
                   6668:     for (i = 0; i < ns->nodeNr; i++) {
                   6669:         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
                   6670:             str2 = xmlNodeGetContent(ns->nodeTab[i]);
                   6671:             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
                   6672:                 xmlFree(str2);
                   6673:                if (neq)
                   6674:                    continue;
                   6675:                 return (1);
                   6676:            } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
                   6677:                if (neq)
                   6678:                    continue;
                   6679:                 return (1);
                   6680:             } else if (neq) {
                   6681:                if (str2 != NULL)
                   6682:                    xmlFree(str2);
                   6683:                return (1);
                   6684:            }
                   6685:             if (str2 != NULL)
                   6686:                 xmlFree(str2);
                   6687:         } else if (neq)
                   6688:            return (1);
                   6689:     }
                   6690:     return (0);
                   6691: }
                   6692: 
                   6693: /**
                   6694:  * xmlXPathEqualNodeSetFloat:
                   6695:  * @arg:  the nodeset object argument
                   6696:  * @f:  the float to compare to
                   6697:  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
                   6698:  *
                   6699:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   6700:  * If one object to be compared is a node-set and the other is a number,
                   6701:  * then the comparison will be true if and only if there is a node in
                   6702:  * the node-set such that the result of performing the comparison on the
                   6703:  * number to be compared and on the result of converting the string-value
                   6704:  * of that node to a number using the number function is true.
                   6705:  *
                   6706:  * Returns 0 or 1 depending on the results of the test.
                   6707:  */
                   6708: static int
                   6709: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
                   6710:     xmlXPathObjectPtr arg, double f, int neq) {
                   6711:   int i, ret=0;
                   6712:   xmlNodeSetPtr ns;
                   6713:   xmlChar *str2;
                   6714:   xmlXPathObjectPtr val;
                   6715:   double v;
                   6716: 
                   6717:     if ((arg == NULL) ||
                   6718:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
                   6719:         return(0);
                   6720: 
                   6721:     ns = arg->nodesetval;
                   6722:     if (ns != NULL) {
                   6723:        for (i=0;i<ns->nodeNr;i++) {
                   6724:            str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
                   6725:            if (str2 != NULL) {
                   6726:                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
                   6727:                xmlFree(str2);
                   6728:                xmlXPathNumberFunction(ctxt, 1);
                   6729:                val = valuePop(ctxt);
                   6730:                v = val->floatval;
                   6731:                xmlXPathReleaseObject(ctxt->context, val);
                   6732:                if (!xmlXPathIsNaN(v)) {
                   6733:                    if ((!neq) && (v==f)) {
                   6734:                        ret = 1;
                   6735:                        break;
                   6736:                    } else if ((neq) && (v!=f)) {
                   6737:                        ret = 1;
                   6738:                        break;
                   6739:                    }
                   6740:                } else {        /* NaN is unequal to any value */
                   6741:                    if (neq)
                   6742:                        ret = 1;
                   6743:                }
                   6744:            }
                   6745:        }
                   6746:     }
                   6747: 
                   6748:     return(ret);
                   6749: }
                   6750: 
                   6751: 
                   6752: /**
                   6753:  * xmlXPathEqualNodeSets:
                   6754:  * @arg1:  first nodeset object argument
                   6755:  * @arg2:  second nodeset object argument
                   6756:  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
                   6757:  *
                   6758:  * Implement the equal / not equal operation on XPath nodesets:
                   6759:  * @arg1 == @arg2  or  @arg1 != @arg2
                   6760:  * If both objects to be compared are node-sets, then the comparison
                   6761:  * will be true if and only if there is a node in the first node-set and
                   6762:  * a node in the second node-set such that the result of performing the
                   6763:  * comparison on the string-values of the two nodes is true.
                   6764:  *
                   6765:  * (needless to say, this is a costly operation)
                   6766:  *
                   6767:  * Returns 0 or 1 depending on the results of the test.
                   6768:  */
                   6769: static int
                   6770: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
                   6771:     int i, j;
                   6772:     unsigned int *hashs1;
                   6773:     unsigned int *hashs2;
                   6774:     xmlChar **values1;
                   6775:     xmlChar **values2;
                   6776:     int ret = 0;
                   6777:     xmlNodeSetPtr ns1;
                   6778:     xmlNodeSetPtr ns2;
                   6779: 
                   6780:     if ((arg1 == NULL) ||
                   6781:        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
                   6782:         return(0);
                   6783:     if ((arg2 == NULL) ||
                   6784:        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
                   6785:         return(0);
                   6786: 
                   6787:     ns1 = arg1->nodesetval;
                   6788:     ns2 = arg2->nodesetval;
                   6789: 
                   6790:     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
                   6791:        return(0);
                   6792:     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
                   6793:        return(0);
                   6794: 
                   6795:     /*
                   6796:      * for equal, check if there is a node pertaining to both sets
                   6797:      */
                   6798:     if (neq == 0)
                   6799:        for (i = 0;i < ns1->nodeNr;i++)
                   6800:            for (j = 0;j < ns2->nodeNr;j++)
                   6801:                if (ns1->nodeTab[i] == ns2->nodeTab[j])
                   6802:                    return(1);
                   6803: 
                   6804:     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
                   6805:     if (values1 == NULL) {
                   6806:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6807:        return(0);
                   6808:     }
                   6809:     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
                   6810:     if (hashs1 == NULL) {
                   6811:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6812:        xmlFree(values1);
                   6813:        return(0);
                   6814:     }
                   6815:     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
                   6816:     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
                   6817:     if (values2 == NULL) {
                   6818:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6819:        xmlFree(hashs1);
                   6820:        xmlFree(values1);
                   6821:        return(0);
                   6822:     }
                   6823:     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
                   6824:     if (hashs2 == NULL) {
                   6825:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6826:        xmlFree(hashs1);
                   6827:        xmlFree(values1);
                   6828:        xmlFree(values2);
                   6829:        return(0);
                   6830:     }
                   6831:     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
                   6832:     for (i = 0;i < ns1->nodeNr;i++) {
                   6833:        hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
                   6834:        for (j = 0;j < ns2->nodeNr;j++) {
                   6835:            if (i == 0)
                   6836:                hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
                   6837:            if (hashs1[i] != hashs2[j]) {
                   6838:                if (neq) {
                   6839:                    ret = 1;
                   6840:                    break;
                   6841:                }
                   6842:            }
                   6843:            else {
                   6844:                if (values1[i] == NULL)
                   6845:                    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
                   6846:                if (values2[j] == NULL)
                   6847:                    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
                   6848:                ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
                   6849:                if (ret)
                   6850:                    break;
                   6851:            }
                   6852:        }
                   6853:        if (ret)
                   6854:            break;
                   6855:     }
                   6856:     for (i = 0;i < ns1->nodeNr;i++)
                   6857:        if (values1[i] != NULL)
                   6858:            xmlFree(values1[i]);
                   6859:     for (j = 0;j < ns2->nodeNr;j++)
                   6860:        if (values2[j] != NULL)
                   6861:            xmlFree(values2[j]);
                   6862:     xmlFree(values1);
                   6863:     xmlFree(values2);
                   6864:     xmlFree(hashs1);
                   6865:     xmlFree(hashs2);
                   6866:     return(ret);
                   6867: }
                   6868: 
                   6869: static int
                   6870: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
                   6871:   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
                   6872:     int ret = 0;
                   6873:     /*
                   6874:      *At this point we are assured neither arg1 nor arg2
                   6875:      *is a nodeset, so we can just pick the appropriate routine.
                   6876:      */
                   6877:     switch (arg1->type) {
                   6878:         case XPATH_UNDEFINED:
                   6879: #ifdef DEBUG_EXPR
                   6880:            xmlGenericError(xmlGenericErrorContext,
                   6881:                    "Equal: undefined\n");
                   6882: #endif
                   6883:            break;
                   6884:         case XPATH_BOOLEAN:
                   6885:            switch (arg2->type) {
                   6886:                case XPATH_UNDEFINED:
                   6887: #ifdef DEBUG_EXPR
                   6888:                    xmlGenericError(xmlGenericErrorContext,
                   6889:                            "Equal: undefined\n");
                   6890: #endif
                   6891:                    break;
                   6892:                case XPATH_BOOLEAN:
                   6893: #ifdef DEBUG_EXPR
                   6894:                    xmlGenericError(xmlGenericErrorContext,
                   6895:                            "Equal: %d boolean %d \n",
                   6896:                            arg1->boolval, arg2->boolval);
                   6897: #endif
                   6898:                    ret = (arg1->boolval == arg2->boolval);
                   6899:                    break;
                   6900:                case XPATH_NUMBER:
                   6901:                    ret = (arg1->boolval ==
                   6902:                           xmlXPathCastNumberToBoolean(arg2->floatval));
                   6903:                    break;
                   6904:                case XPATH_STRING:
                   6905:                    if ((arg2->stringval == NULL) ||
                   6906:                        (arg2->stringval[0] == 0)) ret = 0;
                   6907:                    else
                   6908:                        ret = 1;
                   6909:                    ret = (arg1->boolval == ret);
                   6910:                    break;
                   6911:                case XPATH_USERS:
                   6912:                case XPATH_POINT:
                   6913:                case XPATH_RANGE:
                   6914:                case XPATH_LOCATIONSET:
                   6915:                    TODO
                   6916:                    break;
                   6917:                case XPATH_NODESET:
                   6918:                case XPATH_XSLT_TREE:
                   6919:                    break;
                   6920:            }
                   6921:            break;
                   6922:         case XPATH_NUMBER:
                   6923:            switch (arg2->type) {
                   6924:                case XPATH_UNDEFINED:
                   6925: #ifdef DEBUG_EXPR
                   6926:                    xmlGenericError(xmlGenericErrorContext,
                   6927:                            "Equal: undefined\n");
                   6928: #endif
                   6929:                    break;
                   6930:                case XPATH_BOOLEAN:
                   6931:                    ret = (arg2->boolval==
                   6932:                           xmlXPathCastNumberToBoolean(arg1->floatval));
                   6933:                    break;
                   6934:                case XPATH_STRING:
                   6935:                    valuePush(ctxt, arg2);
                   6936:                    xmlXPathNumberFunction(ctxt, 1);
                   6937:                    arg2 = valuePop(ctxt);
                   6938:                    /* no break on purpose */
                   6939:                case XPATH_NUMBER:
                   6940:                    /* Hand check NaN and Infinity equalities */
                   6941:                    if (xmlXPathIsNaN(arg1->floatval) ||
                   6942:                            xmlXPathIsNaN(arg2->floatval)) {
                   6943:                        ret = 0;
                   6944:                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
                   6945:                        if (xmlXPathIsInf(arg2->floatval) == 1)
                   6946:                            ret = 1;
                   6947:                        else
                   6948:                            ret = 0;
                   6949:                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
                   6950:                        if (xmlXPathIsInf(arg2->floatval) == -1)
                   6951:                            ret = 1;
                   6952:                        else
                   6953:                            ret = 0;
                   6954:                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
                   6955:                        if (xmlXPathIsInf(arg1->floatval) == 1)
                   6956:                            ret = 1;
                   6957:                        else
                   6958:                            ret = 0;
                   6959:                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
                   6960:                        if (xmlXPathIsInf(arg1->floatval) == -1)
                   6961:                            ret = 1;
                   6962:                        else
                   6963:                            ret = 0;
                   6964:                    } else {
                   6965:                        ret = (arg1->floatval == arg2->floatval);
                   6966:                    }
                   6967:                    break;
                   6968:                case XPATH_USERS:
                   6969:                case XPATH_POINT:
                   6970:                case XPATH_RANGE:
                   6971:                case XPATH_LOCATIONSET:
                   6972:                    TODO
                   6973:                    break;
                   6974:                case XPATH_NODESET:
                   6975:                case XPATH_XSLT_TREE:
                   6976:                    break;
                   6977:            }
                   6978:            break;
                   6979:         case XPATH_STRING:
                   6980:            switch (arg2->type) {
                   6981:                case XPATH_UNDEFINED:
                   6982: #ifdef DEBUG_EXPR
                   6983:                    xmlGenericError(xmlGenericErrorContext,
                   6984:                            "Equal: undefined\n");
                   6985: #endif
                   6986:                    break;
                   6987:                case XPATH_BOOLEAN:
                   6988:                    if ((arg1->stringval == NULL) ||
                   6989:                        (arg1->stringval[0] == 0)) ret = 0;
                   6990:                    else
                   6991:                        ret = 1;
                   6992:                    ret = (arg2->boolval == ret);
                   6993:                    break;
                   6994:                case XPATH_STRING:
                   6995:                    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
                   6996:                    break;
                   6997:                case XPATH_NUMBER:
                   6998:                    valuePush(ctxt, arg1);
                   6999:                    xmlXPathNumberFunction(ctxt, 1);
                   7000:                    arg1 = valuePop(ctxt);
                   7001:                    /* Hand check NaN and Infinity equalities */
                   7002:                    if (xmlXPathIsNaN(arg1->floatval) ||
                   7003:                            xmlXPathIsNaN(arg2->floatval)) {
                   7004:                        ret = 0;
                   7005:                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
                   7006:                        if (xmlXPathIsInf(arg2->floatval) == 1)
                   7007:                            ret = 1;
                   7008:                        else
                   7009:                            ret = 0;
                   7010:                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
                   7011:                        if (xmlXPathIsInf(arg2->floatval) == -1)
                   7012:                            ret = 1;
                   7013:                        else
                   7014:                            ret = 0;
                   7015:                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
                   7016:                        if (xmlXPathIsInf(arg1->floatval) == 1)
                   7017:                            ret = 1;
                   7018:                        else
                   7019:                            ret = 0;
                   7020:                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
                   7021:                        if (xmlXPathIsInf(arg1->floatval) == -1)
                   7022:                            ret = 1;
                   7023:                        else
                   7024:                            ret = 0;
                   7025:                    } else {
                   7026:                        ret = (arg1->floatval == arg2->floatval);
                   7027:                    }
                   7028:                    break;
                   7029:                case XPATH_USERS:
                   7030:                case XPATH_POINT:
                   7031:                case XPATH_RANGE:
                   7032:                case XPATH_LOCATIONSET:
                   7033:                    TODO
                   7034:                    break;
                   7035:                case XPATH_NODESET:
                   7036:                case XPATH_XSLT_TREE:
                   7037:                    break;
                   7038:            }
                   7039:            break;
                   7040:         case XPATH_USERS:
                   7041:        case XPATH_POINT:
                   7042:        case XPATH_RANGE:
                   7043:        case XPATH_LOCATIONSET:
                   7044:            TODO
                   7045:            break;
                   7046:        case XPATH_NODESET:
                   7047:        case XPATH_XSLT_TREE:
                   7048:            break;
                   7049:     }
                   7050:     xmlXPathReleaseObject(ctxt->context, arg1);
                   7051:     xmlXPathReleaseObject(ctxt->context, arg2);
                   7052:     return(ret);
                   7053: }
                   7054: 
                   7055: /**
                   7056:  * xmlXPathEqualValues:
                   7057:  * @ctxt:  the XPath Parser context
                   7058:  *
                   7059:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   7060:  *
                   7061:  * Returns 0 or 1 depending on the results of the test.
                   7062:  */
                   7063: int
                   7064: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
                   7065:     xmlXPathObjectPtr arg1, arg2, argtmp;
                   7066:     int ret = 0;
                   7067: 
                   7068:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
                   7069:     arg2 = valuePop(ctxt);
                   7070:     arg1 = valuePop(ctxt);
                   7071:     if ((arg1 == NULL) || (arg2 == NULL)) {
                   7072:        if (arg1 != NULL)
                   7073:            xmlXPathReleaseObject(ctxt->context, arg1);
                   7074:        else
                   7075:            xmlXPathReleaseObject(ctxt->context, arg2);
                   7076:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7077:     }
                   7078: 
                   7079:     if (arg1 == arg2) {
                   7080: #ifdef DEBUG_EXPR
                   7081:         xmlGenericError(xmlGenericErrorContext,
                   7082:                "Equal: by pointer\n");
                   7083: #endif
                   7084:        xmlXPathFreeObject(arg1);
                   7085:         return(1);
                   7086:     }
                   7087: 
                   7088:     /*
                   7089:      *If either argument is a nodeset, it's a 'special case'
                   7090:      */
                   7091:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
                   7092:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7093:        /*
                   7094:         *Hack it to assure arg1 is the nodeset
                   7095:         */
                   7096:        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
                   7097:                argtmp = arg2;
                   7098:                arg2 = arg1;
                   7099:                arg1 = argtmp;
                   7100:        }
                   7101:        switch (arg2->type) {
                   7102:            case XPATH_UNDEFINED:
                   7103: #ifdef DEBUG_EXPR
                   7104:                xmlGenericError(xmlGenericErrorContext,
                   7105:                        "Equal: undefined\n");
                   7106: #endif
                   7107:                break;
                   7108:            case XPATH_NODESET:
                   7109:            case XPATH_XSLT_TREE:
                   7110:                ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
                   7111:                break;
                   7112:            case XPATH_BOOLEAN:
                   7113:                if ((arg1->nodesetval == NULL) ||
                   7114:                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
                   7115:                else
                   7116:                    ret = 1;
                   7117:                ret = (ret == arg2->boolval);
                   7118:                break;
                   7119:            case XPATH_NUMBER:
                   7120:                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
                   7121:                break;
                   7122:            case XPATH_STRING:
                   7123:                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
                   7124:                break;
                   7125:            case XPATH_USERS:
                   7126:            case XPATH_POINT:
                   7127:            case XPATH_RANGE:
                   7128:            case XPATH_LOCATIONSET:
                   7129:                TODO
                   7130:                break;
                   7131:        }
                   7132:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7133:        xmlXPathReleaseObject(ctxt->context, arg2);
                   7134:        return(ret);
                   7135:     }
                   7136: 
                   7137:     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
                   7138: }
                   7139: 
                   7140: /**
                   7141:  * xmlXPathNotEqualValues:
                   7142:  * @ctxt:  the XPath Parser context
                   7143:  *
                   7144:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   7145:  *
                   7146:  * Returns 0 or 1 depending on the results of the test.
                   7147:  */
                   7148: int
                   7149: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
                   7150:     xmlXPathObjectPtr arg1, arg2, argtmp;
                   7151:     int ret = 0;
                   7152: 
                   7153:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
                   7154:     arg2 = valuePop(ctxt);
                   7155:     arg1 = valuePop(ctxt);
                   7156:     if ((arg1 == NULL) || (arg2 == NULL)) {
                   7157:        if (arg1 != NULL)
                   7158:            xmlXPathReleaseObject(ctxt->context, arg1);
                   7159:        else
                   7160:            xmlXPathReleaseObject(ctxt->context, arg2);
                   7161:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7162:     }
                   7163: 
                   7164:     if (arg1 == arg2) {
                   7165: #ifdef DEBUG_EXPR
                   7166:         xmlGenericError(xmlGenericErrorContext,
                   7167:                "NotEqual: by pointer\n");
                   7168: #endif
                   7169:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7170:         return(0);
                   7171:     }
                   7172: 
                   7173:     /*
                   7174:      *If either argument is a nodeset, it's a 'special case'
                   7175:      */
                   7176:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
                   7177:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7178:        /*
                   7179:         *Hack it to assure arg1 is the nodeset
                   7180:         */
                   7181:        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
                   7182:                argtmp = arg2;
                   7183:                arg2 = arg1;
                   7184:                arg1 = argtmp;
                   7185:        }
                   7186:        switch (arg2->type) {
                   7187:            case XPATH_UNDEFINED:
                   7188: #ifdef DEBUG_EXPR
                   7189:                xmlGenericError(xmlGenericErrorContext,
                   7190:                        "NotEqual: undefined\n");
                   7191: #endif
                   7192:                break;
                   7193:            case XPATH_NODESET:
                   7194:            case XPATH_XSLT_TREE:
                   7195:                ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
                   7196:                break;
                   7197:            case XPATH_BOOLEAN:
                   7198:                if ((arg1->nodesetval == NULL) ||
                   7199:                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
                   7200:                else
                   7201:                    ret = 1;
                   7202:                ret = (ret != arg2->boolval);
                   7203:                break;
                   7204:            case XPATH_NUMBER:
                   7205:                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
                   7206:                break;
                   7207:            case XPATH_STRING:
                   7208:                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
                   7209:                break;
                   7210:            case XPATH_USERS:
                   7211:            case XPATH_POINT:
                   7212:            case XPATH_RANGE:
                   7213:            case XPATH_LOCATIONSET:
                   7214:                TODO
                   7215:                break;
                   7216:        }
                   7217:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7218:        xmlXPathReleaseObject(ctxt->context, arg2);
                   7219:        return(ret);
                   7220:     }
                   7221: 
                   7222:     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
                   7223: }
                   7224: 
                   7225: /**
                   7226:  * xmlXPathCompareValues:
                   7227:  * @ctxt:  the XPath Parser context
                   7228:  * @inf:  less than (1) or greater than (0)
                   7229:  * @strict:  is the comparison strict
                   7230:  *
                   7231:  * Implement the compare operation on XPath objects:
                   7232:  *     @arg1 < @arg2    (1, 1, ...
                   7233:  *     @arg1 <= @arg2   (1, 0, ...
                   7234:  *     @arg1 > @arg2    (0, 1, ...
                   7235:  *     @arg1 >= @arg2   (0, 0, ...
                   7236:  *
                   7237:  * When neither object to be compared is a node-set and the operator is
                   7238:  * <=, <, >=, >, then the objects are compared by converted both objects
                   7239:  * to numbers and comparing the numbers according to IEEE 754. The <
                   7240:  * comparison will be true if and only if the first number is less than the
                   7241:  * second number. The <= comparison will be true if and only if the first
                   7242:  * number is less than or equal to the second number. The > comparison
                   7243:  * will be true if and only if the first number is greater than the second
                   7244:  * number. The >= comparison will be true if and only if the first number
                   7245:  * is greater than or equal to the second number.
                   7246:  *
                   7247:  * Returns 1 if the comparison succeeded, 0 if it failed
                   7248:  */
                   7249: int
                   7250: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
                   7251:     int ret = 0, arg1i = 0, arg2i = 0;
                   7252:     xmlXPathObjectPtr arg1, arg2;
                   7253: 
                   7254:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
                   7255:     arg2 = valuePop(ctxt);
                   7256:     arg1 = valuePop(ctxt);
                   7257:     if ((arg1 == NULL) || (arg2 == NULL)) {
                   7258:        if (arg1 != NULL)
                   7259:            xmlXPathReleaseObject(ctxt->context, arg1);
                   7260:        else
                   7261:            xmlXPathReleaseObject(ctxt->context, arg2);
                   7262:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7263:     }
                   7264: 
                   7265:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
                   7266:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7267:        /*
                   7268:         * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
                   7269:         * are not freed from within this routine; they will be freed from the
                   7270:         * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
                   7271:         */
                   7272:        if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
                   7273:          ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
                   7274:            ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
                   7275:        } else {
                   7276:            if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7277:                ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
                   7278:                                                  arg1, arg2);
                   7279:            } else {
                   7280:                ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
                   7281:                                                  arg2, arg1);
                   7282:            }
                   7283:        }
                   7284:        return(ret);
                   7285:     }
                   7286: 
                   7287:     if (arg1->type != XPATH_NUMBER) {
                   7288:        valuePush(ctxt, arg1);
                   7289:        xmlXPathNumberFunction(ctxt, 1);
                   7290:        arg1 = valuePop(ctxt);
                   7291:     }
                   7292:     if (arg1->type != XPATH_NUMBER) {
                   7293:        xmlXPathFreeObject(arg1);
                   7294:        xmlXPathFreeObject(arg2);
                   7295:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7296:     }
                   7297:     if (arg2->type != XPATH_NUMBER) {
                   7298:        valuePush(ctxt, arg2);
                   7299:        xmlXPathNumberFunction(ctxt, 1);
                   7300:        arg2 = valuePop(ctxt);
                   7301:     }
                   7302:     if (arg2->type != XPATH_NUMBER) {
                   7303:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7304:        xmlXPathReleaseObject(ctxt->context, arg2);
                   7305:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7306:     }
                   7307:     /*
                   7308:      * Add tests for infinity and nan
                   7309:      * => feedback on 3.4 for Inf and NaN
                   7310:      */
                   7311:     /* Hand check NaN and Infinity comparisons */
                   7312:     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
                   7313:        ret=0;
                   7314:     } else {
                   7315:        arg1i=xmlXPathIsInf(arg1->floatval);
                   7316:        arg2i=xmlXPathIsInf(arg2->floatval);
                   7317:        if (inf && strict) {
                   7318:            if ((arg1i == -1 && arg2i != -1) ||
                   7319:                (arg2i == 1 && arg1i != 1)) {
                   7320:                ret = 1;
                   7321:            } else if (arg1i == 0 && arg2i == 0) {
                   7322:                ret = (arg1->floatval < arg2->floatval);
                   7323:            } else {
                   7324:                ret = 0;
                   7325:            }
                   7326:        }
                   7327:        else if (inf && !strict) {
                   7328:            if (arg1i == -1 || arg2i == 1) {
                   7329:                ret = 1;
                   7330:            } else if (arg1i == 0 && arg2i == 0) {
                   7331:                ret = (arg1->floatval <= arg2->floatval);
                   7332:            } else {
                   7333:                ret = 0;
                   7334:            }
                   7335:        }
                   7336:        else if (!inf && strict) {
                   7337:            if ((arg1i == 1 && arg2i != 1) ||
                   7338:                (arg2i == -1 && arg1i != -1)) {
                   7339:                ret = 1;
                   7340:            } else if (arg1i == 0 && arg2i == 0) {
                   7341:                ret = (arg1->floatval > arg2->floatval);
                   7342:            } else {
                   7343:                ret = 0;
                   7344:            }
                   7345:        }
                   7346:        else if (!inf && !strict) {
                   7347:            if (arg1i == 1 || arg2i == -1) {
                   7348:                ret = 1;
                   7349:            } else if (arg1i == 0 && arg2i == 0) {
                   7350:                ret = (arg1->floatval >= arg2->floatval);
                   7351:            } else {
                   7352:                ret = 0;
                   7353:            }
                   7354:        }
                   7355:     }
                   7356:     xmlXPathReleaseObject(ctxt->context, arg1);
                   7357:     xmlXPathReleaseObject(ctxt->context, arg2);
                   7358:     return(ret);
                   7359: }
                   7360: 
                   7361: /**
                   7362:  * xmlXPathValueFlipSign:
                   7363:  * @ctxt:  the XPath Parser context
                   7364:  *
                   7365:  * Implement the unary - operation on an XPath object
                   7366:  * The numeric operators convert their operands to numbers as if
                   7367:  * by calling the number function.
                   7368:  */
                   7369: void
                   7370: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
                   7371:     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
                   7372:     CAST_TO_NUMBER;
                   7373:     CHECK_TYPE(XPATH_NUMBER);
                   7374:     if (xmlXPathIsNaN(ctxt->value->floatval))
                   7375:         ctxt->value->floatval=xmlXPathNAN;
                   7376:     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
                   7377:         ctxt->value->floatval=xmlXPathNINF;
                   7378:     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
                   7379:         ctxt->value->floatval=xmlXPathPINF;
                   7380:     else if (ctxt->value->floatval == 0) {
                   7381:         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
                   7382:            ctxt->value->floatval = xmlXPathNZERO;
                   7383:        else
                   7384:            ctxt->value->floatval = 0;
                   7385:     }
                   7386:     else
                   7387:         ctxt->value->floatval = - ctxt->value->floatval;
                   7388: }
                   7389: 
                   7390: /**
                   7391:  * xmlXPathAddValues:
                   7392:  * @ctxt:  the XPath Parser context
                   7393:  *
                   7394:  * Implement the add operation on XPath objects:
                   7395:  * The numeric operators convert their operands to numbers as if
                   7396:  * by calling the number function.
                   7397:  */
                   7398: void
                   7399: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
                   7400:     xmlXPathObjectPtr arg;
                   7401:     double val;
                   7402: 
                   7403:     arg = valuePop(ctxt);
                   7404:     if (arg == NULL)
                   7405:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7406:     val = xmlXPathCastToNumber(arg);
                   7407:     xmlXPathReleaseObject(ctxt->context, arg);
                   7408:     CAST_TO_NUMBER;
                   7409:     CHECK_TYPE(XPATH_NUMBER);
                   7410:     ctxt->value->floatval += val;
                   7411: }
                   7412: 
                   7413: /**
                   7414:  * xmlXPathSubValues:
                   7415:  * @ctxt:  the XPath Parser context
                   7416:  *
                   7417:  * Implement the subtraction operation on XPath objects:
                   7418:  * The numeric operators convert their operands to numbers as if
                   7419:  * by calling the number function.
                   7420:  */
                   7421: void
                   7422: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
                   7423:     xmlXPathObjectPtr arg;
                   7424:     double val;
                   7425: 
                   7426:     arg = valuePop(ctxt);
                   7427:     if (arg == NULL)
                   7428:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7429:     val = xmlXPathCastToNumber(arg);
                   7430:     xmlXPathReleaseObject(ctxt->context, arg);
                   7431:     CAST_TO_NUMBER;
                   7432:     CHECK_TYPE(XPATH_NUMBER);
                   7433:     ctxt->value->floatval -= val;
                   7434: }
                   7435: 
                   7436: /**
                   7437:  * xmlXPathMultValues:
                   7438:  * @ctxt:  the XPath Parser context
                   7439:  *
                   7440:  * Implement the multiply operation on XPath objects:
                   7441:  * The numeric operators convert their operands to numbers as if
                   7442:  * by calling the number function.
                   7443:  */
                   7444: void
                   7445: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
                   7446:     xmlXPathObjectPtr arg;
                   7447:     double val;
                   7448: 
                   7449:     arg = valuePop(ctxt);
                   7450:     if (arg == NULL)
                   7451:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7452:     val = xmlXPathCastToNumber(arg);
                   7453:     xmlXPathReleaseObject(ctxt->context, arg);
                   7454:     CAST_TO_NUMBER;
                   7455:     CHECK_TYPE(XPATH_NUMBER);
                   7456:     ctxt->value->floatval *= val;
                   7457: }
                   7458: 
                   7459: /**
                   7460:  * xmlXPathDivValues:
                   7461:  * @ctxt:  the XPath Parser context
                   7462:  *
                   7463:  * Implement the div operation on XPath objects @arg1 / @arg2:
                   7464:  * The numeric operators convert their operands to numbers as if
                   7465:  * by calling the number function.
                   7466:  */
                   7467: void
                   7468: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
                   7469:     xmlXPathObjectPtr arg;
                   7470:     double val;
                   7471: 
                   7472:     arg = valuePop(ctxt);
                   7473:     if (arg == NULL)
                   7474:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7475:     val = xmlXPathCastToNumber(arg);
                   7476:     xmlXPathReleaseObject(ctxt->context, arg);
                   7477:     CAST_TO_NUMBER;
                   7478:     CHECK_TYPE(XPATH_NUMBER);
                   7479:     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
                   7480:        ctxt->value->floatval = xmlXPathNAN;
                   7481:     else if (val == 0 && xmlXPathGetSign(val) != 0) {
                   7482:        if (ctxt->value->floatval == 0)
                   7483:            ctxt->value->floatval = xmlXPathNAN;
                   7484:        else if (ctxt->value->floatval > 0)
                   7485:            ctxt->value->floatval = xmlXPathNINF;
                   7486:        else if (ctxt->value->floatval < 0)
                   7487:            ctxt->value->floatval = xmlXPathPINF;
                   7488:     }
                   7489:     else if (val == 0) {
                   7490:        if (ctxt->value->floatval == 0)
                   7491:            ctxt->value->floatval = xmlXPathNAN;
                   7492:        else if (ctxt->value->floatval > 0)
                   7493:            ctxt->value->floatval = xmlXPathPINF;
                   7494:        else if (ctxt->value->floatval < 0)
                   7495:            ctxt->value->floatval = xmlXPathNINF;
                   7496:     } else
                   7497:        ctxt->value->floatval /= val;
                   7498: }
                   7499: 
                   7500: /**
                   7501:  * xmlXPathModValues:
                   7502:  * @ctxt:  the XPath Parser context
                   7503:  *
                   7504:  * Implement the mod operation on XPath objects: @arg1 / @arg2
                   7505:  * The numeric operators convert their operands to numbers as if
                   7506:  * by calling the number function.
                   7507:  */
                   7508: void
                   7509: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
                   7510:     xmlXPathObjectPtr arg;
                   7511:     double arg1, arg2;
                   7512: 
                   7513:     arg = valuePop(ctxt);
                   7514:     if (arg == NULL)
                   7515:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7516:     arg2 = xmlXPathCastToNumber(arg);
                   7517:     xmlXPathReleaseObject(ctxt->context, arg);
                   7518:     CAST_TO_NUMBER;
                   7519:     CHECK_TYPE(XPATH_NUMBER);
                   7520:     arg1 = ctxt->value->floatval;
                   7521:     if (arg2 == 0)
                   7522:        ctxt->value->floatval = xmlXPathNAN;
                   7523:     else {
                   7524:        ctxt->value->floatval = fmod(arg1, arg2);
                   7525:     }
                   7526: }
                   7527: 
                   7528: /************************************************************************
                   7529:  *                                                                     *
                   7530:  *             The traversal functions                                 *
                   7531:  *                                                                     *
                   7532:  ************************************************************************/
                   7533: 
                   7534: /*
                   7535:  * A traversal function enumerates nodes along an axis.
                   7536:  * Initially it must be called with NULL, and it indicates
                   7537:  * termination on the axis by returning NULL.
                   7538:  */
                   7539: typedef xmlNodePtr (*xmlXPathTraversalFunction)
                   7540:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
                   7541: 
                   7542: /*
                   7543:  * xmlXPathTraversalFunctionExt:
                   7544:  * A traversal function enumerates nodes along an axis.
                   7545:  * Initially it must be called with NULL, and it indicates
                   7546:  * termination on the axis by returning NULL.
                   7547:  * The context node of the traversal is specified via @contextNode.
                   7548:  */
                   7549: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
                   7550:                     (xmlNodePtr cur, xmlNodePtr contextNode);
                   7551: 
                   7552: /*
                   7553:  * xmlXPathNodeSetMergeFunction:
                   7554:  * Used for merging node sets in xmlXPathCollectAndTest().
                   7555:  */
                   7556: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
                   7557:                    (xmlNodeSetPtr, xmlNodeSetPtr, int);
                   7558: 
                   7559: 
                   7560: /**
                   7561:  * xmlXPathNextSelf:
                   7562:  * @ctxt:  the XPath Parser context
                   7563:  * @cur:  the current node in the traversal
                   7564:  *
                   7565:  * Traversal function for the "self" direction
                   7566:  * The self axis contains just the context node itself
                   7567:  *
                   7568:  * Returns the next element following that axis
                   7569:  */
                   7570: xmlNodePtr
                   7571: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7572:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7573:     if (cur == NULL)
                   7574:         return(ctxt->context->node);
                   7575:     return(NULL);
                   7576: }
                   7577: 
                   7578: /**
                   7579:  * xmlXPathNextChild:
                   7580:  * @ctxt:  the XPath Parser context
                   7581:  * @cur:  the current node in the traversal
                   7582:  *
                   7583:  * Traversal function for the "child" direction
                   7584:  * The child axis contains the children of the context node in document order.
                   7585:  *
                   7586:  * Returns the next element following that axis
                   7587:  */
                   7588: xmlNodePtr
                   7589: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7590:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7591:     if (cur == NULL) {
                   7592:        if (ctxt->context->node == NULL) return(NULL);
                   7593:        switch (ctxt->context->node->type) {
                   7594:             case XML_ELEMENT_NODE:
                   7595:             case XML_TEXT_NODE:
                   7596:             case XML_CDATA_SECTION_NODE:
                   7597:             case XML_ENTITY_REF_NODE:
                   7598:             case XML_ENTITY_NODE:
                   7599:             case XML_PI_NODE:
                   7600:             case XML_COMMENT_NODE:
                   7601:             case XML_NOTATION_NODE:
                   7602:             case XML_DTD_NODE:
                   7603:                return(ctxt->context->node->children);
                   7604:             case XML_DOCUMENT_NODE:
                   7605:             case XML_DOCUMENT_TYPE_NODE:
                   7606:             case XML_DOCUMENT_FRAG_NODE:
                   7607:             case XML_HTML_DOCUMENT_NODE:
                   7608: #ifdef LIBXML_DOCB_ENABLED
                   7609:            case XML_DOCB_DOCUMENT_NODE:
                   7610: #endif
                   7611:                return(((xmlDocPtr) ctxt->context->node)->children);
                   7612:            case XML_ELEMENT_DECL:
                   7613:            case XML_ATTRIBUTE_DECL:
                   7614:            case XML_ENTITY_DECL:
                   7615:             case XML_ATTRIBUTE_NODE:
                   7616:            case XML_NAMESPACE_DECL:
                   7617:            case XML_XINCLUDE_START:
                   7618:            case XML_XINCLUDE_END:
                   7619:                return(NULL);
                   7620:        }
                   7621:        return(NULL);
                   7622:     }
                   7623:     if ((cur->type == XML_DOCUMENT_NODE) ||
                   7624:         (cur->type == XML_HTML_DOCUMENT_NODE))
                   7625:        return(NULL);
                   7626:     return(cur->next);
                   7627: }
                   7628: 
                   7629: /**
                   7630:  * xmlXPathNextChildElement:
                   7631:  * @ctxt:  the XPath Parser context
                   7632:  * @cur:  the current node in the traversal
                   7633:  *
                   7634:  * Traversal function for the "child" direction and nodes of type element.
                   7635:  * The child axis contains the children of the context node in document order.
                   7636:  *
                   7637:  * Returns the next element following that axis
                   7638:  */
                   7639: static xmlNodePtr
                   7640: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7641:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7642:     if (cur == NULL) {
                   7643:        cur = ctxt->context->node;
                   7644:        if (cur == NULL) return(NULL);
                   7645:        /*
                   7646:        * Get the first element child.
                   7647:        */
                   7648:        switch (cur->type) {
                   7649:             case XML_ELEMENT_NODE:
                   7650:            case XML_DOCUMENT_FRAG_NODE:
                   7651:            case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
                   7652:             case XML_ENTITY_NODE:
                   7653:                cur = cur->children;
                   7654:                if (cur != NULL) {
                   7655:                    if (cur->type == XML_ELEMENT_NODE)
                   7656:                        return(cur);
                   7657:                    do {
                   7658:                        cur = cur->next;
                   7659:                    } while ((cur != NULL) &&
                   7660:                        (cur->type != XML_ELEMENT_NODE));
                   7661:                    return(cur);
                   7662:                }
                   7663:                return(NULL);
                   7664:             case XML_DOCUMENT_NODE:
                   7665:             case XML_HTML_DOCUMENT_NODE:
                   7666: #ifdef LIBXML_DOCB_ENABLED
                   7667:            case XML_DOCB_DOCUMENT_NODE:
                   7668: #endif
                   7669:                return(xmlDocGetRootElement((xmlDocPtr) cur));
                   7670:            default:
                   7671:                return(NULL);
                   7672:        }
                   7673:        return(NULL);
                   7674:     }
                   7675:     /*
                   7676:     * Get the next sibling element node.
                   7677:     */
                   7678:     switch (cur->type) {
                   7679:        case XML_ELEMENT_NODE:
                   7680:        case XML_TEXT_NODE:
                   7681:        case XML_ENTITY_REF_NODE:
                   7682:        case XML_ENTITY_NODE:
                   7683:        case XML_CDATA_SECTION_NODE:
                   7684:        case XML_PI_NODE:
                   7685:        case XML_COMMENT_NODE:
                   7686:        case XML_XINCLUDE_END:
                   7687:            break;
                   7688:        /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
                   7689:        default:
                   7690:            return(NULL);
                   7691:     }
                   7692:     if (cur->next != NULL) {
                   7693:        if (cur->next->type == XML_ELEMENT_NODE)
                   7694:            return(cur->next);
                   7695:        cur = cur->next;
                   7696:        do {
                   7697:            cur = cur->next;
                   7698:        } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
                   7699:        return(cur);
                   7700:     }
                   7701:     return(NULL);
                   7702: }
                   7703: 
                   7704: /**
                   7705:  * xmlXPathNextDescendantOrSelfElemParent:
                   7706:  * @ctxt:  the XPath Parser context
                   7707:  * @cur:  the current node in the traversal
                   7708:  *
                   7709:  * Traversal function for the "descendant-or-self" axis.
                   7710:  * Additionally it returns only nodes which can be parents of
                   7711:  * element nodes.
                   7712:  *
                   7713:  *
                   7714:  * Returns the next element following that axis
                   7715:  */
                   7716: static xmlNodePtr
                   7717: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
                   7718:                                       xmlNodePtr contextNode)
                   7719: {
                   7720:     if (cur == NULL) {
                   7721:        if (contextNode == NULL)
                   7722:            return(NULL);
                   7723:        switch (contextNode->type) {
                   7724:            case XML_ELEMENT_NODE:
                   7725:            case XML_XINCLUDE_START:
                   7726:            case XML_DOCUMENT_FRAG_NODE:
                   7727:            case XML_DOCUMENT_NODE:
                   7728: #ifdef LIBXML_DOCB_ENABLED
                   7729:            case XML_DOCB_DOCUMENT_NODE:
                   7730: #endif
                   7731:            case XML_HTML_DOCUMENT_NODE:            
                   7732:                return(contextNode);
                   7733:            default:
                   7734:                return(NULL);
                   7735:        }
                   7736:        return(NULL);
                   7737:     } else {
                   7738:        xmlNodePtr start = cur;
                   7739: 
                   7740:        while (cur != NULL) {
                   7741:            switch (cur->type) {
                   7742:                case XML_ELEMENT_NODE:
                   7743:                /* TODO: OK to have XInclude here? */
                   7744:                case XML_XINCLUDE_START:
                   7745:                case XML_DOCUMENT_FRAG_NODE:
                   7746:                    if (cur != start)
                   7747:                        return(cur);
                   7748:                    if (cur->children != NULL) {
                   7749:                        cur = cur->children;
                   7750:                        continue;
                   7751:                    }
                   7752:                    break;
                   7753:                /* Not sure if we need those here. */
                   7754:                case XML_DOCUMENT_NODE:
                   7755: #ifdef LIBXML_DOCB_ENABLED
                   7756:                case XML_DOCB_DOCUMENT_NODE:
                   7757: #endif
                   7758:                case XML_HTML_DOCUMENT_NODE:
                   7759:                    if (cur != start)
                   7760:                        return(cur);
                   7761:                    return(xmlDocGetRootElement((xmlDocPtr) cur));
                   7762:                default:
                   7763:                    break;
                   7764:            }
                   7765: 
                   7766: next_sibling:
                   7767:            if ((cur == NULL) || (cur == contextNode))
                   7768:                return(NULL);
                   7769:            if (cur->next != NULL) {
                   7770:                cur = cur->next;
                   7771:            } else {
                   7772:                cur = cur->parent;
                   7773:                goto next_sibling;
                   7774:            }
                   7775:        }
                   7776:     }
                   7777:     return(NULL);
                   7778: }
                   7779: 
                   7780: /**
                   7781:  * xmlXPathNextDescendant:
                   7782:  * @ctxt:  the XPath Parser context
                   7783:  * @cur:  the current node in the traversal
                   7784:  *
                   7785:  * Traversal function for the "descendant" direction
                   7786:  * the descendant axis contains the descendants of the context node in document
                   7787:  * order; a descendant is a child or a child of a child and so on.
                   7788:  *
                   7789:  * Returns the next element following that axis
                   7790:  */
                   7791: xmlNodePtr
                   7792: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7793:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7794:     if (cur == NULL) {
                   7795:        if (ctxt->context->node == NULL)
                   7796:            return(NULL);
                   7797:        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   7798:            (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   7799:            return(NULL);
                   7800: 
                   7801:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
                   7802:            return(ctxt->context->doc->children);
                   7803:         return(ctxt->context->node->children);
                   7804:     }
                   7805: 
                   7806:     if (cur->children != NULL) {
                   7807:        /*
                   7808:         * Do not descend on entities declarations
                   7809:         */
                   7810:        if (cur->children->type != XML_ENTITY_DECL) {
                   7811:            cur = cur->children;
                   7812:            /*
                   7813:             * Skip DTDs
                   7814:             */
                   7815:            if (cur->type != XML_DTD_NODE)
                   7816:                return(cur);
                   7817:        }
                   7818:     }
                   7819: 
                   7820:     if (cur == ctxt->context->node) return(NULL);
                   7821: 
                   7822:     while (cur->next != NULL) {
                   7823:        cur = cur->next;
                   7824:        if ((cur->type != XML_ENTITY_DECL) &&
                   7825:            (cur->type != XML_DTD_NODE))
                   7826:            return(cur);
                   7827:     }
                   7828: 
                   7829:     do {
                   7830:         cur = cur->parent;
                   7831:        if (cur == NULL) break;
                   7832:        if (cur == ctxt->context->node) return(NULL);
                   7833:        if (cur->next != NULL) {
                   7834:            cur = cur->next;
                   7835:            return(cur);
                   7836:        }
                   7837:     } while (cur != NULL);
                   7838:     return(cur);
                   7839: }
                   7840: 
                   7841: /**
                   7842:  * xmlXPathNextDescendantOrSelf:
                   7843:  * @ctxt:  the XPath Parser context
                   7844:  * @cur:  the current node in the traversal
                   7845:  *
                   7846:  * Traversal function for the "descendant-or-self" direction
                   7847:  * the descendant-or-self axis contains the context node and the descendants
                   7848:  * of the context node in document order; thus the context node is the first
                   7849:  * node on the axis, and the first child of the context node is the second node
                   7850:  * on the axis
                   7851:  *
                   7852:  * Returns the next element following that axis
                   7853:  */
                   7854: xmlNodePtr
                   7855: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7856:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7857:     if (cur == NULL) {
                   7858:        if (ctxt->context->node == NULL)
                   7859:            return(NULL);
                   7860:        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   7861:            (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   7862:            return(NULL);
                   7863:         return(ctxt->context->node);
                   7864:     }
                   7865: 
                   7866:     return(xmlXPathNextDescendant(ctxt, cur));
                   7867: }
                   7868: 
                   7869: /**
                   7870:  * xmlXPathNextParent:
                   7871:  * @ctxt:  the XPath Parser context
                   7872:  * @cur:  the current node in the traversal
                   7873:  *
                   7874:  * Traversal function for the "parent" direction
                   7875:  * The parent axis contains the parent of the context node, if there is one.
                   7876:  *
                   7877:  * Returns the next element following that axis
                   7878:  */
                   7879: xmlNodePtr
                   7880: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7881:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7882:     /*
                   7883:      * the parent of an attribute or namespace node is the element
                   7884:      * to which the attribute or namespace node is attached
                   7885:      * Namespace handling !!!
                   7886:      */
                   7887:     if (cur == NULL) {
                   7888:        if (ctxt->context->node == NULL) return(NULL);
                   7889:        switch (ctxt->context->node->type) {
                   7890:             case XML_ELEMENT_NODE:
                   7891:             case XML_TEXT_NODE:
                   7892:             case XML_CDATA_SECTION_NODE:
                   7893:             case XML_ENTITY_REF_NODE:
                   7894:             case XML_ENTITY_NODE:
                   7895:             case XML_PI_NODE:
                   7896:             case XML_COMMENT_NODE:
                   7897:             case XML_NOTATION_NODE:
                   7898:             case XML_DTD_NODE:
                   7899:            case XML_ELEMENT_DECL:
                   7900:            case XML_ATTRIBUTE_DECL:
                   7901:            case XML_XINCLUDE_START:
                   7902:            case XML_XINCLUDE_END:
                   7903:            case XML_ENTITY_DECL:
                   7904:                if (ctxt->context->node->parent == NULL)
                   7905:                    return((xmlNodePtr) ctxt->context->doc);
                   7906:                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
                   7907:                    ((ctxt->context->node->parent->name[0] == ' ') ||
                   7908:                     (xmlStrEqual(ctxt->context->node->parent->name,
                   7909:                                 BAD_CAST "fake node libxslt"))))
                   7910:                    return(NULL);
                   7911:                return(ctxt->context->node->parent);
                   7912:             case XML_ATTRIBUTE_NODE: {
                   7913:                xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
                   7914: 
                   7915:                return(att->parent);
                   7916:            }
                   7917:             case XML_DOCUMENT_NODE:
                   7918:             case XML_DOCUMENT_TYPE_NODE:
                   7919:             case XML_DOCUMENT_FRAG_NODE:
                   7920:             case XML_HTML_DOCUMENT_NODE:
                   7921: #ifdef LIBXML_DOCB_ENABLED
                   7922:            case XML_DOCB_DOCUMENT_NODE:
                   7923: #endif
                   7924:                 return(NULL);
                   7925:            case XML_NAMESPACE_DECL: {
                   7926:                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
                   7927: 
                   7928:                if ((ns->next != NULL) &&
                   7929:                    (ns->next->type != XML_NAMESPACE_DECL))
                   7930:                    return((xmlNodePtr) ns->next);
                   7931:                 return(NULL);
                   7932:            }
                   7933:        }
                   7934:     }
                   7935:     return(NULL);
                   7936: }
                   7937: 
                   7938: /**
                   7939:  * xmlXPathNextAncestor:
                   7940:  * @ctxt:  the XPath Parser context
                   7941:  * @cur:  the current node in the traversal
                   7942:  *
                   7943:  * Traversal function for the "ancestor" direction
                   7944:  * the ancestor axis contains the ancestors of the context node; the ancestors
                   7945:  * of the context node consist of the parent of context node and the parent's
                   7946:  * parent and so on; the nodes are ordered in reverse document order; thus the
                   7947:  * parent is the first node on the axis, and the parent's parent is the second
                   7948:  * node on the axis
                   7949:  *
                   7950:  * Returns the next element following that axis
                   7951:  */
                   7952: xmlNodePtr
                   7953: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7954:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7955:     /*
                   7956:      * the parent of an attribute or namespace node is the element
                   7957:      * to which the attribute or namespace node is attached
                   7958:      * !!!!!!!!!!!!!
                   7959:      */
                   7960:     if (cur == NULL) {
                   7961:        if (ctxt->context->node == NULL) return(NULL);
                   7962:        switch (ctxt->context->node->type) {
                   7963:             case XML_ELEMENT_NODE:
                   7964:             case XML_TEXT_NODE:
                   7965:             case XML_CDATA_SECTION_NODE:
                   7966:             case XML_ENTITY_REF_NODE:
                   7967:             case XML_ENTITY_NODE:
                   7968:             case XML_PI_NODE:
                   7969:             case XML_COMMENT_NODE:
                   7970:            case XML_DTD_NODE:
                   7971:            case XML_ELEMENT_DECL:
                   7972:            case XML_ATTRIBUTE_DECL:
                   7973:            case XML_ENTITY_DECL:
                   7974:             case XML_NOTATION_NODE:
                   7975:            case XML_XINCLUDE_START:
                   7976:            case XML_XINCLUDE_END:
                   7977:                if (ctxt->context->node->parent == NULL)
                   7978:                    return((xmlNodePtr) ctxt->context->doc);
                   7979:                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
                   7980:                    ((ctxt->context->node->parent->name[0] == ' ') ||
                   7981:                     (xmlStrEqual(ctxt->context->node->parent->name,
                   7982:                                 BAD_CAST "fake node libxslt"))))
                   7983:                    return(NULL);
                   7984:                return(ctxt->context->node->parent);
                   7985:             case XML_ATTRIBUTE_NODE: {
                   7986:                xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
                   7987: 
                   7988:                return(tmp->parent);
                   7989:            }
                   7990:             case XML_DOCUMENT_NODE:
                   7991:             case XML_DOCUMENT_TYPE_NODE:
                   7992:             case XML_DOCUMENT_FRAG_NODE:
                   7993:             case XML_HTML_DOCUMENT_NODE:
                   7994: #ifdef LIBXML_DOCB_ENABLED
                   7995:            case XML_DOCB_DOCUMENT_NODE:
                   7996: #endif
                   7997:                 return(NULL);
                   7998:            case XML_NAMESPACE_DECL: {
                   7999:                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
                   8000: 
                   8001:                if ((ns->next != NULL) &&
                   8002:                    (ns->next->type != XML_NAMESPACE_DECL))
                   8003:                    return((xmlNodePtr) ns->next);
                   8004:                /* Bad, how did that namespace end up here ? */
                   8005:                 return(NULL);
                   8006:            }
                   8007:        }
                   8008:        return(NULL);
                   8009:     }
                   8010:     if (cur == ctxt->context->doc->children)
                   8011:        return((xmlNodePtr) ctxt->context->doc);
                   8012:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   8013:        return(NULL);
                   8014:     switch (cur->type) {
                   8015:        case XML_ELEMENT_NODE:
                   8016:        case XML_TEXT_NODE:
                   8017:        case XML_CDATA_SECTION_NODE:
                   8018:        case XML_ENTITY_REF_NODE:
                   8019:        case XML_ENTITY_NODE:
                   8020:        case XML_PI_NODE:
                   8021:        case XML_COMMENT_NODE:
                   8022:        case XML_NOTATION_NODE:
                   8023:        case XML_DTD_NODE:
                   8024:         case XML_ELEMENT_DECL:
                   8025:         case XML_ATTRIBUTE_DECL:
                   8026:         case XML_ENTITY_DECL:
                   8027:        case XML_XINCLUDE_START:
                   8028:        case XML_XINCLUDE_END:
                   8029:            if (cur->parent == NULL)
                   8030:                return(NULL);
                   8031:            if ((cur->parent->type == XML_ELEMENT_NODE) &&
                   8032:                ((cur->parent->name[0] == ' ') ||
                   8033:                 (xmlStrEqual(cur->parent->name,
                   8034:                              BAD_CAST "fake node libxslt"))))
                   8035:                return(NULL);
                   8036:            return(cur->parent);
                   8037:        case XML_ATTRIBUTE_NODE: {
                   8038:            xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
                   8039: 
                   8040:            return(att->parent);
                   8041:        }
                   8042:        case XML_NAMESPACE_DECL: {
                   8043:            xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
                   8044: 
                   8045:            if ((ns->next != NULL) &&
                   8046:                (ns->next->type != XML_NAMESPACE_DECL))
                   8047:                return((xmlNodePtr) ns->next);
                   8048:            /* Bad, how did that namespace end up here ? */
                   8049:             return(NULL);
                   8050:        }
                   8051:        case XML_DOCUMENT_NODE:
                   8052:        case XML_DOCUMENT_TYPE_NODE:
                   8053:        case XML_DOCUMENT_FRAG_NODE:
                   8054:        case XML_HTML_DOCUMENT_NODE:
                   8055: #ifdef LIBXML_DOCB_ENABLED
                   8056:        case XML_DOCB_DOCUMENT_NODE:
                   8057: #endif
                   8058:            return(NULL);
                   8059:     }
                   8060:     return(NULL);
                   8061: }
                   8062: 
                   8063: /**
                   8064:  * xmlXPathNextAncestorOrSelf:
                   8065:  * @ctxt:  the XPath Parser context
                   8066:  * @cur:  the current node in the traversal
                   8067:  *
                   8068:  * Traversal function for the "ancestor-or-self" direction
                   8069:  * he ancestor-or-self axis contains the context node and ancestors of
                   8070:  * the context node in reverse document order; thus the context node is
                   8071:  * the first node on the axis, and the context node's parent the second;
                   8072:  * parent here is defined the same as with the parent axis.
                   8073:  *
                   8074:  * Returns the next element following that axis
                   8075:  */
                   8076: xmlNodePtr
                   8077: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8078:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8079:     if (cur == NULL)
                   8080:         return(ctxt->context->node);
                   8081:     return(xmlXPathNextAncestor(ctxt, cur));
                   8082: }
                   8083: 
                   8084: /**
                   8085:  * xmlXPathNextFollowingSibling:
                   8086:  * @ctxt:  the XPath Parser context
                   8087:  * @cur:  the current node in the traversal
                   8088:  *
                   8089:  * Traversal function for the "following-sibling" direction
                   8090:  * The following-sibling axis contains the following siblings of the context
                   8091:  * node in document order.
                   8092:  *
                   8093:  * Returns the next element following that axis
                   8094:  */
                   8095: xmlNodePtr
                   8096: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8097:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8098:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   8099:        (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   8100:        return(NULL);
                   8101:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   8102:         return(NULL);
                   8103:     if (cur == NULL)
                   8104:         return(ctxt->context->node->next);
                   8105:     return(cur->next);
                   8106: }
                   8107: 
                   8108: /**
                   8109:  * xmlXPathNextPrecedingSibling:
                   8110:  * @ctxt:  the XPath Parser context
                   8111:  * @cur:  the current node in the traversal
                   8112:  *
                   8113:  * Traversal function for the "preceding-sibling" direction
                   8114:  * The preceding-sibling axis contains the preceding siblings of the context
                   8115:  * node in reverse document order; the first preceding sibling is first on the
                   8116:  * axis; the sibling preceding that node is the second on the axis and so on.
                   8117:  *
                   8118:  * Returns the next element following that axis
                   8119:  */
                   8120: xmlNodePtr
                   8121: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8122:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8123:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   8124:        (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   8125:        return(NULL);
                   8126:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   8127:         return(NULL);
                   8128:     if (cur == NULL)
                   8129:         return(ctxt->context->node->prev);
                   8130:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
                   8131:        cur = cur->prev;
                   8132:        if (cur == NULL)
                   8133:            return(ctxt->context->node->prev);
                   8134:     }
                   8135:     return(cur->prev);
                   8136: }
                   8137: 
                   8138: /**
                   8139:  * xmlXPathNextFollowing:
                   8140:  * @ctxt:  the XPath Parser context
                   8141:  * @cur:  the current node in the traversal
                   8142:  *
                   8143:  * Traversal function for the "following" direction
                   8144:  * The following axis contains all nodes in the same document as the context
                   8145:  * node that are after the context node in document order, excluding any
                   8146:  * descendants and excluding attribute nodes and namespace nodes; the nodes
                   8147:  * are ordered in document order
                   8148:  *
                   8149:  * Returns the next element following that axis
                   8150:  */
                   8151: xmlNodePtr
                   8152: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8153:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8154:     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
                   8155:         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
                   8156:         return(cur->children);
                   8157: 
                   8158:     if (cur == NULL) {
                   8159:         cur = ctxt->context->node;
                   8160:         if (cur->type == XML_NAMESPACE_DECL)
                   8161:             return(NULL);
                   8162:         if (cur->type == XML_ATTRIBUTE_NODE)
                   8163:             cur = cur->parent;
                   8164:     }
                   8165:     if (cur == NULL) return(NULL) ; /* ERROR */
                   8166:     if (cur->next != NULL) return(cur->next) ;
                   8167:     do {
                   8168:         cur = cur->parent;
                   8169:         if (cur == NULL) break;
                   8170:         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
                   8171:         if (cur->next != NULL) return(cur->next);
                   8172:     } while (cur != NULL);
                   8173:     return(cur);
                   8174: }
                   8175: 
                   8176: /*
                   8177:  * xmlXPathIsAncestor:
                   8178:  * @ancestor:  the ancestor node
                   8179:  * @node:  the current node
                   8180:  *
                   8181:  * Check that @ancestor is a @node's ancestor
                   8182:  *
                   8183:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
                   8184:  */
                   8185: static int
                   8186: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
                   8187:     if ((ancestor == NULL) || (node == NULL)) return(0);
                   8188:     /* nodes need to be in the same document */
                   8189:     if (ancestor->doc != node->doc) return(0);
                   8190:     /* avoid searching if ancestor or node is the root node */
                   8191:     if (ancestor == (xmlNodePtr) node->doc) return(1);
                   8192:     if (node == (xmlNodePtr) ancestor->doc) return(0);
                   8193:     while (node->parent != NULL) {
                   8194:         if (node->parent == ancestor)
                   8195:             return(1);
                   8196:        node = node->parent;
                   8197:     }
                   8198:     return(0);
                   8199: }
                   8200: 
                   8201: /**
                   8202:  * xmlXPathNextPreceding:
                   8203:  * @ctxt:  the XPath Parser context
                   8204:  * @cur:  the current node in the traversal
                   8205:  *
                   8206:  * Traversal function for the "preceding" direction
                   8207:  * the preceding axis contains all nodes in the same document as the context
                   8208:  * node that are before the context node in document order, excluding any
                   8209:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
                   8210:  * ordered in reverse document order
                   8211:  *
                   8212:  * Returns the next element following that axis
                   8213:  */
                   8214: xmlNodePtr
                   8215: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
                   8216: {
                   8217:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8218:     if (cur == NULL) {
                   8219:         cur = ctxt->context->node;
                   8220:         if (cur->type == XML_NAMESPACE_DECL)
                   8221:             return(NULL);
                   8222:         if (cur->type == XML_ATTRIBUTE_NODE)
                   8223:             return(cur->parent);
                   8224:     }
                   8225:     if (cur == NULL)
                   8226:        return (NULL);
                   8227:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
                   8228:        cur = cur->prev;
                   8229:     do {
                   8230:         if (cur->prev != NULL) {
                   8231:             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
                   8232:             return (cur);
                   8233:         }
                   8234: 
                   8235:         cur = cur->parent;
                   8236:         if (cur == NULL)
                   8237:             return (NULL);
                   8238:         if (cur == ctxt->context->doc->children)
                   8239:             return (NULL);
                   8240:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
                   8241:     return (cur);
                   8242: }
                   8243: 
                   8244: /**
                   8245:  * xmlXPathNextPrecedingInternal:
                   8246:  * @ctxt:  the XPath Parser context
                   8247:  * @cur:  the current node in the traversal
                   8248:  *
                   8249:  * Traversal function for the "preceding" direction
                   8250:  * the preceding axis contains all nodes in the same document as the context
                   8251:  * node that are before the context node in document order, excluding any
                   8252:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
                   8253:  * ordered in reverse document order
                   8254:  * This is a faster implementation but internal only since it requires a
                   8255:  * state kept in the parser context: ctxt->ancestor.
                   8256:  *
                   8257:  * Returns the next element following that axis
                   8258:  */
                   8259: static xmlNodePtr
                   8260: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
                   8261:                               xmlNodePtr cur)
                   8262: {
                   8263:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8264:     if (cur == NULL) {
                   8265:         cur = ctxt->context->node;
                   8266:         if (cur == NULL)
                   8267:             return (NULL);
                   8268:         if (cur->type == XML_NAMESPACE_DECL)
                   8269:             return (NULL);
                   8270:         ctxt->ancestor = cur->parent;
                   8271:     }
                   8272:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
                   8273:        cur = cur->prev;
                   8274:     while (cur->prev == NULL) {
                   8275:         cur = cur->parent;
                   8276:         if (cur == NULL)
                   8277:             return (NULL);
                   8278:         if (cur == ctxt->context->doc->children)
                   8279:             return (NULL);
                   8280:         if (cur != ctxt->ancestor)
                   8281:             return (cur);
                   8282:         ctxt->ancestor = cur->parent;
                   8283:     }
                   8284:     cur = cur->prev;
                   8285:     while (cur->last != NULL)
                   8286:         cur = cur->last;
                   8287:     return (cur);
                   8288: }
                   8289: 
                   8290: /**
                   8291:  * xmlXPathNextNamespace:
                   8292:  * @ctxt:  the XPath Parser context
                   8293:  * @cur:  the current attribute in the traversal
                   8294:  *
                   8295:  * Traversal function for the "namespace" direction
                   8296:  * the namespace axis contains the namespace nodes of the context node;
                   8297:  * the order of nodes on this axis is implementation-defined; the axis will
                   8298:  * be empty unless the context node is an element
                   8299:  *
                   8300:  * We keep the XML namespace node at the end of the list.
                   8301:  *
                   8302:  * Returns the next element following that axis
                   8303:  */
                   8304: xmlNodePtr
                   8305: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8306:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8307:     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
                   8308:     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
                   8309:         if (ctxt->context->tmpNsList != NULL)
                   8310:            xmlFree(ctxt->context->tmpNsList);
                   8311:        ctxt->context->tmpNsList =
                   8312:            xmlGetNsList(ctxt->context->doc, ctxt->context->node);
                   8313:        ctxt->context->tmpNsNr = 0;
                   8314:        if (ctxt->context->tmpNsList != NULL) {
                   8315:            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
                   8316:                ctxt->context->tmpNsNr++;
                   8317:            }
                   8318:        }
                   8319:        return((xmlNodePtr) xmlXPathXMLNamespace);
                   8320:     }
                   8321:     if (ctxt->context->tmpNsNr > 0) {
                   8322:        return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
                   8323:     } else {
                   8324:        if (ctxt->context->tmpNsList != NULL)
                   8325:            xmlFree(ctxt->context->tmpNsList);
                   8326:        ctxt->context->tmpNsList = NULL;
                   8327:        return(NULL);
                   8328:     }
                   8329: }
                   8330: 
                   8331: /**
                   8332:  * xmlXPathNextAttribute:
                   8333:  * @ctxt:  the XPath Parser context
                   8334:  * @cur:  the current attribute in the traversal
                   8335:  *
                   8336:  * Traversal function for the "attribute" direction
                   8337:  * TODO: support DTD inherited default attributes
                   8338:  *
                   8339:  * Returns the next element following that axis
                   8340:  */
                   8341: xmlNodePtr
                   8342: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8343:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8344:     if (ctxt->context->node == NULL)
                   8345:        return(NULL);
                   8346:     if (ctxt->context->node->type != XML_ELEMENT_NODE)
                   8347:        return(NULL);
                   8348:     if (cur == NULL) {
                   8349:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
                   8350:            return(NULL);
                   8351:         return((xmlNodePtr)ctxt->context->node->properties);
                   8352:     }
                   8353:     return((xmlNodePtr)cur->next);
                   8354: }
                   8355: 
                   8356: /************************************************************************
                   8357:  *                                                                     *
                   8358:  *             NodeTest Functions                                      *
                   8359:  *                                                                     *
                   8360:  ************************************************************************/
                   8361: 
                   8362: #define IS_FUNCTION                    200
                   8363: 
                   8364: 
                   8365: /************************************************************************
                   8366:  *                                                                     *
                   8367:  *             Implicit tree core function library                     *
                   8368:  *                                                                     *
                   8369:  ************************************************************************/
                   8370: 
                   8371: /**
                   8372:  * xmlXPathRoot:
                   8373:  * @ctxt:  the XPath Parser context
                   8374:  *
                   8375:  * Initialize the context to the root of the document
                   8376:  */
                   8377: void
                   8378: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
                   8379:     if ((ctxt == NULL) || (ctxt->context == NULL))
                   8380:        return;
                   8381:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
                   8382:     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8383:        ctxt->context->node));
                   8384: }
                   8385: 
                   8386: /************************************************************************
                   8387:  *                                                                     *
                   8388:  *             The explicit core function library                      *
                   8389:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib        *
                   8390:  *                                                                     *
                   8391:  ************************************************************************/
                   8392: 
                   8393: 
                   8394: /**
                   8395:  * xmlXPathLastFunction:
                   8396:  * @ctxt:  the XPath Parser context
                   8397:  * @nargs:  the number of arguments
                   8398:  *
                   8399:  * Implement the last() XPath function
                   8400:  *    number last()
                   8401:  * The last function returns the number of nodes in the context node list.
                   8402:  */
                   8403: void
                   8404: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8405:     CHECK_ARITY(0);
                   8406:     if (ctxt->context->contextSize >= 0) {
                   8407:        valuePush(ctxt,
                   8408:            xmlXPathCacheNewFloat(ctxt->context,
                   8409:                (double) ctxt->context->contextSize));
                   8410: #ifdef DEBUG_EXPR
                   8411:        xmlGenericError(xmlGenericErrorContext,
                   8412:                "last() : %d\n", ctxt->context->contextSize);
                   8413: #endif
                   8414:     } else {
                   8415:        XP_ERROR(XPATH_INVALID_CTXT_SIZE);
                   8416:     }
                   8417: }
                   8418: 
                   8419: /**
                   8420:  * xmlXPathPositionFunction:
                   8421:  * @ctxt:  the XPath Parser context
                   8422:  * @nargs:  the number of arguments
                   8423:  *
                   8424:  * Implement the position() XPath function
                   8425:  *    number position()
                   8426:  * The position function returns the position of the context node in the
                   8427:  * context node list. The first position is 1, and so the last position
                   8428:  * will be equal to last().
                   8429:  */
                   8430: void
                   8431: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8432:     CHECK_ARITY(0);
                   8433:     if (ctxt->context->proximityPosition >= 0) {
                   8434:        valuePush(ctxt,
                   8435:              xmlXPathCacheNewFloat(ctxt->context,
                   8436:                (double) ctxt->context->proximityPosition));
                   8437: #ifdef DEBUG_EXPR
                   8438:        xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
                   8439:                ctxt->context->proximityPosition);
                   8440: #endif
                   8441:     } else {
                   8442:        XP_ERROR(XPATH_INVALID_CTXT_POSITION);
                   8443:     }
                   8444: }
                   8445: 
                   8446: /**
                   8447:  * xmlXPathCountFunction:
                   8448:  * @ctxt:  the XPath Parser context
                   8449:  * @nargs:  the number of arguments
                   8450:  *
                   8451:  * Implement the count() XPath function
                   8452:  *    number count(node-set)
                   8453:  */
                   8454: void
                   8455: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8456:     xmlXPathObjectPtr cur;
                   8457: 
                   8458:     CHECK_ARITY(1);
                   8459:     if ((ctxt->value == NULL) ||
                   8460:        ((ctxt->value->type != XPATH_NODESET) &&
                   8461:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   8462:        XP_ERROR(XPATH_INVALID_TYPE);
                   8463:     cur = valuePop(ctxt);
                   8464: 
                   8465:     if ((cur == NULL) || (cur->nodesetval == NULL))
                   8466:        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
                   8467:     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
                   8468:        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
                   8469:            (double) cur->nodesetval->nodeNr));
                   8470:     } else {
                   8471:        if ((cur->nodesetval->nodeNr != 1) ||
                   8472:            (cur->nodesetval->nodeTab == NULL)) {
                   8473:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
                   8474:        } else {
                   8475:            xmlNodePtr tmp;
                   8476:            int i = 0;
                   8477: 
                   8478:            tmp = cur->nodesetval->nodeTab[0];
                   8479:            if (tmp != NULL) {
                   8480:                tmp = tmp->children;
                   8481:                while (tmp != NULL) {
                   8482:                    tmp = tmp->next;
                   8483:                    i++;
                   8484:                }
                   8485:            }
                   8486:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
                   8487:        }
                   8488:     }
                   8489:     xmlXPathReleaseObject(ctxt->context, cur);
                   8490: }
                   8491: 
                   8492: /**
                   8493:  * xmlXPathGetElementsByIds:
                   8494:  * @doc:  the document
                   8495:  * @ids:  a whitespace separated list of IDs
                   8496:  *
                   8497:  * Selects elements by their unique ID.
                   8498:  *
                   8499:  * Returns a node-set of selected elements.
                   8500:  */
                   8501: static xmlNodeSetPtr
                   8502: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
                   8503:     xmlNodeSetPtr ret;
                   8504:     const xmlChar *cur = ids;
                   8505:     xmlChar *ID;
                   8506:     xmlAttrPtr attr;
                   8507:     xmlNodePtr elem = NULL;
                   8508: 
                   8509:     if (ids == NULL) return(NULL);
                   8510: 
                   8511:     ret = xmlXPathNodeSetCreate(NULL);
                   8512:     if (ret == NULL)
                   8513:         return(ret);
                   8514: 
                   8515:     while (IS_BLANK_CH(*cur)) cur++;
                   8516:     while (*cur != 0) {
                   8517:        while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
                   8518:            cur++;
                   8519: 
                   8520:         ID = xmlStrndup(ids, cur - ids);
                   8521:        if (ID != NULL) {
                   8522:            /*
                   8523:             * We used to check the fact that the value passed
                   8524:             * was an NCName, but this generated much troubles for
                   8525:             * me and Aleksey Sanin, people blatantly violated that
                   8526:             * constaint, like Visa3D spec.
                   8527:             * if (xmlValidateNCName(ID, 1) == 0)
                   8528:             */
                   8529:            attr = xmlGetID(doc, ID);
                   8530:            if (attr != NULL) {
                   8531:                if (attr->type == XML_ATTRIBUTE_NODE)
                   8532:                    elem = attr->parent;
                   8533:                else if (attr->type == XML_ELEMENT_NODE)
                   8534:                    elem = (xmlNodePtr) attr;
                   8535:                else
                   8536:                    elem = NULL;
                   8537:                if (elem != NULL)
                   8538:                    xmlXPathNodeSetAdd(ret, elem);
                   8539:            }
                   8540:            xmlFree(ID);
                   8541:        }
                   8542: 
                   8543:        while (IS_BLANK_CH(*cur)) cur++;
                   8544:        ids = cur;
                   8545:     }
                   8546:     return(ret);
                   8547: }
                   8548: 
                   8549: /**
                   8550:  * xmlXPathIdFunction:
                   8551:  * @ctxt:  the XPath Parser context
                   8552:  * @nargs:  the number of arguments
                   8553:  *
                   8554:  * Implement the id() XPath function
                   8555:  *    node-set id(object)
                   8556:  * The id function selects elements by their unique ID
                   8557:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
                   8558:  * then the result is the union of the result of applying id to the
                   8559:  * string value of each of the nodes in the argument node-set. When the
                   8560:  * argument to id is of any other type, the argument is converted to a
                   8561:  * string as if by a call to the string function; the string is split
                   8562:  * into a whitespace-separated list of tokens (whitespace is any sequence
                   8563:  * of characters matching the production S); the result is a node-set
                   8564:  * containing the elements in the same document as the context node that
                   8565:  * have a unique ID equal to any of the tokens in the list.
                   8566:  */
                   8567: void
                   8568: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8569:     xmlChar *tokens;
                   8570:     xmlNodeSetPtr ret;
                   8571:     xmlXPathObjectPtr obj;
                   8572: 
                   8573:     CHECK_ARITY(1);
                   8574:     obj = valuePop(ctxt);
                   8575:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   8576:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
                   8577:        xmlNodeSetPtr ns;
                   8578:        int i;
                   8579: 
                   8580:        ret = xmlXPathNodeSetCreate(NULL);
                   8581:         /*
                   8582:          * FIXME -- in an out-of-memory condition this will behave badly.
                   8583:          * The solution is not clear -- we already popped an item from
                   8584:          * ctxt, so the object is in a corrupt state.
                   8585:          */
                   8586: 
                   8587:        if (obj->nodesetval != NULL) {
                   8588:            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
                   8589:                tokens =
                   8590:                    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
                   8591:                ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
                   8592:                ret = xmlXPathNodeSetMerge(ret, ns);
                   8593:                xmlXPathFreeNodeSet(ns);
                   8594:                if (tokens != NULL)
                   8595:                    xmlFree(tokens);
                   8596:            }
                   8597:        }
                   8598:        xmlXPathReleaseObject(ctxt->context, obj);
                   8599:        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
                   8600:        return;
                   8601:     }
                   8602:     obj = xmlXPathCacheConvertString(ctxt->context, obj);
                   8603:     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
                   8604:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
                   8605:     xmlXPathReleaseObject(ctxt->context, obj);
                   8606:     return;
                   8607: }
                   8608: 
                   8609: /**
                   8610:  * xmlXPathLocalNameFunction:
                   8611:  * @ctxt:  the XPath Parser context
                   8612:  * @nargs:  the number of arguments
                   8613:  *
                   8614:  * Implement the local-name() XPath function
                   8615:  *    string local-name(node-set?)
                   8616:  * The local-name function returns a string containing the local part
                   8617:  * of the name of the node in the argument node-set that is first in
                   8618:  * document order. If the node-set is empty or the first node has no
                   8619:  * name, an empty string is returned. If the argument is omitted it
                   8620:  * defaults to the context node.
                   8621:  */
                   8622: void
                   8623: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8624:     xmlXPathObjectPtr cur;
                   8625: 
                   8626:     if (ctxt == NULL) return;
                   8627: 
                   8628:     if (nargs == 0) {
                   8629:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8630:            ctxt->context->node));
                   8631:        nargs = 1;
                   8632:     }
                   8633: 
                   8634:     CHECK_ARITY(1);
                   8635:     if ((ctxt->value == NULL) ||
                   8636:        ((ctxt->value->type != XPATH_NODESET) &&
                   8637:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   8638:        XP_ERROR(XPATH_INVALID_TYPE);
                   8639:     cur = valuePop(ctxt);
                   8640: 
                   8641:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
                   8642:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8643:     } else {
                   8644:        int i = 0; /* Should be first in document order !!!!! */
                   8645:        switch (cur->nodesetval->nodeTab[i]->type) {
                   8646:        case XML_ELEMENT_NODE:
                   8647:        case XML_ATTRIBUTE_NODE:
                   8648:        case XML_PI_NODE:
                   8649:            if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
                   8650:                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8651:            else
                   8652:                valuePush(ctxt,
                   8653:                      xmlXPathCacheNewString(ctxt->context,
                   8654:                        cur->nodesetval->nodeTab[i]->name));
                   8655:            break;
                   8656:        case XML_NAMESPACE_DECL:
                   8657:            valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   8658:                        ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
                   8659:            break;
                   8660:        default:
                   8661:            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8662:        }
                   8663:     }
                   8664:     xmlXPathReleaseObject(ctxt->context, cur);
                   8665: }
                   8666: 
                   8667: /**
                   8668:  * xmlXPathNamespaceURIFunction:
                   8669:  * @ctxt:  the XPath Parser context
                   8670:  * @nargs:  the number of arguments
                   8671:  *
                   8672:  * Implement the namespace-uri() XPath function
                   8673:  *    string namespace-uri(node-set?)
                   8674:  * The namespace-uri function returns a string containing the
                   8675:  * namespace URI of the expanded name of the node in the argument
                   8676:  * node-set that is first in document order. If the node-set is empty,
                   8677:  * the first node has no name, or the expanded name has no namespace
                   8678:  * URI, an empty string is returned. If the argument is omitted it
                   8679:  * defaults to the context node.
                   8680:  */
                   8681: void
                   8682: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8683:     xmlXPathObjectPtr cur;
                   8684: 
                   8685:     if (ctxt == NULL) return;
                   8686: 
                   8687:     if (nargs == 0) {
                   8688:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8689:            ctxt->context->node));
                   8690:        nargs = 1;
                   8691:     }
                   8692:     CHECK_ARITY(1);
                   8693:     if ((ctxt->value == NULL) ||
                   8694:        ((ctxt->value->type != XPATH_NODESET) &&
                   8695:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   8696:        XP_ERROR(XPATH_INVALID_TYPE);
                   8697:     cur = valuePop(ctxt);
                   8698: 
                   8699:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
                   8700:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8701:     } else {
                   8702:        int i = 0; /* Should be first in document order !!!!! */
                   8703:        switch (cur->nodesetval->nodeTab[i]->type) {
                   8704:        case XML_ELEMENT_NODE:
                   8705:        case XML_ATTRIBUTE_NODE:
                   8706:            if (cur->nodesetval->nodeTab[i]->ns == NULL)
                   8707:                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8708:            else
                   8709:                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   8710:                          cur->nodesetval->nodeTab[i]->ns->href));
                   8711:            break;
                   8712:        default:
                   8713:            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8714:        }
                   8715:     }
                   8716:     xmlXPathReleaseObject(ctxt->context, cur);
                   8717: }
                   8718: 
                   8719: /**
                   8720:  * xmlXPathNameFunction:
                   8721:  * @ctxt:  the XPath Parser context
                   8722:  * @nargs:  the number of arguments
                   8723:  *
                   8724:  * Implement the name() XPath function
                   8725:  *    string name(node-set?)
                   8726:  * The name function returns a string containing a QName representing
                   8727:  * the name of the node in the argument node-set that is first in document
                   8728:  * order. The QName must represent the name with respect to the namespace
                   8729:  * declarations in effect on the node whose name is being represented.
                   8730:  * Typically, this will be the form in which the name occurred in the XML
                   8731:  * source. This need not be the case if there are namespace declarations
                   8732:  * in effect on the node that associate multiple prefixes with the same
                   8733:  * namespace. However, an implementation may include information about
                   8734:  * the original prefix in its representation of nodes; in this case, an
                   8735:  * implementation can ensure that the returned string is always the same
                   8736:  * as the QName used in the XML source. If the argument it omitted it
                   8737:  * defaults to the context node.
                   8738:  * Libxml keep the original prefix so the "real qualified name" used is
                   8739:  * returned.
                   8740:  */
                   8741: static void
                   8742: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
                   8743: {
                   8744:     xmlXPathObjectPtr cur;
                   8745: 
                   8746:     if (nargs == 0) {
                   8747:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8748:            ctxt->context->node));
                   8749:         nargs = 1;
                   8750:     }
                   8751: 
                   8752:     CHECK_ARITY(1);
                   8753:     if ((ctxt->value == NULL) ||
                   8754:         ((ctxt->value->type != XPATH_NODESET) &&
                   8755:          (ctxt->value->type != XPATH_XSLT_TREE)))
                   8756:         XP_ERROR(XPATH_INVALID_TYPE);
                   8757:     cur = valuePop(ctxt);
                   8758: 
                   8759:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
                   8760:         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8761:     } else {
                   8762:         int i = 0;              /* Should be first in document order !!!!! */
                   8763: 
                   8764:         switch (cur->nodesetval->nodeTab[i]->type) {
                   8765:             case XML_ELEMENT_NODE:
                   8766:             case XML_ATTRIBUTE_NODE:
                   8767:                if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
                   8768:                    valuePush(ctxt,
                   8769:                        xmlXPathCacheNewCString(ctxt->context, ""));
                   8770:                else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
                   8771:                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
                   8772:                    valuePush(ctxt,
                   8773:                        xmlXPathCacheNewString(ctxt->context,
                   8774:                            cur->nodesetval->nodeTab[i]->name));
                   8775:                } else {
                   8776:                    xmlChar *fullname;
                   8777: 
                   8778:                    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
                   8779:                                     cur->nodesetval->nodeTab[i]->ns->prefix,
                   8780:                                     NULL, 0);
                   8781:                    if (fullname == cur->nodesetval->nodeTab[i]->name)
                   8782:                        fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
                   8783:                    if (fullname == NULL) {
                   8784:                        XP_ERROR(XPATH_MEMORY_ERROR);
                   8785:                    }
                   8786:                    valuePush(ctxt, xmlXPathCacheWrapString(
                   8787:                        ctxt->context, fullname));
                   8788:                 }
                   8789:                 break;
                   8790:             default:
                   8791:                valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8792:                    cur->nodesetval->nodeTab[i]));
                   8793:                 xmlXPathLocalNameFunction(ctxt, 1);
                   8794:         }
                   8795:     }
                   8796:     xmlXPathReleaseObject(ctxt->context, cur);
                   8797: }
                   8798: 
                   8799: 
                   8800: /**
                   8801:  * xmlXPathStringFunction:
                   8802:  * @ctxt:  the XPath Parser context
                   8803:  * @nargs:  the number of arguments
                   8804:  *
                   8805:  * Implement the string() XPath function
                   8806:  *    string string(object?)
                   8807:  * The string function converts an object to a string as follows:
                   8808:  *    - A node-set is converted to a string by returning the value of
                   8809:  *      the node in the node-set that is first in document order.
                   8810:  *      If the node-set is empty, an empty string is returned.
                   8811:  *    - A number is converted to a string as follows
                   8812:  *      + NaN is converted to the string NaN
                   8813:  *      + positive zero is converted to the string 0
                   8814:  *      + negative zero is converted to the string 0
                   8815:  *      + positive infinity is converted to the string Infinity
                   8816:  *      + negative infinity is converted to the string -Infinity
                   8817:  *      + if the number is an integer, the number is represented in
                   8818:  *        decimal form as a Number with no decimal point and no leading
                   8819:  *        zeros, preceded by a minus sign (-) if the number is negative
                   8820:  *      + otherwise, the number is represented in decimal form as a
                   8821:  *        Number including a decimal point with at least one digit
                   8822:  *        before the decimal point and at least one digit after the
                   8823:  *        decimal point, preceded by a minus sign (-) if the number
                   8824:  *        is negative; there must be no leading zeros before the decimal
                   8825:  *        point apart possibly from the one required digit immediately
                   8826:  *        before the decimal point; beyond the one required digit
                   8827:  *        after the decimal point there must be as many, but only as
                   8828:  *        many, more digits as are needed to uniquely distinguish the
                   8829:  *        number from all other IEEE 754 numeric values.
                   8830:  *    - The boolean false value is converted to the string false.
                   8831:  *      The boolean true value is converted to the string true.
                   8832:  *
                   8833:  * If the argument is omitted, it defaults to a node-set with the
                   8834:  * context node as its only member.
                   8835:  */
                   8836: void
                   8837: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8838:     xmlXPathObjectPtr cur;
                   8839: 
                   8840:     if (ctxt == NULL) return;
                   8841:     if (nargs == 0) {
                   8842:     valuePush(ctxt,
                   8843:        xmlXPathCacheWrapString(ctxt->context,
                   8844:            xmlXPathCastNodeToString(ctxt->context->node)));
                   8845:        return;
                   8846:     }
                   8847: 
                   8848:     CHECK_ARITY(1);
                   8849:     cur = valuePop(ctxt);
                   8850:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   8851:     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
                   8852: }
                   8853: 
                   8854: /**
                   8855:  * xmlXPathStringLengthFunction:
                   8856:  * @ctxt:  the XPath Parser context
                   8857:  * @nargs:  the number of arguments
                   8858:  *
                   8859:  * Implement the string-length() XPath function
                   8860:  *    number string-length(string?)
                   8861:  * The string-length returns the number of characters in the string
                   8862:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
                   8863:  * the context node converted to a string, in other words the value
                   8864:  * of the context node.
                   8865:  */
                   8866: void
                   8867: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8868:     xmlXPathObjectPtr cur;
                   8869: 
                   8870:     if (nargs == 0) {
                   8871:         if ((ctxt == NULL) || (ctxt->context == NULL))
                   8872:            return;
                   8873:        if (ctxt->context->node == NULL) {
                   8874:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
                   8875:        } else {
                   8876:            xmlChar *content;
                   8877: 
                   8878:            content = xmlXPathCastNodeToString(ctxt->context->node);
                   8879:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
                   8880:                xmlUTF8Strlen(content)));
                   8881:            xmlFree(content);
                   8882:        }
                   8883:        return;
                   8884:     }
                   8885:     CHECK_ARITY(1);
                   8886:     CAST_TO_STRING;
                   8887:     CHECK_TYPE(XPATH_STRING);
                   8888:     cur = valuePop(ctxt);
                   8889:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
                   8890:        xmlUTF8Strlen(cur->stringval)));
                   8891:     xmlXPathReleaseObject(ctxt->context, cur);
                   8892: }
                   8893: 
                   8894: /**
                   8895:  * xmlXPathConcatFunction:
                   8896:  * @ctxt:  the XPath Parser context
                   8897:  * @nargs:  the number of arguments
                   8898:  *
                   8899:  * Implement the concat() XPath function
                   8900:  *    string concat(string, string, string*)
                   8901:  * The concat function returns the concatenation of its arguments.
                   8902:  */
                   8903: void
                   8904: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8905:     xmlXPathObjectPtr cur, newobj;
                   8906:     xmlChar *tmp;
                   8907: 
                   8908:     if (ctxt == NULL) return;
                   8909:     if (nargs < 2) {
                   8910:        CHECK_ARITY(2);
                   8911:     }
                   8912: 
                   8913:     CAST_TO_STRING;
                   8914:     cur = valuePop(ctxt);
                   8915:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
                   8916:        xmlXPathReleaseObject(ctxt->context, cur);
                   8917:        return;
                   8918:     }
                   8919:     nargs--;
                   8920: 
                   8921:     while (nargs > 0) {
                   8922:        CAST_TO_STRING;
                   8923:        newobj = valuePop(ctxt);
                   8924:        if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
                   8925:            xmlXPathReleaseObject(ctxt->context, newobj);
                   8926:            xmlXPathReleaseObject(ctxt->context, cur);
                   8927:            XP_ERROR(XPATH_INVALID_TYPE);
                   8928:        }
                   8929:        tmp = xmlStrcat(newobj->stringval, cur->stringval);
                   8930:        newobj->stringval = cur->stringval;
                   8931:        cur->stringval = tmp;
                   8932:        xmlXPathReleaseObject(ctxt->context, newobj);
                   8933:        nargs--;
                   8934:     }
                   8935:     valuePush(ctxt, cur);
                   8936: }
                   8937: 
                   8938: /**
                   8939:  * xmlXPathContainsFunction:
                   8940:  * @ctxt:  the XPath Parser context
                   8941:  * @nargs:  the number of arguments
                   8942:  *
                   8943:  * Implement the contains() XPath function
                   8944:  *    boolean contains(string, string)
                   8945:  * The contains function returns true if the first argument string
                   8946:  * contains the second argument string, and otherwise returns false.
                   8947:  */
                   8948: void
                   8949: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8950:     xmlXPathObjectPtr hay, needle;
                   8951: 
                   8952:     CHECK_ARITY(2);
                   8953:     CAST_TO_STRING;
                   8954:     CHECK_TYPE(XPATH_STRING);
                   8955:     needle = valuePop(ctxt);
                   8956:     CAST_TO_STRING;
                   8957:     hay = valuePop(ctxt);
                   8958: 
                   8959:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
                   8960:        xmlXPathReleaseObject(ctxt->context, hay);
                   8961:        xmlXPathReleaseObject(ctxt->context, needle);
                   8962:        XP_ERROR(XPATH_INVALID_TYPE);
                   8963:     }
                   8964:     if (xmlStrstr(hay->stringval, needle->stringval))
                   8965:        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
                   8966:     else
                   8967:        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
                   8968:     xmlXPathReleaseObject(ctxt->context, hay);
                   8969:     xmlXPathReleaseObject(ctxt->context, needle);
                   8970: }
                   8971: 
                   8972: /**
                   8973:  * xmlXPathStartsWithFunction:
                   8974:  * @ctxt:  the XPath Parser context
                   8975:  * @nargs:  the number of arguments
                   8976:  *
                   8977:  * Implement the starts-with() XPath function
                   8978:  *    boolean starts-with(string, string)
                   8979:  * The starts-with function returns true if the first argument string
                   8980:  * starts with the second argument string, and otherwise returns false.
                   8981:  */
                   8982: void
                   8983: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8984:     xmlXPathObjectPtr hay, needle;
                   8985:     int n;
                   8986: 
                   8987:     CHECK_ARITY(2);
                   8988:     CAST_TO_STRING;
                   8989:     CHECK_TYPE(XPATH_STRING);
                   8990:     needle = valuePop(ctxt);
                   8991:     CAST_TO_STRING;
                   8992:     hay = valuePop(ctxt);
                   8993: 
                   8994:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
                   8995:        xmlXPathReleaseObject(ctxt->context, hay);
                   8996:        xmlXPathReleaseObject(ctxt->context, needle);
                   8997:        XP_ERROR(XPATH_INVALID_TYPE);
                   8998:     }
                   8999:     n = xmlStrlen(needle->stringval);
                   9000:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
                   9001:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
                   9002:     else
                   9003:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
                   9004:     xmlXPathReleaseObject(ctxt->context, hay);
                   9005:     xmlXPathReleaseObject(ctxt->context, needle);
                   9006: }
                   9007: 
                   9008: /**
                   9009:  * xmlXPathSubstringFunction:
                   9010:  * @ctxt:  the XPath Parser context
                   9011:  * @nargs:  the number of arguments
                   9012:  *
                   9013:  * Implement the substring() XPath function
                   9014:  *    string substring(string, number, number?)
                   9015:  * The substring function returns the substring of the first argument
                   9016:  * starting at the position specified in the second argument with
                   9017:  * length specified in the third argument. For example,
                   9018:  * substring("12345",2,3) returns "234". If the third argument is not
                   9019:  * specified, it returns the substring starting at the position specified
                   9020:  * in the second argument and continuing to the end of the string. For
                   9021:  * example, substring("12345",2) returns "2345".  More precisely, each
                   9022:  * character in the string (see [3.6 Strings]) is considered to have a
                   9023:  * numeric position: the position of the first character is 1, the position
                   9024:  * of the second character is 2 and so on. The returned substring contains
                   9025:  * those characters for which the position of the character is greater than
                   9026:  * or equal to the second argument and, if the third argument is specified,
                   9027:  * less than the sum of the second and third arguments; the comparisons
                   9028:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
                   9029:  *  - substring("12345", 1.5, 2.6) returns "234"
                   9030:  *  - substring("12345", 0, 3) returns "12"
                   9031:  *  - substring("12345", 0 div 0, 3) returns ""
                   9032:  *  - substring("12345", 1, 0 div 0) returns ""
                   9033:  *  - substring("12345", -42, 1 div 0) returns "12345"
                   9034:  *  - substring("12345", -1 div 0, 1 div 0) returns ""
                   9035:  */
                   9036: void
                   9037: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9038:     xmlXPathObjectPtr str, start, len;
                   9039:     double le=0, in;
                   9040:     int i, l, m;
                   9041:     xmlChar *ret;
                   9042: 
                   9043:     if (nargs < 2) {
                   9044:        CHECK_ARITY(2);
                   9045:     }
                   9046:     if (nargs > 3) {
                   9047:        CHECK_ARITY(3);
                   9048:     }
                   9049:     /*
                   9050:      * take care of possible last (position) argument
                   9051:     */
                   9052:     if (nargs == 3) {
                   9053:        CAST_TO_NUMBER;
                   9054:        CHECK_TYPE(XPATH_NUMBER);
                   9055:        len = valuePop(ctxt);
                   9056:        le = len->floatval;
                   9057:        xmlXPathReleaseObject(ctxt->context, len);
                   9058:     }
                   9059: 
                   9060:     CAST_TO_NUMBER;
                   9061:     CHECK_TYPE(XPATH_NUMBER);
                   9062:     start = valuePop(ctxt);
                   9063:     in = start->floatval;
                   9064:     xmlXPathReleaseObject(ctxt->context, start);
                   9065:     CAST_TO_STRING;
                   9066:     CHECK_TYPE(XPATH_STRING);
                   9067:     str = valuePop(ctxt);
                   9068:     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
                   9069: 
                   9070:     /*
                   9071:      * If last pos not present, calculate last position
                   9072:     */
                   9073:     if (nargs != 3) {
                   9074:        le = (double)m;
                   9075:        if (in < 1.0)
                   9076:            in = 1.0;
                   9077:     }
                   9078: 
                   9079:     /* Need to check for the special cases where either
                   9080:      * the index is NaN, the length is NaN, or both
                   9081:      * arguments are infinity (relying on Inf + -Inf = NaN)
                   9082:      */
                   9083:     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
                   9084:         /*
                   9085:          * To meet the requirements of the spec, the arguments
                   9086:         * must be converted to integer format before
                   9087:         * initial index calculations are done
                   9088:          *
                   9089:          * First we go to integer form, rounding up
                   9090:         * and checking for special cases
                   9091:          */
                   9092:         i = (int) in;
                   9093:         if (((double)i)+0.5 <= in) i++;
                   9094: 
                   9095:        if (xmlXPathIsInf(le) == 1) {
                   9096:            l = m;
                   9097:            if (i < 1)
                   9098:                i = 1;
                   9099:        }
                   9100:        else if (xmlXPathIsInf(le) == -1 || le < 0.0)
                   9101:            l = 0;
                   9102:        else {
                   9103:            l = (int) le;
                   9104:            if (((double)l)+0.5 <= le) l++;
                   9105:        }
                   9106: 
                   9107:        /* Now we normalize inidices */
                   9108:         i -= 1;
                   9109:         l += i;
                   9110:         if (i < 0)
                   9111:             i = 0;
                   9112:         if (l > m)
                   9113:             l = m;
                   9114: 
                   9115:         /* number of chars to copy */
                   9116:         l -= i;
                   9117: 
                   9118:         ret = xmlUTF8Strsub(str->stringval, i, l);
                   9119:     }
                   9120:     else {
                   9121:         ret = NULL;
                   9122:     }
                   9123:     if (ret == NULL)
                   9124:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   9125:     else {
                   9126:        valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
                   9127:        xmlFree(ret);
                   9128:     }
                   9129:     xmlXPathReleaseObject(ctxt->context, str);
                   9130: }
                   9131: 
                   9132: /**
                   9133:  * xmlXPathSubstringBeforeFunction:
                   9134:  * @ctxt:  the XPath Parser context
                   9135:  * @nargs:  the number of arguments
                   9136:  *
                   9137:  * Implement the substring-before() XPath function
                   9138:  *    string substring-before(string, string)
                   9139:  * The substring-before function returns the substring of the first
                   9140:  * argument string that precedes the first occurrence of the second
                   9141:  * argument string in the first argument string, or the empty string
                   9142:  * if the first argument string does not contain the second argument
                   9143:  * string. For example, substring-before("1999/04/01","/") returns 1999.
                   9144:  */
                   9145: void
                   9146: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9147:   xmlXPathObjectPtr str;
                   9148:   xmlXPathObjectPtr find;
                   9149:   xmlBufferPtr target;
                   9150:   const xmlChar *point;
                   9151:   int offset;
                   9152: 
                   9153:   CHECK_ARITY(2);
                   9154:   CAST_TO_STRING;
                   9155:   find = valuePop(ctxt);
                   9156:   CAST_TO_STRING;
                   9157:   str = valuePop(ctxt);
                   9158: 
                   9159:   target = xmlBufferCreate();
                   9160:   if (target) {
                   9161:     point = xmlStrstr(str->stringval, find->stringval);
                   9162:     if (point) {
                   9163:       offset = (int)(point - str->stringval);
                   9164:       xmlBufferAdd(target, str->stringval, offset);
                   9165:     }
                   9166:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   9167:        xmlBufferContent(target)));
                   9168:     xmlBufferFree(target);
                   9169:   }
                   9170:   xmlXPathReleaseObject(ctxt->context, str);
                   9171:   xmlXPathReleaseObject(ctxt->context, find);
                   9172: }
                   9173: 
                   9174: /**
                   9175:  * xmlXPathSubstringAfterFunction:
                   9176:  * @ctxt:  the XPath Parser context
                   9177:  * @nargs:  the number of arguments
                   9178:  *
                   9179:  * Implement the substring-after() XPath function
                   9180:  *    string substring-after(string, string)
                   9181:  * The substring-after function returns the substring of the first
                   9182:  * argument string that follows the first occurrence of the second
                   9183:  * argument string in the first argument string, or the empty stringi
                   9184:  * if the first argument string does not contain the second argument
                   9185:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
                   9186:  * and substring-after("1999/04/01","19") returns 99/04/01.
                   9187:  */
                   9188: void
                   9189: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9190:   xmlXPathObjectPtr str;
                   9191:   xmlXPathObjectPtr find;
                   9192:   xmlBufferPtr target;
                   9193:   const xmlChar *point;
                   9194:   int offset;
                   9195: 
                   9196:   CHECK_ARITY(2);
                   9197:   CAST_TO_STRING;
                   9198:   find = valuePop(ctxt);
                   9199:   CAST_TO_STRING;
                   9200:   str = valuePop(ctxt);
                   9201: 
                   9202:   target = xmlBufferCreate();
                   9203:   if (target) {
                   9204:     point = xmlStrstr(str->stringval, find->stringval);
                   9205:     if (point) {
                   9206:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
                   9207:       xmlBufferAdd(target, &str->stringval[offset],
                   9208:                   xmlStrlen(str->stringval) - offset);
                   9209:     }
                   9210:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   9211:        xmlBufferContent(target)));
                   9212:     xmlBufferFree(target);
                   9213:   }
                   9214:   xmlXPathReleaseObject(ctxt->context, str);
                   9215:   xmlXPathReleaseObject(ctxt->context, find);
                   9216: }
                   9217: 
                   9218: /**
                   9219:  * xmlXPathNormalizeFunction:
                   9220:  * @ctxt:  the XPath Parser context
                   9221:  * @nargs:  the number of arguments
                   9222:  *
                   9223:  * Implement the normalize-space() XPath function
                   9224:  *    string normalize-space(string?)
                   9225:  * The normalize-space function returns the argument string with white
                   9226:  * space normalized by stripping leading and trailing whitespace
                   9227:  * and replacing sequences of whitespace characters by a single
                   9228:  * space. Whitespace characters are the same allowed by the S production
                   9229:  * in XML. If the argument is omitted, it defaults to the context
                   9230:  * node converted to a string, in other words the value of the context node.
                   9231:  */
                   9232: void
                   9233: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9234:   xmlXPathObjectPtr obj = NULL;
                   9235:   xmlChar *source = NULL;
                   9236:   xmlBufferPtr target;
                   9237:   xmlChar blank;
                   9238: 
                   9239:   if (ctxt == NULL) return;
                   9240:   if (nargs == 0) {
                   9241:     /* Use current context node */
                   9242:       valuePush(ctxt,
                   9243:          xmlXPathCacheWrapString(ctxt->context,
                   9244:            xmlXPathCastNodeToString(ctxt->context->node)));
                   9245:     nargs = 1;
                   9246:   }
                   9247: 
                   9248:   CHECK_ARITY(1);
                   9249:   CAST_TO_STRING;
                   9250:   CHECK_TYPE(XPATH_STRING);
                   9251:   obj = valuePop(ctxt);
                   9252:   source = obj->stringval;
                   9253: 
                   9254:   target = xmlBufferCreate();
                   9255:   if (target && source) {
                   9256: 
                   9257:     /* Skip leading whitespaces */
                   9258:     while (IS_BLANK_CH(*source))
                   9259:       source++;
                   9260: 
                   9261:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
                   9262:     blank = 0;
                   9263:     while (*source) {
                   9264:       if (IS_BLANK_CH(*source)) {
                   9265:        blank = 0x20;
                   9266:       } else {
                   9267:        if (blank) {
                   9268:          xmlBufferAdd(target, &blank, 1);
                   9269:          blank = 0;
                   9270:        }
                   9271:        xmlBufferAdd(target, source, 1);
                   9272:       }
                   9273:       source++;
                   9274:     }
                   9275:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   9276:        xmlBufferContent(target)));
                   9277:     xmlBufferFree(target);
                   9278:   }
                   9279:   xmlXPathReleaseObject(ctxt->context, obj);
                   9280: }
                   9281: 
                   9282: /**
                   9283:  * xmlXPathTranslateFunction:
                   9284:  * @ctxt:  the XPath Parser context
                   9285:  * @nargs:  the number of arguments
                   9286:  *
                   9287:  * Implement the translate() XPath function
                   9288:  *    string translate(string, string, string)
                   9289:  * The translate function returns the first argument string with
                   9290:  * occurrences of characters in the second argument string replaced
                   9291:  * by the character at the corresponding position in the third argument
                   9292:  * string. For example, translate("bar","abc","ABC") returns the string
                   9293:  * BAr. If there is a character in the second argument string with no
                   9294:  * character at a corresponding position in the third argument string
                   9295:  * (because the second argument string is longer than the third argument
                   9296:  * string), then occurrences of that character in the first argument
                   9297:  * string are removed. For example, translate("--aaa--","abc-","ABC")
                   9298:  * returns "AAA". If a character occurs more than once in second
                   9299:  * argument string, then the first occurrence determines the replacement
                   9300:  * character. If the third argument string is longer than the second
                   9301:  * argument string, then excess characters are ignored.
                   9302:  */
                   9303: void
                   9304: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9305:     xmlXPathObjectPtr str;
                   9306:     xmlXPathObjectPtr from;
                   9307:     xmlXPathObjectPtr to;
                   9308:     xmlBufferPtr target;
                   9309:     int offset, max;
                   9310:     xmlChar ch;
                   9311:     const xmlChar *point;
                   9312:     xmlChar *cptr;
                   9313: 
                   9314:     CHECK_ARITY(3);
                   9315: 
                   9316:     CAST_TO_STRING;
                   9317:     to = valuePop(ctxt);
                   9318:     CAST_TO_STRING;
                   9319:     from = valuePop(ctxt);
                   9320:     CAST_TO_STRING;
                   9321:     str = valuePop(ctxt);
                   9322: 
                   9323:     target = xmlBufferCreate();
                   9324:     if (target) {
                   9325:        max = xmlUTF8Strlen(to->stringval);
                   9326:        for (cptr = str->stringval; (ch=*cptr); ) {
                   9327:            offset = xmlUTF8Strloc(from->stringval, cptr);
                   9328:            if (offset >= 0) {
                   9329:                if (offset < max) {
                   9330:                    point = xmlUTF8Strpos(to->stringval, offset);
                   9331:                    if (point)
                   9332:                        xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
                   9333:                }
                   9334:            } else
                   9335:                xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
                   9336: 
                   9337:            /* Step to next character in input */
                   9338:            cptr++;
                   9339:            if ( ch & 0x80 ) {
                   9340:                /* if not simple ascii, verify proper format */
                   9341:                if ( (ch & 0xc0) != 0xc0 ) {
                   9342:                    xmlGenericError(xmlGenericErrorContext,
                   9343:                        "xmlXPathTranslateFunction: Invalid UTF8 string\n");
1.1.1.2 ! misho    9344:                     /* not asserting an XPath error is probably better */
1.1       misho    9345:                    break;
                   9346:                }
                   9347:                /* then skip over remaining bytes for this char */
                   9348:                while ( (ch <<= 1) & 0x80 )
                   9349:                    if ( (*cptr++ & 0xc0) != 0x80 ) {
                   9350:                        xmlGenericError(xmlGenericErrorContext,
                   9351:                            "xmlXPathTranslateFunction: Invalid UTF8 string\n");
1.1.1.2 ! misho    9352:                         /* not asserting an XPath error is probably better */
1.1       misho    9353:                        break;
                   9354:                    }
                   9355:                if (ch & 0x80) /* must have had error encountered */
                   9356:                    break;
                   9357:            }
                   9358:        }
                   9359:     }
                   9360:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   9361:        xmlBufferContent(target)));
                   9362:     xmlBufferFree(target);
                   9363:     xmlXPathReleaseObject(ctxt->context, str);
                   9364:     xmlXPathReleaseObject(ctxt->context, from);
                   9365:     xmlXPathReleaseObject(ctxt->context, to);
                   9366: }
                   9367: 
                   9368: /**
                   9369:  * xmlXPathBooleanFunction:
                   9370:  * @ctxt:  the XPath Parser context
                   9371:  * @nargs:  the number of arguments
                   9372:  *
                   9373:  * Implement the boolean() XPath function
                   9374:  *    boolean boolean(object)
                   9375:  * The boolean function converts its argument to a boolean as follows:
                   9376:  *    - a number is true if and only if it is neither positive or
                   9377:  *      negative zero nor NaN
                   9378:  *    - a node-set is true if and only if it is non-empty
                   9379:  *    - a string is true if and only if its length is non-zero
                   9380:  */
                   9381: void
                   9382: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9383:     xmlXPathObjectPtr cur;
                   9384: 
                   9385:     CHECK_ARITY(1);
                   9386:     cur = valuePop(ctxt);
                   9387:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   9388:     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
                   9389:     valuePush(ctxt, cur);
                   9390: }
                   9391: 
                   9392: /**
                   9393:  * xmlXPathNotFunction:
                   9394:  * @ctxt:  the XPath Parser context
                   9395:  * @nargs:  the number of arguments
                   9396:  *
                   9397:  * Implement the not() XPath function
                   9398:  *    boolean not(boolean)
                   9399:  * The not function returns true if its argument is false,
                   9400:  * and false otherwise.
                   9401:  */
                   9402: void
                   9403: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9404:     CHECK_ARITY(1);
                   9405:     CAST_TO_BOOLEAN;
                   9406:     CHECK_TYPE(XPATH_BOOLEAN);
                   9407:     ctxt->value->boolval = ! ctxt->value->boolval;
                   9408: }
                   9409: 
                   9410: /**
                   9411:  * xmlXPathTrueFunction:
                   9412:  * @ctxt:  the XPath Parser context
                   9413:  * @nargs:  the number of arguments
                   9414:  *
                   9415:  * Implement the true() XPath function
                   9416:  *    boolean true()
                   9417:  */
                   9418: void
                   9419: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9420:     CHECK_ARITY(0);
                   9421:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
                   9422: }
                   9423: 
                   9424: /**
                   9425:  * xmlXPathFalseFunction:
                   9426:  * @ctxt:  the XPath Parser context
                   9427:  * @nargs:  the number of arguments
                   9428:  *
                   9429:  * Implement the false() XPath function
                   9430:  *    boolean false()
                   9431:  */
                   9432: void
                   9433: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9434:     CHECK_ARITY(0);
                   9435:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
                   9436: }
                   9437: 
                   9438: /**
                   9439:  * xmlXPathLangFunction:
                   9440:  * @ctxt:  the XPath Parser context
                   9441:  * @nargs:  the number of arguments
                   9442:  *
                   9443:  * Implement the lang() XPath function
                   9444:  *    boolean lang(string)
                   9445:  * The lang function returns true or false depending on whether the
                   9446:  * language of the context node as specified by xml:lang attributes
                   9447:  * is the same as or is a sublanguage of the language specified by
                   9448:  * the argument string. The language of the context node is determined
                   9449:  * by the value of the xml:lang attribute on the context node, or, if
                   9450:  * the context node has no xml:lang attribute, by the value of the
                   9451:  * xml:lang attribute on the nearest ancestor of the context node that
                   9452:  * has an xml:lang attribute. If there is no such attribute, then lang
                   9453:  * returns false. If there is such an attribute, then lang returns
                   9454:  * true if the attribute value is equal to the argument ignoring case,
                   9455:  * or if there is some suffix starting with - such that the attribute
                   9456:  * value is equal to the argument ignoring that suffix of the attribute
                   9457:  * value and ignoring case.
                   9458:  */
                   9459: void
                   9460: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9461:     xmlXPathObjectPtr val = NULL;
                   9462:     const xmlChar *theLang = NULL;
                   9463:     const xmlChar *lang;
                   9464:     int ret = 0;
                   9465:     int i;
                   9466: 
                   9467:     CHECK_ARITY(1);
                   9468:     CAST_TO_STRING;
                   9469:     CHECK_TYPE(XPATH_STRING);
                   9470:     val = valuePop(ctxt);
                   9471:     lang = val->stringval;
                   9472:     theLang = xmlNodeGetLang(ctxt->context->node);
                   9473:     if ((theLang != NULL) && (lang != NULL)) {
                   9474:         for (i = 0;lang[i] != 0;i++)
                   9475:            if (toupper(lang[i]) != toupper(theLang[i]))
                   9476:                goto not_equal;
                   9477:        if ((theLang[i] == 0) || (theLang[i] == '-'))
                   9478:            ret = 1;
                   9479:     }
                   9480: not_equal:
                   9481:     if (theLang != NULL)
                   9482:        xmlFree((void *)theLang);
                   9483: 
                   9484:     xmlXPathReleaseObject(ctxt->context, val);
                   9485:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
                   9486: }
                   9487: 
                   9488: /**
                   9489:  * xmlXPathNumberFunction:
                   9490:  * @ctxt:  the XPath Parser context
                   9491:  * @nargs:  the number of arguments
                   9492:  *
                   9493:  * Implement the number() XPath function
                   9494:  *    number number(object?)
                   9495:  */
                   9496: void
                   9497: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9498:     xmlXPathObjectPtr cur;
                   9499:     double res;
                   9500: 
                   9501:     if (ctxt == NULL) return;
                   9502:     if (nargs == 0) {
                   9503:        if (ctxt->context->node == NULL) {
                   9504:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
                   9505:        } else {
                   9506:            xmlChar* content = xmlNodeGetContent(ctxt->context->node);
                   9507: 
                   9508:            res = xmlXPathStringEvalNumber(content);
                   9509:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
                   9510:            xmlFree(content);
                   9511:        }
                   9512:        return;
                   9513:     }
                   9514: 
                   9515:     CHECK_ARITY(1);
                   9516:     cur = valuePop(ctxt);
                   9517:     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
                   9518: }
                   9519: 
                   9520: /**
                   9521:  * xmlXPathSumFunction:
                   9522:  * @ctxt:  the XPath Parser context
                   9523:  * @nargs:  the number of arguments
                   9524:  *
                   9525:  * Implement the sum() XPath function
                   9526:  *    number sum(node-set)
                   9527:  * The sum function returns the sum of the values of the nodes in
                   9528:  * the argument node-set.
                   9529:  */
                   9530: void
                   9531: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9532:     xmlXPathObjectPtr cur;
                   9533:     int i;
                   9534:     double res = 0.0;
                   9535: 
                   9536:     CHECK_ARITY(1);
                   9537:     if ((ctxt->value == NULL) ||
                   9538:        ((ctxt->value->type != XPATH_NODESET) &&
                   9539:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   9540:        XP_ERROR(XPATH_INVALID_TYPE);
                   9541:     cur = valuePop(ctxt);
                   9542: 
                   9543:     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
                   9544:        for (i = 0; i < cur->nodesetval->nodeNr; i++) {
                   9545:            res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
                   9546:        }
                   9547:     }
                   9548:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
                   9549:     xmlXPathReleaseObject(ctxt->context, cur);
                   9550: }
                   9551: 
                   9552: /*
                   9553:  * To assure working code on multiple platforms, we want to only depend
                   9554:  * upon the characteristic truncation of converting a floating point value
                   9555:  * to an integer.  Unfortunately, because of the different storage sizes
                   9556:  * of our internal floating point value (double) and integer (int), we
                   9557:  * can't directly convert (see bug 301162).  This macro is a messy
                   9558:  * 'workaround'
                   9559:  */
                   9560: #define XTRUNC(f, v)            \
                   9561:     f = fmod((v), INT_MAX);     \
                   9562:     f = (v) - (f) + (double)((int)(f));
                   9563: 
                   9564: /**
                   9565:  * xmlXPathFloorFunction:
                   9566:  * @ctxt:  the XPath Parser context
                   9567:  * @nargs:  the number of arguments
                   9568:  *
                   9569:  * Implement the floor() XPath function
                   9570:  *    number floor(number)
                   9571:  * The floor function returns the largest (closest to positive infinity)
                   9572:  * number that is not greater than the argument and that is an integer.
                   9573:  */
                   9574: void
                   9575: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9576:     double f;
                   9577: 
                   9578:     CHECK_ARITY(1);
                   9579:     CAST_TO_NUMBER;
                   9580:     CHECK_TYPE(XPATH_NUMBER);
                   9581: 
                   9582:     XTRUNC(f, ctxt->value->floatval);
                   9583:     if (f != ctxt->value->floatval) {
                   9584:        if (ctxt->value->floatval > 0)
                   9585:            ctxt->value->floatval = f;
                   9586:        else
                   9587:            ctxt->value->floatval = f - 1;
                   9588:     }
                   9589: }
                   9590: 
                   9591: /**
                   9592:  * xmlXPathCeilingFunction:
                   9593:  * @ctxt:  the XPath Parser context
                   9594:  * @nargs:  the number of arguments
                   9595:  *
                   9596:  * Implement the ceiling() XPath function
                   9597:  *    number ceiling(number)
                   9598:  * The ceiling function returns the smallest (closest to negative infinity)
                   9599:  * number that is not less than the argument and that is an integer.
                   9600:  */
                   9601: void
                   9602: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9603:     double f;
                   9604: 
                   9605:     CHECK_ARITY(1);
                   9606:     CAST_TO_NUMBER;
                   9607:     CHECK_TYPE(XPATH_NUMBER);
                   9608: 
                   9609: #if 0
                   9610:     ctxt->value->floatval = ceil(ctxt->value->floatval);
                   9611: #else
                   9612:     XTRUNC(f, ctxt->value->floatval);
                   9613:     if (f != ctxt->value->floatval) {
                   9614:        if (ctxt->value->floatval > 0)
                   9615:            ctxt->value->floatval = f + 1;
                   9616:        else {
                   9617:            if (ctxt->value->floatval < 0 && f == 0)
                   9618:                ctxt->value->floatval = xmlXPathNZERO;
                   9619:            else
                   9620:                ctxt->value->floatval = f;
                   9621:        }
                   9622: 
                   9623:     }
                   9624: #endif
                   9625: }
                   9626: 
                   9627: /**
                   9628:  * xmlXPathRoundFunction:
                   9629:  * @ctxt:  the XPath Parser context
                   9630:  * @nargs:  the number of arguments
                   9631:  *
                   9632:  * Implement the round() XPath function
                   9633:  *    number round(number)
                   9634:  * The round function returns the number that is closest to the
                   9635:  * argument and that is an integer. If there are two such numbers,
                   9636:  * then the one that is even is returned.
                   9637:  */
                   9638: void
                   9639: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9640:     double f;
                   9641: 
                   9642:     CHECK_ARITY(1);
                   9643:     CAST_TO_NUMBER;
                   9644:     CHECK_TYPE(XPATH_NUMBER);
                   9645: 
                   9646:     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
                   9647:        (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
                   9648:        (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
                   9649:        (ctxt->value->floatval == 0.0))
                   9650:        return;
                   9651: 
                   9652:     XTRUNC(f, ctxt->value->floatval);
                   9653:     if (ctxt->value->floatval < 0) {
                   9654:        if (ctxt->value->floatval < f - 0.5)
                   9655:            ctxt->value->floatval = f - 1;
                   9656:        else
                   9657:            ctxt->value->floatval = f;
                   9658:        if (ctxt->value->floatval == 0)
                   9659:            ctxt->value->floatval = xmlXPathNZERO;
                   9660:     } else {
                   9661:        if (ctxt->value->floatval < f + 0.5)
                   9662:            ctxt->value->floatval = f;
                   9663:        else
                   9664:            ctxt->value->floatval = f + 1;
                   9665:     }
                   9666: }
                   9667: 
                   9668: /************************************************************************
                   9669:  *                                                                     *
                   9670:  *                     The Parser                                      *
                   9671:  *                                                                     *
                   9672:  ************************************************************************/
                   9673: 
                   9674: /*
                   9675:  * a few forward declarations since we use a recursive call based
                   9676:  * implementation.
                   9677:  */
                   9678: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
                   9679: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
                   9680: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
                   9681: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
                   9682: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
                   9683:                                          int qualified);
                   9684: 
                   9685: /**
                   9686:  * xmlXPathCurrentChar:
                   9687:  * @ctxt:  the XPath parser context
                   9688:  * @cur:  pointer to the beginning of the char
                   9689:  * @len:  pointer to the length of the char read
                   9690:  *
                   9691:  * The current char value, if using UTF-8 this may actually span multiple
                   9692:  * bytes in the input buffer.
                   9693:  *
                   9694:  * Returns the current char value and its length
                   9695:  */
                   9696: 
                   9697: static int
                   9698: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
                   9699:     unsigned char c;
                   9700:     unsigned int val;
                   9701:     const xmlChar *cur;
                   9702: 
                   9703:     if (ctxt == NULL)
                   9704:        return(0);
                   9705:     cur = ctxt->cur;
                   9706: 
                   9707:     /*
                   9708:      * We are supposed to handle UTF8, check it's valid
                   9709:      * From rfc2044: encoding of the Unicode values on UTF-8:
                   9710:      *
                   9711:      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
                   9712:      * 0000 0000-0000 007F   0xxxxxxx
                   9713:      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
                   9714:      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
                   9715:      *
                   9716:      * Check for the 0x110000 limit too
                   9717:      */
                   9718:     c = *cur;
                   9719:     if (c & 0x80) {
                   9720:        if ((cur[1] & 0xc0) != 0x80)
                   9721:            goto encoding_error;
                   9722:        if ((c & 0xe0) == 0xe0) {
                   9723: 
                   9724:            if ((cur[2] & 0xc0) != 0x80)
                   9725:                goto encoding_error;
                   9726:            if ((c & 0xf0) == 0xf0) {
                   9727:                if (((c & 0xf8) != 0xf0) ||
                   9728:                    ((cur[3] & 0xc0) != 0x80))
                   9729:                    goto encoding_error;
                   9730:                /* 4-byte code */
                   9731:                *len = 4;
                   9732:                val = (cur[0] & 0x7) << 18;
                   9733:                val |= (cur[1] & 0x3f) << 12;
                   9734:                val |= (cur[2] & 0x3f) << 6;
                   9735:                val |= cur[3] & 0x3f;
                   9736:            } else {
                   9737:              /* 3-byte code */
                   9738:                *len = 3;
                   9739:                val = (cur[0] & 0xf) << 12;
                   9740:                val |= (cur[1] & 0x3f) << 6;
                   9741:                val |= cur[2] & 0x3f;
                   9742:            }
                   9743:        } else {
                   9744:          /* 2-byte code */
                   9745:            *len = 2;
                   9746:            val = (cur[0] & 0x1f) << 6;
                   9747:            val |= cur[1] & 0x3f;
                   9748:        }
                   9749:        if (!IS_CHAR(val)) {
                   9750:            XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
                   9751:        }
                   9752:        return(val);
                   9753:     } else {
                   9754:        /* 1-byte code */
                   9755:        *len = 1;
                   9756:        return((int) *cur);
                   9757:     }
                   9758: encoding_error:
                   9759:     /*
                   9760:      * If we detect an UTF8 error that probably means that the
                   9761:      * input encoding didn't get properly advertised in the
                   9762:      * declaration header. Report the error and switch the encoding
                   9763:      * to ISO-Latin-1 (if you don't like this policy, just declare the
                   9764:      * encoding !)
                   9765:      */
                   9766:     *len = 0;
                   9767:     XP_ERROR0(XPATH_ENCODING_ERROR);
                   9768: }
                   9769: 
                   9770: /**
                   9771:  * xmlXPathParseNCName:
                   9772:  * @ctxt:  the XPath Parser context
                   9773:  *
                   9774:  * parse an XML namespace non qualified name.
                   9775:  *
                   9776:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
                   9777:  *
                   9778:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
                   9779:  *                       CombiningChar | Extender
                   9780:  *
                   9781:  * Returns the namespace name or NULL
                   9782:  */
                   9783: 
                   9784: xmlChar *
                   9785: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
                   9786:     const xmlChar *in;
                   9787:     xmlChar *ret;
                   9788:     int count = 0;
                   9789: 
                   9790:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
                   9791:     /*
                   9792:      * Accelerator for simple ASCII names
                   9793:      */
                   9794:     in = ctxt->cur;
                   9795:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9796:        ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9797:        (*in == '_')) {
                   9798:        in++;
                   9799:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9800:               ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9801:               ((*in >= 0x30) && (*in <= 0x39)) ||
                   9802:               (*in == '_') || (*in == '.') ||
                   9803:               (*in == '-'))
                   9804:            in++;
                   9805:        if ((*in == ' ') || (*in == '>') || (*in == '/') ||
                   9806:             (*in == '[') || (*in == ']') || (*in == ':') ||
                   9807:             (*in == '@') || (*in == '*')) {
                   9808:            count = in - ctxt->cur;
                   9809:            if (count == 0)
                   9810:                return(NULL);
                   9811:            ret = xmlStrndup(ctxt->cur, count);
                   9812:            ctxt->cur = in;
                   9813:            return(ret);
                   9814:        }
                   9815:     }
                   9816:     return(xmlXPathParseNameComplex(ctxt, 0));
                   9817: }
                   9818: 
                   9819: 
                   9820: /**
                   9821:  * xmlXPathParseQName:
                   9822:  * @ctxt:  the XPath Parser context
                   9823:  * @prefix:  a xmlChar **
                   9824:  *
                   9825:  * parse an XML qualified name
                   9826:  *
                   9827:  * [NS 5] QName ::= (Prefix ':')? LocalPart
                   9828:  *
                   9829:  * [NS 6] Prefix ::= NCName
                   9830:  *
                   9831:  * [NS 7] LocalPart ::= NCName
                   9832:  *
                   9833:  * Returns the function returns the local part, and prefix is updated
                   9834:  *   to get the Prefix if any.
                   9835:  */
                   9836: 
                   9837: static xmlChar *
                   9838: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
                   9839:     xmlChar *ret = NULL;
                   9840: 
                   9841:     *prefix = NULL;
                   9842:     ret = xmlXPathParseNCName(ctxt);
                   9843:     if (ret && CUR == ':') {
                   9844:         *prefix = ret;
                   9845:        NEXT;
                   9846:        ret = xmlXPathParseNCName(ctxt);
                   9847:     }
                   9848:     return(ret);
                   9849: }
                   9850: 
                   9851: /**
                   9852:  * xmlXPathParseName:
                   9853:  * @ctxt:  the XPath Parser context
                   9854:  *
                   9855:  * parse an XML name
                   9856:  *
                   9857:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                   9858:  *                  CombiningChar | Extender
                   9859:  *
                   9860:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                   9861:  *
                   9862:  * Returns the namespace name or NULL
                   9863:  */
                   9864: 
                   9865: xmlChar *
                   9866: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
                   9867:     const xmlChar *in;
                   9868:     xmlChar *ret;
                   9869:     int count = 0;
                   9870: 
                   9871:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
                   9872:     /*
                   9873:      * Accelerator for simple ASCII names
                   9874:      */
                   9875:     in = ctxt->cur;
                   9876:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9877:        ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9878:        (*in == '_') || (*in == ':')) {
                   9879:        in++;
                   9880:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9881:               ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9882:               ((*in >= 0x30) && (*in <= 0x39)) ||
                   9883:               (*in == '_') || (*in == '-') ||
                   9884:               (*in == ':') || (*in == '.'))
                   9885:            in++;
                   9886:        if ((*in > 0) && (*in < 0x80)) {
                   9887:            count = in - ctxt->cur;
                   9888:            ret = xmlStrndup(ctxt->cur, count);
                   9889:            ctxt->cur = in;
                   9890:            return(ret);
                   9891:        }
                   9892:     }
                   9893:     return(xmlXPathParseNameComplex(ctxt, 1));
                   9894: }
                   9895: 
                   9896: static xmlChar *
                   9897: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
                   9898:     xmlChar buf[XML_MAX_NAMELEN + 5];
                   9899:     int len = 0, l;
                   9900:     int c;
                   9901: 
                   9902:     /*
                   9903:      * Handler for more complex cases
                   9904:      */
                   9905:     c = CUR_CHAR(l);
                   9906:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
                   9907:         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
                   9908:         (c == '*') || /* accelerators */
                   9909:        (!IS_LETTER(c) && (c != '_') &&
                   9910:          ((qualified) && (c != ':')))) {
                   9911:        return(NULL);
                   9912:     }
                   9913: 
                   9914:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
                   9915:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
                   9916:             (c == '.') || (c == '-') ||
                   9917:            (c == '_') || ((qualified) && (c == ':')) ||
                   9918:            (IS_COMBINING(c)) ||
                   9919:            (IS_EXTENDER(c)))) {
                   9920:        COPY_BUF(l,buf,len,c);
                   9921:        NEXTL(l);
                   9922:        c = CUR_CHAR(l);
                   9923:        if (len >= XML_MAX_NAMELEN) {
                   9924:            /*
                   9925:             * Okay someone managed to make a huge name, so he's ready to pay
                   9926:             * for the processing speed.
                   9927:             */
                   9928:            xmlChar *buffer;
                   9929:            int max = len * 2;
                   9930: 
                   9931:            buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
                   9932:            if (buffer == NULL) {
                   9933:                XP_ERRORNULL(XPATH_MEMORY_ERROR);
                   9934:            }
                   9935:            memcpy(buffer, buf, len);
                   9936:            while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
                   9937:                   (c == '.') || (c == '-') ||
                   9938:                   (c == '_') || ((qualified) && (c == ':')) ||
                   9939:                   (IS_COMBINING(c)) ||
                   9940:                   (IS_EXTENDER(c))) {
                   9941:                if (len + 10 > max) {
                   9942:                    max *= 2;
                   9943:                    buffer = (xmlChar *) xmlRealloc(buffer,
                   9944:                                                    max * sizeof(xmlChar));
                   9945:                    if (buffer == NULL) {
                   9946:                        XP_ERRORNULL(XPATH_MEMORY_ERROR);
                   9947:                    }
                   9948:                }
                   9949:                COPY_BUF(l,buffer,len,c);
                   9950:                NEXTL(l);
                   9951:                c = CUR_CHAR(l);
                   9952:            }
                   9953:            buffer[len] = 0;
                   9954:            return(buffer);
                   9955:        }
                   9956:     }
                   9957:     if (len == 0)
                   9958:        return(NULL);
                   9959:     return(xmlStrndup(buf, len));
                   9960: }
                   9961: 
                   9962: #define MAX_FRAC 20
                   9963: 
                   9964: /*
                   9965:  * These are used as divisors for the fractional part of a number.
                   9966:  * Since the table includes 1.0 (representing '0' fractional digits),
                   9967:  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
                   9968:  */
                   9969: static double my_pow10[MAX_FRAC+1] = {
                   9970:     1.0, 10.0, 100.0, 1000.0, 10000.0,
                   9971:     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
                   9972:     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
                   9973:     100000000000000.0,
                   9974:     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
                   9975:     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
                   9976: };
                   9977: 
                   9978: /**
                   9979:  * xmlXPathStringEvalNumber:
                   9980:  * @str:  A string to scan
                   9981:  *
                   9982:  *  [30a]  Float  ::= Number ('e' Digits?)?
                   9983:  *
                   9984:  *  [30]   Number ::=   Digits ('.' Digits?)?
                   9985:  *                    | '.' Digits
                   9986:  *  [31]   Digits ::=   [0-9]+
                   9987:  *
                   9988:  * Compile a Number in the string
                   9989:  * In complement of the Number expression, this function also handles
                   9990:  * negative values : '-' Number.
                   9991:  *
                   9992:  * Returns the double value.
                   9993:  */
                   9994: double
                   9995: xmlXPathStringEvalNumber(const xmlChar *str) {
                   9996:     const xmlChar *cur = str;
                   9997:     double ret;
                   9998:     int ok = 0;
                   9999:     int isneg = 0;
                   10000:     int exponent = 0;
                   10001:     int is_exponent_negative = 0;
                   10002: #ifdef __GNUC__
                   10003:     unsigned long tmp = 0;
                   10004:     double temp;
                   10005: #endif
                   10006:     if (cur == NULL) return(0);
                   10007:     while (IS_BLANK_CH(*cur)) cur++;
                   10008:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
                   10009:         return(xmlXPathNAN);
                   10010:     }
                   10011:     if (*cur == '-') {
                   10012:        isneg = 1;
                   10013:        cur++;
                   10014:     }
                   10015: 
                   10016: #ifdef __GNUC__
                   10017:     /*
                   10018:      * tmp/temp is a workaround against a gcc compiler bug
                   10019:      * http://veillard.com/gcc.bug
                   10020:      */
                   10021:     ret = 0;
                   10022:     while ((*cur >= '0') && (*cur <= '9')) {
                   10023:        ret = ret * 10;
                   10024:        tmp = (*cur - '0');
                   10025:        ok = 1;
                   10026:        cur++;
                   10027:        temp = (double) tmp;
                   10028:        ret = ret + temp;
                   10029:     }
                   10030: #else
                   10031:     ret = 0;
                   10032:     while ((*cur >= '0') && (*cur <= '9')) {
                   10033:        ret = ret * 10 + (*cur - '0');
                   10034:        ok = 1;
                   10035:        cur++;
                   10036:     }
                   10037: #endif
                   10038: 
                   10039:     if (*cur == '.') {
                   10040:        int v, frac = 0;
                   10041:        double fraction = 0;
                   10042: 
                   10043:         cur++;
                   10044:        if (((*cur < '0') || (*cur > '9')) && (!ok)) {
                   10045:            return(xmlXPathNAN);
                   10046:        }
                   10047:        while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
                   10048:            v = (*cur - '0');
                   10049:            fraction = fraction * 10 + v;
                   10050:            frac = frac + 1;
                   10051:            cur++;
                   10052:        }
                   10053:        fraction /= my_pow10[frac];
                   10054:        ret = ret + fraction;
                   10055:        while ((*cur >= '0') && (*cur <= '9'))
                   10056:            cur++;
                   10057:     }
                   10058:     if ((*cur == 'e') || (*cur == 'E')) {
                   10059:       cur++;
                   10060:       if (*cur == '-') {
                   10061:        is_exponent_negative = 1;
                   10062:        cur++;
                   10063:       } else if (*cur == '+') {
                   10064:         cur++;
                   10065:       }
                   10066:       while ((*cur >= '0') && (*cur <= '9')) {
                   10067:        exponent = exponent * 10 + (*cur - '0');
                   10068:        cur++;
                   10069:       }
                   10070:     }
                   10071:     while (IS_BLANK_CH(*cur)) cur++;
                   10072:     if (*cur != 0) return(xmlXPathNAN);
                   10073:     if (isneg) ret = -ret;
                   10074:     if (is_exponent_negative) exponent = -exponent;
                   10075:     ret *= pow(10.0, (double)exponent);
                   10076:     return(ret);
                   10077: }
                   10078: 
                   10079: /**
                   10080:  * xmlXPathCompNumber:
                   10081:  * @ctxt:  the XPath Parser context
                   10082:  *
                   10083:  *  [30]   Number ::=   Digits ('.' Digits?)?
                   10084:  *                    | '.' Digits
                   10085:  *  [31]   Digits ::=   [0-9]+
                   10086:  *
                   10087:  * Compile a Number, then push it on the stack
                   10088:  *
                   10089:  */
                   10090: static void
                   10091: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
                   10092: {
                   10093:     double ret = 0.0;
                   10094:     int ok = 0;
                   10095:     int exponent = 0;
                   10096:     int is_exponent_negative = 0;
                   10097: #ifdef __GNUC__
                   10098:     unsigned long tmp = 0;
                   10099:     double temp;
                   10100: #endif
                   10101: 
                   10102:     CHECK_ERROR;
                   10103:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
                   10104:         XP_ERROR(XPATH_NUMBER_ERROR);
                   10105:     }
                   10106: #ifdef __GNUC__
                   10107:     /*
                   10108:      * tmp/temp is a workaround against a gcc compiler bug
                   10109:      * http://veillard.com/gcc.bug
                   10110:      */
                   10111:     ret = 0;
                   10112:     while ((CUR >= '0') && (CUR <= '9')) {
                   10113:        ret = ret * 10;
                   10114:        tmp = (CUR - '0');
                   10115:         ok = 1;
                   10116:         NEXT;
                   10117:        temp = (double) tmp;
                   10118:        ret = ret + temp;
                   10119:     }
                   10120: #else
                   10121:     ret = 0;
                   10122:     while ((CUR >= '0') && (CUR <= '9')) {
                   10123:        ret = ret * 10 + (CUR - '0');
                   10124:        ok = 1;
                   10125:        NEXT;
                   10126:     }
                   10127: #endif
                   10128:     if (CUR == '.') {
                   10129:        int v, frac = 0;
                   10130:        double fraction = 0;
                   10131: 
                   10132:         NEXT;
                   10133:         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
                   10134:             XP_ERROR(XPATH_NUMBER_ERROR);
                   10135:         }
                   10136:         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
                   10137:            v = (CUR - '0');
                   10138:            fraction = fraction * 10 + v;
                   10139:            frac = frac + 1;
                   10140:             NEXT;
                   10141:         }
                   10142:         fraction /= my_pow10[frac];
                   10143:         ret = ret + fraction;
                   10144:         while ((CUR >= '0') && (CUR <= '9'))
                   10145:             NEXT;
                   10146:     }
                   10147:     if ((CUR == 'e') || (CUR == 'E')) {
                   10148:         NEXT;
                   10149:         if (CUR == '-') {
                   10150:             is_exponent_negative = 1;
                   10151:             NEXT;
                   10152:         } else if (CUR == '+') {
                   10153:            NEXT;
                   10154:        }
                   10155:         while ((CUR >= '0') && (CUR <= '9')) {
                   10156:             exponent = exponent * 10 + (CUR - '0');
                   10157:             NEXT;
                   10158:         }
                   10159:         if (is_exponent_negative)
                   10160:             exponent = -exponent;
                   10161:         ret *= pow(10.0, (double) exponent);
                   10162:     }
                   10163:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
                   10164:                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
                   10165: }
                   10166: 
                   10167: /**
                   10168:  * xmlXPathParseLiteral:
                   10169:  * @ctxt:  the XPath Parser context
                   10170:  *
                   10171:  * Parse a Literal
                   10172:  *
                   10173:  *  [29]   Literal ::=   '"' [^"]* '"'
                   10174:  *                    | "'" [^']* "'"
                   10175:  *
                   10176:  * Returns the value found or NULL in case of error
                   10177:  */
                   10178: static xmlChar *
                   10179: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
                   10180:     const xmlChar *q;
                   10181:     xmlChar *ret = NULL;
                   10182: 
                   10183:     if (CUR == '"') {
                   10184:         NEXT;
                   10185:        q = CUR_PTR;
                   10186:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
                   10187:            NEXT;
                   10188:        if (!IS_CHAR_CH(CUR)) {
                   10189:            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
                   10190:        } else {
                   10191:            ret = xmlStrndup(q, CUR_PTR - q);
                   10192:            NEXT;
                   10193:         }
                   10194:     } else if (CUR == '\'') {
                   10195:         NEXT;
                   10196:        q = CUR_PTR;
                   10197:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
                   10198:            NEXT;
                   10199:        if (!IS_CHAR_CH(CUR)) {
                   10200:            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
                   10201:        } else {
                   10202:            ret = xmlStrndup(q, CUR_PTR - q);
                   10203:            NEXT;
                   10204:         }
                   10205:     } else {
                   10206:        XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
                   10207:     }
                   10208:     return(ret);
                   10209: }
                   10210: 
                   10211: /**
                   10212:  * xmlXPathCompLiteral:
                   10213:  * @ctxt:  the XPath Parser context
                   10214:  *
                   10215:  * Parse a Literal and push it on the stack.
                   10216:  *
                   10217:  *  [29]   Literal ::=   '"' [^"]* '"'
                   10218:  *                    | "'" [^']* "'"
                   10219:  *
                   10220:  * TODO: xmlXPathCompLiteral memory allocation could be improved.
                   10221:  */
                   10222: static void
                   10223: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
                   10224:     const xmlChar *q;
                   10225:     xmlChar *ret = NULL;
                   10226: 
                   10227:     if (CUR == '"') {
                   10228:         NEXT;
                   10229:        q = CUR_PTR;
                   10230:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
                   10231:            NEXT;
                   10232:        if (!IS_CHAR_CH(CUR)) {
                   10233:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
                   10234:        } else {
                   10235:            ret = xmlStrndup(q, CUR_PTR - q);
                   10236:            NEXT;
                   10237:         }
                   10238:     } else if (CUR == '\'') {
                   10239:         NEXT;
                   10240:        q = CUR_PTR;
                   10241:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
                   10242:            NEXT;
                   10243:        if (!IS_CHAR_CH(CUR)) {
                   10244:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
                   10245:        } else {
                   10246:            ret = xmlStrndup(q, CUR_PTR - q);
                   10247:            NEXT;
                   10248:         }
                   10249:     } else {
                   10250:        XP_ERROR(XPATH_START_LITERAL_ERROR);
                   10251:     }
                   10252:     if (ret == NULL) return;
                   10253:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
                   10254:                   xmlXPathCacheNewString(ctxt->context, ret), NULL);
                   10255:     xmlFree(ret);
                   10256: }
                   10257: 
                   10258: /**
                   10259:  * xmlXPathCompVariableReference:
                   10260:  * @ctxt:  the XPath Parser context
                   10261:  *
                   10262:  * Parse a VariableReference, evaluate it and push it on the stack.
                   10263:  *
                   10264:  * The variable bindings consist of a mapping from variable names
                   10265:  * to variable values. The value of a variable is an object, which can be
                   10266:  * of any of the types that are possible for the value of an expression,
                   10267:  * and may also be of additional types not specified here.
                   10268:  *
                   10269:  * Early evaluation is possible since:
                   10270:  * The variable bindings [...] used to evaluate a subexpression are
                   10271:  * always the same as those used to evaluate the containing expression.
                   10272:  *
                   10273:  *  [36]   VariableReference ::=   '$' QName
                   10274:  */
                   10275: static void
                   10276: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
                   10277:     xmlChar *name;
                   10278:     xmlChar *prefix;
                   10279: 
                   10280:     SKIP_BLANKS;
                   10281:     if (CUR != '$') {
                   10282:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
                   10283:     }
                   10284:     NEXT;
                   10285:     name = xmlXPathParseQName(ctxt, &prefix);
                   10286:     if (name == NULL) {
                   10287:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
                   10288:     }
                   10289:     ctxt->comp->last = -1;
                   10290:     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
                   10291:                   name, prefix);
                   10292:     SKIP_BLANKS;
                   10293:     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
                   10294:        XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
                   10295:     }
                   10296: }
                   10297: 
                   10298: /**
                   10299:  * xmlXPathIsNodeType:
                   10300:  * @name:  a name string
                   10301:  *
                   10302:  * Is the name given a NodeType one.
                   10303:  *
                   10304:  *  [38]   NodeType ::=   'comment'
                   10305:  *                    | 'text'
                   10306:  *                    | 'processing-instruction'
                   10307:  *                    | 'node'
                   10308:  *
                   10309:  * Returns 1 if true 0 otherwise
                   10310:  */
                   10311: int
                   10312: xmlXPathIsNodeType(const xmlChar *name) {
                   10313:     if (name == NULL)
                   10314:        return(0);
                   10315: 
                   10316:     if (xmlStrEqual(name, BAD_CAST "node"))
                   10317:        return(1);
                   10318:     if (xmlStrEqual(name, BAD_CAST "text"))
                   10319:        return(1);
                   10320:     if (xmlStrEqual(name, BAD_CAST "comment"))
                   10321:        return(1);
                   10322:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
                   10323:        return(1);
                   10324:     return(0);
                   10325: }
                   10326: 
                   10327: /**
                   10328:  * xmlXPathCompFunctionCall:
                   10329:  * @ctxt:  the XPath Parser context
                   10330:  *
                   10331:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
                   10332:  *  [17]   Argument ::=   Expr
                   10333:  *
                   10334:  * Compile a function call, the evaluation of all arguments are
                   10335:  * pushed on the stack
                   10336:  */
                   10337: static void
                   10338: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
                   10339:     xmlChar *name;
                   10340:     xmlChar *prefix;
                   10341:     int nbargs = 0;
                   10342:     int sort = 1;
                   10343: 
                   10344:     name = xmlXPathParseQName(ctxt, &prefix);
                   10345:     if (name == NULL) {
                   10346:        xmlFree(prefix);
                   10347:        XP_ERROR(XPATH_EXPR_ERROR);
                   10348:     }
                   10349:     SKIP_BLANKS;
                   10350: #ifdef DEBUG_EXPR
                   10351:     if (prefix == NULL)
                   10352:        xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
                   10353:                        name);
                   10354:     else
                   10355:        xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
                   10356:                        prefix, name);
                   10357: #endif
                   10358: 
                   10359:     if (CUR != '(') {
                   10360:        XP_ERROR(XPATH_EXPR_ERROR);
                   10361:     }
                   10362:     NEXT;
                   10363:     SKIP_BLANKS;
                   10364: 
                   10365:     /*
                   10366:     * Optimization for count(): we don't need the node-set to be sorted.
                   10367:     */
                   10368:     if ((prefix == NULL) && (name[0] == 'c') &&
                   10369:        xmlStrEqual(name, BAD_CAST "count"))
                   10370:     {
                   10371:        sort = 0;
                   10372:     }
                   10373:     ctxt->comp->last = -1;
                   10374:     if (CUR != ')') {
                   10375:        while (CUR != 0) {
                   10376:            int op1 = ctxt->comp->last;
                   10377:            ctxt->comp->last = -1;
                   10378:            xmlXPathCompileExpr(ctxt, sort);
                   10379:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   10380:                xmlFree(name);
                   10381:                xmlFree(prefix);
                   10382:                return;
                   10383:            }
                   10384:            PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
                   10385:            nbargs++;
                   10386:            if (CUR == ')') break;
                   10387:            if (CUR != ',') {
                   10388:                XP_ERROR(XPATH_EXPR_ERROR);
                   10389:            }
                   10390:            NEXT;
                   10391:            SKIP_BLANKS;
                   10392:        }
                   10393:     }
                   10394:     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
                   10395:                   name, prefix);
                   10396:     NEXT;
                   10397:     SKIP_BLANKS;
                   10398: }
                   10399: 
                   10400: /**
                   10401:  * xmlXPathCompPrimaryExpr:
                   10402:  * @ctxt:  the XPath Parser context
                   10403:  *
                   10404:  *  [15]   PrimaryExpr ::=   VariableReference
                   10405:  *                | '(' Expr ')'
                   10406:  *                | Literal
                   10407:  *                | Number
                   10408:  *                | FunctionCall
                   10409:  *
                   10410:  * Compile a primary expression.
                   10411:  */
                   10412: static void
                   10413: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
                   10414:     SKIP_BLANKS;
                   10415:     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
                   10416:     else if (CUR == '(') {
                   10417:        NEXT;
                   10418:        SKIP_BLANKS;
                   10419:        xmlXPathCompileExpr(ctxt, 1);
                   10420:        CHECK_ERROR;
                   10421:        if (CUR != ')') {
                   10422:            XP_ERROR(XPATH_EXPR_ERROR);
                   10423:        }
                   10424:        NEXT;
                   10425:        SKIP_BLANKS;
                   10426:     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
                   10427:        xmlXPathCompNumber(ctxt);
                   10428:     } else if ((CUR == '\'') || (CUR == '"')) {
                   10429:        xmlXPathCompLiteral(ctxt);
                   10430:     } else {
                   10431:        xmlXPathCompFunctionCall(ctxt);
                   10432:     }
                   10433:     SKIP_BLANKS;
                   10434: }
                   10435: 
                   10436: /**
                   10437:  * xmlXPathCompFilterExpr:
                   10438:  * @ctxt:  the XPath Parser context
                   10439:  *
                   10440:  *  [20]   FilterExpr ::=   PrimaryExpr
                   10441:  *               | FilterExpr Predicate
                   10442:  *
                   10443:  * Compile a filter expression.
                   10444:  * Square brackets are used to filter expressions in the same way that
                   10445:  * they are used in location paths. It is an error if the expression to
                   10446:  * be filtered does not evaluate to a node-set. The context node list
                   10447:  * used for evaluating the expression in square brackets is the node-set
                   10448:  * to be filtered listed in document order.
                   10449:  */
                   10450: 
                   10451: static void
                   10452: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
                   10453:     xmlXPathCompPrimaryExpr(ctxt);
                   10454:     CHECK_ERROR;
                   10455:     SKIP_BLANKS;
                   10456: 
                   10457:     while (CUR == '[') {
                   10458:        xmlXPathCompPredicate(ctxt, 1);
                   10459:        SKIP_BLANKS;
                   10460:     }
                   10461: 
                   10462: 
                   10463: }
                   10464: 
                   10465: /**
                   10466:  * xmlXPathScanName:
                   10467:  * @ctxt:  the XPath Parser context
                   10468:  *
                   10469:  * Trickery: parse an XML name but without consuming the input flow
                   10470:  * Needed to avoid insanity in the parser state.
                   10471:  *
                   10472:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                   10473:  *                  CombiningChar | Extender
                   10474:  *
                   10475:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                   10476:  *
                   10477:  * [6] Names ::= Name (S Name)*
                   10478:  *
                   10479:  * Returns the Name parsed or NULL
                   10480:  */
                   10481: 
                   10482: static xmlChar *
                   10483: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
                   10484:     int len = 0, l;
                   10485:     int c;
                   10486:     const xmlChar *cur;
                   10487:     xmlChar *ret;
                   10488: 
                   10489:     cur = ctxt->cur;
                   10490: 
                   10491:     c = CUR_CHAR(l);
                   10492:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
                   10493:        (!IS_LETTER(c) && (c != '_') &&
                   10494:          (c != ':'))) {
                   10495:        return(NULL);
                   10496:     }
                   10497: 
                   10498:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
                   10499:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
                   10500:             (c == '.') || (c == '-') ||
                   10501:            (c == '_') || (c == ':') ||
                   10502:            (IS_COMBINING(c)) ||
                   10503:            (IS_EXTENDER(c)))) {
                   10504:        len += l;
                   10505:        NEXTL(l);
                   10506:        c = CUR_CHAR(l);
                   10507:     }
                   10508:     ret = xmlStrndup(cur, ctxt->cur - cur);
                   10509:     ctxt->cur = cur;
                   10510:     return(ret);
                   10511: }
                   10512: 
                   10513: /**
                   10514:  * xmlXPathCompPathExpr:
                   10515:  * @ctxt:  the XPath Parser context
                   10516:  *
                   10517:  *  [19]   PathExpr ::=   LocationPath
                   10518:  *               | FilterExpr
                   10519:  *               | FilterExpr '/' RelativeLocationPath
                   10520:  *               | FilterExpr '//' RelativeLocationPath
                   10521:  *
                   10522:  * Compile a path expression.
                   10523:  * The / operator and // operators combine an arbitrary expression
                   10524:  * and a relative location path. It is an error if the expression
                   10525:  * does not evaluate to a node-set.
                   10526:  * The / operator does composition in the same way as when / is
                   10527:  * used in a location path. As in location paths, // is short for
                   10528:  * /descendant-or-self::node()/.
                   10529:  */
                   10530: 
                   10531: static void
                   10532: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
                   10533:     int lc = 1;           /* Should we branch to LocationPath ?         */
                   10534:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
                   10535: 
                   10536:     SKIP_BLANKS;
                   10537:     if ((CUR == '$') || (CUR == '(') ||
                   10538:        (IS_ASCII_DIGIT(CUR)) ||
                   10539:         (CUR == '\'') || (CUR == '"') ||
                   10540:        (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
                   10541:        lc = 0;
                   10542:     } else if (CUR == '*') {
                   10543:        /* relative or absolute location path */
                   10544:        lc = 1;
                   10545:     } else if (CUR == '/') {
                   10546:        /* relative or absolute location path */
                   10547:        lc = 1;
                   10548:     } else if (CUR == '@') {
                   10549:        /* relative abbreviated attribute location path */
                   10550:        lc = 1;
                   10551:     } else if (CUR == '.') {
                   10552:        /* relative abbreviated attribute location path */
                   10553:        lc = 1;
                   10554:     } else {
                   10555:        /*
                   10556:         * Problem is finding if we have a name here whether it's:
                   10557:         *   - a nodetype
                   10558:         *   - a function call in which case it's followed by '('
                   10559:         *   - an axis in which case it's followed by ':'
                   10560:         *   - a element name
                   10561:         * We do an a priori analysis here rather than having to
                   10562:         * maintain parsed token content through the recursive function
                   10563:         * calls. This looks uglier but makes the code easier to
                   10564:         * read/write/debug.
                   10565:         */
                   10566:        SKIP_BLANKS;
                   10567:        name = xmlXPathScanName(ctxt);
                   10568:        if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
                   10569: #ifdef DEBUG_STEP
                   10570:            xmlGenericError(xmlGenericErrorContext,
                   10571:                    "PathExpr: Axis\n");
                   10572: #endif
                   10573:            lc = 1;
                   10574:            xmlFree(name);
                   10575:        } else if (name != NULL) {
                   10576:            int len =xmlStrlen(name);
                   10577: 
                   10578: 
                   10579:            while (NXT(len) != 0) {
                   10580:                if (NXT(len) == '/') {
                   10581:                    /* element name */
                   10582: #ifdef DEBUG_STEP
                   10583:                    xmlGenericError(xmlGenericErrorContext,
                   10584:                            "PathExpr: AbbrRelLocation\n");
                   10585: #endif
                   10586:                    lc = 1;
                   10587:                    break;
                   10588:                } else if (IS_BLANK_CH(NXT(len))) {
                   10589:                    /* ignore blanks */
                   10590:                    ;
                   10591:                } else if (NXT(len) == ':') {
                   10592: #ifdef DEBUG_STEP
                   10593:                    xmlGenericError(xmlGenericErrorContext,
                   10594:                            "PathExpr: AbbrRelLocation\n");
                   10595: #endif
                   10596:                    lc = 1;
                   10597:                    break;
                   10598:                } else if ((NXT(len) == '(')) {
                   10599:                    /* Note Type or Function */
                   10600:                    if (xmlXPathIsNodeType(name)) {
                   10601: #ifdef DEBUG_STEP
                   10602:                        xmlGenericError(xmlGenericErrorContext,
                   10603:                                "PathExpr: Type search\n");
                   10604: #endif
                   10605:                        lc = 1;
                   10606:                    } else {
                   10607: #ifdef DEBUG_STEP
                   10608:                        xmlGenericError(xmlGenericErrorContext,
                   10609:                                "PathExpr: function call\n");
                   10610: #endif
                   10611:                        lc = 0;
                   10612:                    }
                   10613:                     break;
                   10614:                } else if ((NXT(len) == '[')) {
                   10615:                    /* element name */
                   10616: #ifdef DEBUG_STEP
                   10617:                    xmlGenericError(xmlGenericErrorContext,
                   10618:                            "PathExpr: AbbrRelLocation\n");
                   10619: #endif
                   10620:                    lc = 1;
                   10621:                    break;
                   10622:                } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
                   10623:                           (NXT(len) == '=')) {
                   10624:                    lc = 1;
                   10625:                    break;
                   10626:                } else {
                   10627:                    lc = 1;
                   10628:                    break;
                   10629:                }
                   10630:                len++;
                   10631:            }
                   10632:            if (NXT(len) == 0) {
                   10633: #ifdef DEBUG_STEP
                   10634:                xmlGenericError(xmlGenericErrorContext,
                   10635:                        "PathExpr: AbbrRelLocation\n");
                   10636: #endif
                   10637:                /* element name */
                   10638:                lc = 1;
                   10639:            }
                   10640:            xmlFree(name);
                   10641:        } else {
                   10642:            /* make sure all cases are covered explicitly */
                   10643:            XP_ERROR(XPATH_EXPR_ERROR);
                   10644:        }
                   10645:     }
                   10646: 
                   10647:     if (lc) {
                   10648:        if (CUR == '/') {
                   10649:            PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
                   10650:        } else {
                   10651:            PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
                   10652:        }
                   10653:        xmlXPathCompLocationPath(ctxt);
                   10654:     } else {
                   10655:        xmlXPathCompFilterExpr(ctxt);
                   10656:        CHECK_ERROR;
                   10657:        if ((CUR == '/') && (NXT(1) == '/')) {
                   10658:            SKIP(2);
                   10659:            SKIP_BLANKS;
                   10660: 
                   10661:            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   10662:                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   10663:            PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
                   10664: 
                   10665:            xmlXPathCompRelativeLocationPath(ctxt);
                   10666:        } else if (CUR == '/') {
                   10667:            xmlXPathCompRelativeLocationPath(ctxt);
                   10668:        }
                   10669:     }
                   10670:     SKIP_BLANKS;
                   10671: }
                   10672: 
                   10673: /**
                   10674:  * xmlXPathCompUnionExpr:
                   10675:  * @ctxt:  the XPath Parser context
                   10676:  *
                   10677:  *  [18]   UnionExpr ::=   PathExpr
                   10678:  *               | UnionExpr '|' PathExpr
                   10679:  *
                   10680:  * Compile an union expression.
                   10681:  */
                   10682: 
                   10683: static void
                   10684: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
                   10685:     xmlXPathCompPathExpr(ctxt);
                   10686:     CHECK_ERROR;
                   10687:     SKIP_BLANKS;
                   10688:     while (CUR == '|') {
                   10689:        int op1 = ctxt->comp->last;
                   10690:        PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
                   10691: 
                   10692:        NEXT;
                   10693:        SKIP_BLANKS;
                   10694:        xmlXPathCompPathExpr(ctxt);
                   10695: 
                   10696:        PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
                   10697: 
                   10698:        SKIP_BLANKS;
                   10699:     }
                   10700: }
                   10701: 
                   10702: /**
                   10703:  * xmlXPathCompUnaryExpr:
                   10704:  * @ctxt:  the XPath Parser context
                   10705:  *
                   10706:  *  [27]   UnaryExpr ::=   UnionExpr
                   10707:  *                   | '-' UnaryExpr
                   10708:  *
                   10709:  * Compile an unary expression.
                   10710:  */
                   10711: 
                   10712: static void
                   10713: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
                   10714:     int minus = 0;
                   10715:     int found = 0;
                   10716: 
                   10717:     SKIP_BLANKS;
                   10718:     while (CUR == '-') {
                   10719:         minus = 1 - minus;
                   10720:        found = 1;
                   10721:        NEXT;
                   10722:        SKIP_BLANKS;
                   10723:     }
                   10724: 
                   10725:     xmlXPathCompUnionExpr(ctxt);
                   10726:     CHECK_ERROR;
                   10727:     if (found) {
                   10728:        if (minus)
                   10729:            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
                   10730:        else
                   10731:            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
                   10732:     }
                   10733: }
                   10734: 
                   10735: /**
                   10736:  * xmlXPathCompMultiplicativeExpr:
                   10737:  * @ctxt:  the XPath Parser context
                   10738:  *
                   10739:  *  [26]   MultiplicativeExpr ::=   UnaryExpr
                   10740:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
                   10741:  *                   | MultiplicativeExpr 'div' UnaryExpr
                   10742:  *                   | MultiplicativeExpr 'mod' UnaryExpr
                   10743:  *  [34]   MultiplyOperator ::=   '*'
                   10744:  *
                   10745:  * Compile an Additive expression.
                   10746:  */
                   10747: 
                   10748: static void
                   10749: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
                   10750:     xmlXPathCompUnaryExpr(ctxt);
                   10751:     CHECK_ERROR;
                   10752:     SKIP_BLANKS;
                   10753:     while ((CUR == '*') ||
                   10754:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
                   10755:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
                   10756:        int op = -1;
                   10757:        int op1 = ctxt->comp->last;
                   10758: 
                   10759:         if (CUR == '*') {
                   10760:            op = 0;
                   10761:            NEXT;
                   10762:        } else if (CUR == 'd') {
                   10763:            op = 1;
                   10764:            SKIP(3);
                   10765:        } else if (CUR == 'm') {
                   10766:            op = 2;
                   10767:            SKIP(3);
                   10768:        }
                   10769:        SKIP_BLANKS;
                   10770:         xmlXPathCompUnaryExpr(ctxt);
                   10771:        CHECK_ERROR;
                   10772:        PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
                   10773:        SKIP_BLANKS;
                   10774:     }
                   10775: }
                   10776: 
                   10777: /**
                   10778:  * xmlXPathCompAdditiveExpr:
                   10779:  * @ctxt:  the XPath Parser context
                   10780:  *
                   10781:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
                   10782:  *                   | AdditiveExpr '+' MultiplicativeExpr
                   10783:  *                   | AdditiveExpr '-' MultiplicativeExpr
                   10784:  *
                   10785:  * Compile an Additive expression.
                   10786:  */
                   10787: 
                   10788: static void
                   10789: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
                   10790: 
                   10791:     xmlXPathCompMultiplicativeExpr(ctxt);
                   10792:     CHECK_ERROR;
                   10793:     SKIP_BLANKS;
                   10794:     while ((CUR == '+') || (CUR == '-')) {
                   10795:        int plus;
                   10796:        int op1 = ctxt->comp->last;
                   10797: 
                   10798:         if (CUR == '+') plus = 1;
                   10799:        else plus = 0;
                   10800:        NEXT;
                   10801:        SKIP_BLANKS;
                   10802:         xmlXPathCompMultiplicativeExpr(ctxt);
                   10803:        CHECK_ERROR;
                   10804:        PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
                   10805:        SKIP_BLANKS;
                   10806:     }
                   10807: }
                   10808: 
                   10809: /**
                   10810:  * xmlXPathCompRelationalExpr:
                   10811:  * @ctxt:  the XPath Parser context
                   10812:  *
                   10813:  *  [24]   RelationalExpr ::=   AdditiveExpr
                   10814:  *                 | RelationalExpr '<' AdditiveExpr
                   10815:  *                 | RelationalExpr '>' AdditiveExpr
                   10816:  *                 | RelationalExpr '<=' AdditiveExpr
                   10817:  *                 | RelationalExpr '>=' AdditiveExpr
                   10818:  *
                   10819:  *  A <= B > C is allowed ? Answer from James, yes with
                   10820:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
                   10821:  *  which is basically what got implemented.
                   10822:  *
                   10823:  * Compile a Relational expression, then push the result
                   10824:  * on the stack
                   10825:  */
                   10826: 
                   10827: static void
                   10828: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
                   10829:     xmlXPathCompAdditiveExpr(ctxt);
                   10830:     CHECK_ERROR;
                   10831:     SKIP_BLANKS;
                   10832:     while ((CUR == '<') ||
                   10833:            (CUR == '>') ||
                   10834:            ((CUR == '<') && (NXT(1) == '=')) ||
                   10835:            ((CUR == '>') && (NXT(1) == '='))) {
                   10836:        int inf, strict;
                   10837:        int op1 = ctxt->comp->last;
                   10838: 
                   10839:         if (CUR == '<') inf = 1;
                   10840:        else inf = 0;
                   10841:        if (NXT(1) == '=') strict = 0;
                   10842:        else strict = 1;
                   10843:        NEXT;
                   10844:        if (!strict) NEXT;
                   10845:        SKIP_BLANKS;
                   10846:         xmlXPathCompAdditiveExpr(ctxt);
                   10847:        CHECK_ERROR;
                   10848:        PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
                   10849:        SKIP_BLANKS;
                   10850:     }
                   10851: }
                   10852: 
                   10853: /**
                   10854:  * xmlXPathCompEqualityExpr:
                   10855:  * @ctxt:  the XPath Parser context
                   10856:  *
                   10857:  *  [23]   EqualityExpr ::=   RelationalExpr
                   10858:  *                 | EqualityExpr '=' RelationalExpr
                   10859:  *                 | EqualityExpr '!=' RelationalExpr
                   10860:  *
                   10861:  *  A != B != C is allowed ? Answer from James, yes with
                   10862:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
                   10863:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
                   10864:  *  which is basically what got implemented.
                   10865:  *
                   10866:  * Compile an Equality expression.
                   10867:  *
                   10868:  */
                   10869: static void
                   10870: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
                   10871:     xmlXPathCompRelationalExpr(ctxt);
                   10872:     CHECK_ERROR;
                   10873:     SKIP_BLANKS;
                   10874:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
                   10875:        int eq;
                   10876:        int op1 = ctxt->comp->last;
                   10877: 
                   10878:         if (CUR == '=') eq = 1;
                   10879:        else eq = 0;
                   10880:        NEXT;
                   10881:        if (!eq) NEXT;
                   10882:        SKIP_BLANKS;
                   10883:         xmlXPathCompRelationalExpr(ctxt);
                   10884:        CHECK_ERROR;
                   10885:        PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
                   10886:        SKIP_BLANKS;
                   10887:     }
                   10888: }
                   10889: 
                   10890: /**
                   10891:  * xmlXPathCompAndExpr:
                   10892:  * @ctxt:  the XPath Parser context
                   10893:  *
                   10894:  *  [22]   AndExpr ::=   EqualityExpr
                   10895:  *                 | AndExpr 'and' EqualityExpr
                   10896:  *
                   10897:  * Compile an AND expression.
                   10898:  *
                   10899:  */
                   10900: static void
                   10901: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
                   10902:     xmlXPathCompEqualityExpr(ctxt);
                   10903:     CHECK_ERROR;
                   10904:     SKIP_BLANKS;
                   10905:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
                   10906:        int op1 = ctxt->comp->last;
                   10907:         SKIP(3);
                   10908:        SKIP_BLANKS;
                   10909:         xmlXPathCompEqualityExpr(ctxt);
                   10910:        CHECK_ERROR;
                   10911:        PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
                   10912:        SKIP_BLANKS;
                   10913:     }
                   10914: }
                   10915: 
                   10916: /**
                   10917:  * xmlXPathCompileExpr:
                   10918:  * @ctxt:  the XPath Parser context
                   10919:  *
                   10920:  *  [14]   Expr ::=   OrExpr
                   10921:  *  [21]   OrExpr ::=   AndExpr
                   10922:  *                 | OrExpr 'or' AndExpr
                   10923:  *
                   10924:  * Parse and compile an expression
                   10925:  */
                   10926: static void
                   10927: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
                   10928:     xmlXPathCompAndExpr(ctxt);
                   10929:     CHECK_ERROR;
                   10930:     SKIP_BLANKS;
                   10931:     while ((CUR == 'o') && (NXT(1) == 'r')) {
                   10932:        int op1 = ctxt->comp->last;
                   10933:         SKIP(2);
                   10934:        SKIP_BLANKS;
                   10935:         xmlXPathCompAndExpr(ctxt);
                   10936:        CHECK_ERROR;
                   10937:        PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
                   10938:        SKIP_BLANKS;
                   10939:     }
                   10940:     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
                   10941:        /* more ops could be optimized too */
                   10942:        /*
                   10943:        * This is the main place to eliminate sorting for
                   10944:        * operations which don't require a sorted node-set.
                   10945:        * E.g. count().
                   10946:        */
                   10947:        PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
                   10948:     }
                   10949: }
                   10950: 
                   10951: /**
                   10952:  * xmlXPathCompPredicate:
                   10953:  * @ctxt:  the XPath Parser context
                   10954:  * @filter:  act as a filter
                   10955:  *
                   10956:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
                   10957:  *  [9]   PredicateExpr ::=   Expr
                   10958:  *
                   10959:  * Compile a predicate expression
                   10960:  */
                   10961: static void
                   10962: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
                   10963:     int op1 = ctxt->comp->last;
                   10964: 
                   10965:     SKIP_BLANKS;
                   10966:     if (CUR != '[') {
                   10967:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
                   10968:     }
                   10969:     NEXT;
                   10970:     SKIP_BLANKS;
                   10971: 
                   10972:     ctxt->comp->last = -1;
                   10973:     /*
                   10974:     * This call to xmlXPathCompileExpr() will deactivate sorting
                   10975:     * of the predicate result.
                   10976:     * TODO: Sorting is still activated for filters, since I'm not
                   10977:     *  sure if needed. Normally sorting should not be needed, since
                   10978:     *  a filter can only diminish the number of items in a sequence,
                   10979:     *  but won't change its order; so if the initial sequence is sorted,
                   10980:     *  subsequent sorting is not needed.
                   10981:     */
                   10982:     if (! filter)
                   10983:        xmlXPathCompileExpr(ctxt, 0);
                   10984:     else
                   10985:        xmlXPathCompileExpr(ctxt, 1);
                   10986:     CHECK_ERROR;
                   10987: 
                   10988:     if (CUR != ']') {
                   10989:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
                   10990:     }
                   10991: 
                   10992:     if (filter)
                   10993:        PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
                   10994:     else
                   10995:        PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
                   10996: 
                   10997:     NEXT;
                   10998:     SKIP_BLANKS;
                   10999: }
                   11000: 
                   11001: /**
                   11002:  * xmlXPathCompNodeTest:
                   11003:  * @ctxt:  the XPath Parser context
                   11004:  * @test:  pointer to a xmlXPathTestVal
                   11005:  * @type:  pointer to a xmlXPathTypeVal
                   11006:  * @prefix:  placeholder for a possible name prefix
                   11007:  *
                   11008:  * [7] NodeTest ::=   NameTest
                   11009:  *                 | NodeType '(' ')'
                   11010:  *                 | 'processing-instruction' '(' Literal ')'
                   11011:  *
                   11012:  * [37] NameTest ::=  '*'
                   11013:  *                 | NCName ':' '*'
                   11014:  *                 | QName
                   11015:  * [38] NodeType ::= 'comment'
                   11016:  *                | 'text'
                   11017:  *                | 'processing-instruction'
                   11018:  *                | 'node'
                   11019:  *
                   11020:  * Returns the name found and updates @test, @type and @prefix appropriately
                   11021:  */
                   11022: static xmlChar *
                   11023: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
                   11024:                     xmlXPathTypeVal *type, const xmlChar **prefix,
                   11025:                     xmlChar *name) {
                   11026:     int blanks;
                   11027: 
                   11028:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
                   11029:        STRANGE;
                   11030:        return(NULL);
                   11031:     }
                   11032:     *type = (xmlXPathTypeVal) 0;
                   11033:     *test = (xmlXPathTestVal) 0;
                   11034:     *prefix = NULL;
                   11035:     SKIP_BLANKS;
                   11036: 
                   11037:     if ((name == NULL) && (CUR == '*')) {
                   11038:        /*
                   11039:         * All elements
                   11040:         */
                   11041:        NEXT;
                   11042:        *test = NODE_TEST_ALL;
                   11043:        return(NULL);
                   11044:     }
                   11045: 
                   11046:     if (name == NULL)
                   11047:        name = xmlXPathParseNCName(ctxt);
                   11048:     if (name == NULL) {
                   11049:        XP_ERRORNULL(XPATH_EXPR_ERROR);
                   11050:     }
                   11051: 
                   11052:     blanks = IS_BLANK_CH(CUR);
                   11053:     SKIP_BLANKS;
                   11054:     if (CUR == '(') {
                   11055:        NEXT;
                   11056:        /*
                   11057:         * NodeType or PI search
                   11058:         */
                   11059:        if (xmlStrEqual(name, BAD_CAST "comment"))
                   11060:            *type = NODE_TYPE_COMMENT;
                   11061:        else if (xmlStrEqual(name, BAD_CAST "node"))
                   11062:            *type = NODE_TYPE_NODE;
                   11063:        else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
                   11064:            *type = NODE_TYPE_PI;
                   11065:        else if (xmlStrEqual(name, BAD_CAST "text"))
                   11066:            *type = NODE_TYPE_TEXT;
                   11067:        else {
                   11068:            if (name != NULL)
                   11069:                xmlFree(name);
                   11070:            XP_ERRORNULL(XPATH_EXPR_ERROR);
                   11071:        }
                   11072: 
                   11073:        *test = NODE_TEST_TYPE;
                   11074: 
                   11075:        SKIP_BLANKS;
                   11076:        if (*type == NODE_TYPE_PI) {
                   11077:            /*
                   11078:             * Specific case: search a PI by name.
                   11079:             */
                   11080:            if (name != NULL)
                   11081:                xmlFree(name);
                   11082:            name = NULL;
                   11083:            if (CUR != ')') {
                   11084:                name = xmlXPathParseLiteral(ctxt);
                   11085:                CHECK_ERROR NULL;
                   11086:                *test = NODE_TEST_PI;
                   11087:                SKIP_BLANKS;
                   11088:            }
                   11089:        }
                   11090:        if (CUR != ')') {
                   11091:            if (name != NULL)
                   11092:                xmlFree(name);
                   11093:            XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
                   11094:        }
                   11095:        NEXT;
                   11096:        return(name);
                   11097:     }
                   11098:     *test = NODE_TEST_NAME;
                   11099:     if ((!blanks) && (CUR == ':')) {
                   11100:        NEXT;
                   11101: 
                   11102:        /*
                   11103:         * Since currently the parser context don't have a
                   11104:         * namespace list associated:
                   11105:         * The namespace name for this prefix can be computed
                   11106:         * only at evaluation time. The compilation is done
                   11107:         * outside of any context.
                   11108:         */
                   11109: #if 0
                   11110:        *prefix = xmlXPathNsLookup(ctxt->context, name);
                   11111:        if (name != NULL)
                   11112:            xmlFree(name);
                   11113:        if (*prefix == NULL) {
                   11114:            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
                   11115:        }
                   11116: #else
                   11117:        *prefix = name;
                   11118: #endif
                   11119: 
                   11120:        if (CUR == '*') {
                   11121:            /*
                   11122:             * All elements
                   11123:             */
                   11124:            NEXT;
                   11125:            *test = NODE_TEST_ALL;
                   11126:            return(NULL);
                   11127:        }
                   11128: 
                   11129:        name = xmlXPathParseNCName(ctxt);
                   11130:        if (name == NULL) {
                   11131:            XP_ERRORNULL(XPATH_EXPR_ERROR);
                   11132:        }
                   11133:     }
                   11134:     return(name);
                   11135: }
                   11136: 
                   11137: /**
                   11138:  * xmlXPathIsAxisName:
                   11139:  * @name:  a preparsed name token
                   11140:  *
                   11141:  * [6] AxisName ::=   'ancestor'
                   11142:  *                  | 'ancestor-or-self'
                   11143:  *                  | 'attribute'
                   11144:  *                  | 'child'
                   11145:  *                  | 'descendant'
                   11146:  *                  | 'descendant-or-self'
                   11147:  *                  | 'following'
                   11148:  *                  | 'following-sibling'
                   11149:  *                  | 'namespace'
                   11150:  *                  | 'parent'
                   11151:  *                  | 'preceding'
                   11152:  *                  | 'preceding-sibling'
                   11153:  *                  | 'self'
                   11154:  *
                   11155:  * Returns the axis or 0
                   11156:  */
                   11157: static xmlXPathAxisVal
                   11158: xmlXPathIsAxisName(const xmlChar *name) {
                   11159:     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
                   11160:     switch (name[0]) {
                   11161:        case 'a':
                   11162:            if (xmlStrEqual(name, BAD_CAST "ancestor"))
                   11163:                ret = AXIS_ANCESTOR;
                   11164:            if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
                   11165:                ret = AXIS_ANCESTOR_OR_SELF;
                   11166:            if (xmlStrEqual(name, BAD_CAST "attribute"))
                   11167:                ret = AXIS_ATTRIBUTE;
                   11168:            break;
                   11169:        case 'c':
                   11170:            if (xmlStrEqual(name, BAD_CAST "child"))
                   11171:                ret = AXIS_CHILD;
                   11172:            break;
                   11173:        case 'd':
                   11174:            if (xmlStrEqual(name, BAD_CAST "descendant"))
                   11175:                ret = AXIS_DESCENDANT;
                   11176:            if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
                   11177:                ret = AXIS_DESCENDANT_OR_SELF;
                   11178:            break;
                   11179:        case 'f':
                   11180:            if (xmlStrEqual(name, BAD_CAST "following"))
                   11181:                ret = AXIS_FOLLOWING;
                   11182:            if (xmlStrEqual(name, BAD_CAST "following-sibling"))
                   11183:                ret = AXIS_FOLLOWING_SIBLING;
                   11184:            break;
                   11185:        case 'n':
                   11186:            if (xmlStrEqual(name, BAD_CAST "namespace"))
                   11187:                ret = AXIS_NAMESPACE;
                   11188:            break;
                   11189:        case 'p':
                   11190:            if (xmlStrEqual(name, BAD_CAST "parent"))
                   11191:                ret = AXIS_PARENT;
                   11192:            if (xmlStrEqual(name, BAD_CAST "preceding"))
                   11193:                ret = AXIS_PRECEDING;
                   11194:            if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
                   11195:                ret = AXIS_PRECEDING_SIBLING;
                   11196:            break;
                   11197:        case 's':
                   11198:            if (xmlStrEqual(name, BAD_CAST "self"))
                   11199:                ret = AXIS_SELF;
                   11200:            break;
                   11201:     }
                   11202:     return(ret);
                   11203: }
                   11204: 
                   11205: /**
                   11206:  * xmlXPathCompStep:
                   11207:  * @ctxt:  the XPath Parser context
                   11208:  *
                   11209:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
                   11210:  *                  | AbbreviatedStep
                   11211:  *
                   11212:  * [12] AbbreviatedStep ::=   '.' | '..'
                   11213:  *
                   11214:  * [5] AxisSpecifier ::= AxisName '::'
                   11215:  *                  | AbbreviatedAxisSpecifier
                   11216:  *
                   11217:  * [13] AbbreviatedAxisSpecifier ::= '@'?
                   11218:  *
                   11219:  * Modified for XPtr range support as:
                   11220:  *
                   11221:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
                   11222:  *                     | AbbreviatedStep
                   11223:  *                     | 'range-to' '(' Expr ')' Predicate*
                   11224:  *
                   11225:  * Compile one step in a Location Path
                   11226:  * A location step of . is short for self::node(). This is
                   11227:  * particularly useful in conjunction with //. For example, the
                   11228:  * location path .//para is short for
                   11229:  * self::node()/descendant-or-self::node()/child::para
                   11230:  * and so will select all para descendant elements of the context
                   11231:  * node.
                   11232:  * Similarly, a location step of .. is short for parent::node().
                   11233:  * For example, ../title is short for parent::node()/child::title
                   11234:  * and so will select the title children of the parent of the context
                   11235:  * node.
                   11236:  */
                   11237: static void
                   11238: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
                   11239: #ifdef LIBXML_XPTR_ENABLED
                   11240:     int rangeto = 0;
                   11241:     int op2 = -1;
                   11242: #endif
                   11243: 
                   11244:     SKIP_BLANKS;
                   11245:     if ((CUR == '.') && (NXT(1) == '.')) {
                   11246:        SKIP(2);
                   11247:        SKIP_BLANKS;
                   11248:        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
                   11249:                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11250:     } else if (CUR == '.') {
                   11251:        NEXT;
                   11252:        SKIP_BLANKS;
                   11253:     } else {
                   11254:        xmlChar *name = NULL;
                   11255:        const xmlChar *prefix = NULL;
                   11256:        xmlXPathTestVal test = (xmlXPathTestVal) 0;
                   11257:        xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
                   11258:        xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
                   11259:        int op1;
                   11260: 
                   11261:        /*
                   11262:         * The modification needed for XPointer change to the production
                   11263:         */
                   11264: #ifdef LIBXML_XPTR_ENABLED
                   11265:        if (ctxt->xptr) {
                   11266:            name = xmlXPathParseNCName(ctxt);
                   11267:            if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
                   11268:                 op2 = ctxt->comp->last;
                   11269:                xmlFree(name);
                   11270:                SKIP_BLANKS;
                   11271:                if (CUR != '(') {
                   11272:                    XP_ERROR(XPATH_EXPR_ERROR);
                   11273:                }
                   11274:                NEXT;
                   11275:                SKIP_BLANKS;
                   11276: 
                   11277:                xmlXPathCompileExpr(ctxt, 1);
                   11278:                /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
                   11279:                CHECK_ERROR;
                   11280: 
                   11281:                SKIP_BLANKS;
                   11282:                if (CUR != ')') {
                   11283:                    XP_ERROR(XPATH_EXPR_ERROR);
                   11284:                }
                   11285:                NEXT;
                   11286:                rangeto = 1;
                   11287:                goto eval_predicates;
                   11288:            }
                   11289:        }
                   11290: #endif
                   11291:        if (CUR == '*') {
                   11292:            axis = AXIS_CHILD;
                   11293:        } else {
                   11294:            if (name == NULL)
                   11295:                name = xmlXPathParseNCName(ctxt);
                   11296:            if (name != NULL) {
                   11297:                axis = xmlXPathIsAxisName(name);
                   11298:                if (axis != 0) {
                   11299:                    SKIP_BLANKS;
                   11300:                    if ((CUR == ':') && (NXT(1) == ':')) {
                   11301:                        SKIP(2);
                   11302:                        xmlFree(name);
                   11303:                        name = NULL;
                   11304:                    } else {
                   11305:                        /* an element name can conflict with an axis one :-\ */
                   11306:                        axis = AXIS_CHILD;
                   11307:                    }
                   11308:                } else {
                   11309:                    axis = AXIS_CHILD;
                   11310:                }
                   11311:            } else if (CUR == '@') {
                   11312:                NEXT;
                   11313:                axis = AXIS_ATTRIBUTE;
                   11314:            } else {
                   11315:                axis = AXIS_CHILD;
                   11316:            }
                   11317:        }
                   11318: 
                   11319:         if (ctxt->error != XPATH_EXPRESSION_OK) {
                   11320:             xmlFree(name);
                   11321:             return;
                   11322:         }
                   11323: 
                   11324:        name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
                   11325:        if (test == 0)
                   11326:            return;
                   11327: 
                   11328:         if ((prefix != NULL) && (ctxt->context != NULL) &&
                   11329:            (ctxt->context->flags & XML_XPATH_CHECKNS)) {
                   11330:            if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
                   11331:                xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
                   11332:            }
                   11333:        }
                   11334: #ifdef DEBUG_STEP
                   11335:        xmlGenericError(xmlGenericErrorContext,
                   11336:                "Basis : computing new set\n");
                   11337: #endif
                   11338: 
                   11339: #ifdef DEBUG_STEP
                   11340:        xmlGenericError(xmlGenericErrorContext, "Basis : ");
                   11341:        if (ctxt->value == NULL)
                   11342:            xmlGenericError(xmlGenericErrorContext, "no value\n");
                   11343:        else if (ctxt->value->nodesetval == NULL)
                   11344:            xmlGenericError(xmlGenericErrorContext, "Empty\n");
                   11345:        else
                   11346:            xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
                   11347: #endif
                   11348: 
                   11349: #ifdef LIBXML_XPTR_ENABLED
                   11350: eval_predicates:
                   11351: #endif
                   11352:        op1 = ctxt->comp->last;
                   11353:        ctxt->comp->last = -1;
                   11354: 
                   11355:        SKIP_BLANKS;
                   11356:        while (CUR == '[') {
                   11357:            xmlXPathCompPredicate(ctxt, 0);
                   11358:        }
                   11359: 
                   11360: #ifdef LIBXML_XPTR_ENABLED
                   11361:        if (rangeto) {
                   11362:            PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
                   11363:        } else
                   11364: #endif
                   11365:            PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
                   11366:                           test, type, (void *)prefix, (void *)name);
                   11367: 
                   11368:     }
                   11369: #ifdef DEBUG_STEP
                   11370:     xmlGenericError(xmlGenericErrorContext, "Step : ");
                   11371:     if (ctxt->value == NULL)
                   11372:        xmlGenericError(xmlGenericErrorContext, "no value\n");
                   11373:     else if (ctxt->value->nodesetval == NULL)
                   11374:        xmlGenericError(xmlGenericErrorContext, "Empty\n");
                   11375:     else
                   11376:        xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
                   11377:                ctxt->value->nodesetval);
                   11378: #endif
                   11379: }
                   11380: 
                   11381: /**
                   11382:  * xmlXPathCompRelativeLocationPath:
                   11383:  * @ctxt:  the XPath Parser context
                   11384:  *
                   11385:  *  [3]   RelativeLocationPath ::=   Step
                   11386:  *                     | RelativeLocationPath '/' Step
                   11387:  *                     | AbbreviatedRelativeLocationPath
                   11388:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
                   11389:  *
                   11390:  * Compile a relative location path.
                   11391:  */
                   11392: static void
                   11393: xmlXPathCompRelativeLocationPath
                   11394: (xmlXPathParserContextPtr ctxt) {
                   11395:     SKIP_BLANKS;
                   11396:     if ((CUR == '/') && (NXT(1) == '/')) {
                   11397:        SKIP(2);
                   11398:        SKIP_BLANKS;
                   11399:        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   11400:                         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11401:     } else if (CUR == '/') {
                   11402:            NEXT;
                   11403:        SKIP_BLANKS;
                   11404:     }
                   11405:     xmlXPathCompStep(ctxt);
                   11406:     CHECK_ERROR;
                   11407:     SKIP_BLANKS;
                   11408:     while (CUR == '/') {
                   11409:        if ((CUR == '/') && (NXT(1) == '/')) {
                   11410:            SKIP(2);
                   11411:            SKIP_BLANKS;
                   11412:            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   11413:                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11414:            xmlXPathCompStep(ctxt);
                   11415:        } else if (CUR == '/') {
                   11416:            NEXT;
                   11417:            SKIP_BLANKS;
                   11418:            xmlXPathCompStep(ctxt);
                   11419:        }
                   11420:        SKIP_BLANKS;
                   11421:     }
                   11422: }
                   11423: 
                   11424: /**
                   11425:  * xmlXPathCompLocationPath:
                   11426:  * @ctxt:  the XPath Parser context
                   11427:  *
                   11428:  *  [1]   LocationPath ::=   RelativeLocationPath
                   11429:  *                     | AbsoluteLocationPath
                   11430:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
                   11431:  *                     | AbbreviatedAbsoluteLocationPath
                   11432:  *  [10]   AbbreviatedAbsoluteLocationPath ::=
                   11433:  *                           '//' RelativeLocationPath
                   11434:  *
                   11435:  * Compile a location path
                   11436:  *
                   11437:  * // is short for /descendant-or-self::node()/. For example,
                   11438:  * //para is short for /descendant-or-self::node()/child::para and
                   11439:  * so will select any para element in the document (even a para element
                   11440:  * that is a document element will be selected by //para since the
                   11441:  * document element node is a child of the root node); div//para is
                   11442:  * short for div/descendant-or-self::node()/child::para and so will
                   11443:  * select all para descendants of div children.
                   11444:  */
                   11445: static void
                   11446: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
                   11447:     SKIP_BLANKS;
                   11448:     if (CUR != '/') {
                   11449:         xmlXPathCompRelativeLocationPath(ctxt);
                   11450:     } else {
                   11451:        while (CUR == '/') {
                   11452:            if ((CUR == '/') && (NXT(1) == '/')) {
                   11453:                SKIP(2);
                   11454:                SKIP_BLANKS;
                   11455:                PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   11456:                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11457:                xmlXPathCompRelativeLocationPath(ctxt);
                   11458:            } else if (CUR == '/') {
                   11459:                NEXT;
                   11460:                SKIP_BLANKS;
                   11461:                if ((CUR != 0 ) &&
                   11462:                    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
                   11463:                     (CUR == '@') || (CUR == '*')))
                   11464:                    xmlXPathCompRelativeLocationPath(ctxt);
                   11465:            }
                   11466:            CHECK_ERROR;
                   11467:        }
                   11468:     }
                   11469: }
                   11470: 
                   11471: /************************************************************************
                   11472:  *                                                                     *
                   11473:  *             XPath precompiled expression evaluation                 *
                   11474:  *                                                                     *
                   11475:  ************************************************************************/
                   11476: 
                   11477: static int
                   11478: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
                   11479: 
                   11480: #ifdef DEBUG_STEP
                   11481: static void
                   11482: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
                   11483:                          int nbNodes)
                   11484: {
                   11485:     xmlGenericError(xmlGenericErrorContext, "new step : ");
                   11486:     switch (op->value) {
                   11487:         case AXIS_ANCESTOR:
                   11488:             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
                   11489:             break;
                   11490:         case AXIS_ANCESTOR_OR_SELF:
                   11491:             xmlGenericError(xmlGenericErrorContext,
                   11492:                             "axis 'ancestors-or-self' ");
                   11493:             break;
                   11494:         case AXIS_ATTRIBUTE:
                   11495:             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
                   11496:             break;
                   11497:         case AXIS_CHILD:
                   11498:             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
                   11499:             break;
                   11500:         case AXIS_DESCENDANT:
                   11501:             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
                   11502:             break;
                   11503:         case AXIS_DESCENDANT_OR_SELF:
                   11504:             xmlGenericError(xmlGenericErrorContext,
                   11505:                             "axis 'descendant-or-self' ");
                   11506:             break;
                   11507:         case AXIS_FOLLOWING:
                   11508:             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
                   11509:             break;
                   11510:         case AXIS_FOLLOWING_SIBLING:
                   11511:             xmlGenericError(xmlGenericErrorContext,
                   11512:                             "axis 'following-siblings' ");
                   11513:             break;
                   11514:         case AXIS_NAMESPACE:
                   11515:             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
                   11516:             break;
                   11517:         case AXIS_PARENT:
                   11518:             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
                   11519:             break;
                   11520:         case AXIS_PRECEDING:
                   11521:             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
                   11522:             break;
                   11523:         case AXIS_PRECEDING_SIBLING:
                   11524:             xmlGenericError(xmlGenericErrorContext,
                   11525:                             "axis 'preceding-sibling' ");
                   11526:             break;
                   11527:         case AXIS_SELF:
                   11528:             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
                   11529:             break;
                   11530:     }
                   11531:     xmlGenericError(xmlGenericErrorContext,
                   11532:        " context contains %d nodes\n", nbNodes);
                   11533:     switch (op->value2) {
                   11534:         case NODE_TEST_NONE:
                   11535:             xmlGenericError(xmlGenericErrorContext,
                   11536:                             "           searching for none !!!\n");
                   11537:             break;
                   11538:         case NODE_TEST_TYPE:
                   11539:             xmlGenericError(xmlGenericErrorContext,
                   11540:                             "           searching for type %d\n", op->value3);
                   11541:             break;
                   11542:         case NODE_TEST_PI:
                   11543:             xmlGenericError(xmlGenericErrorContext,
                   11544:                             "           searching for PI !!!\n");
                   11545:             break;
                   11546:         case NODE_TEST_ALL:
                   11547:             xmlGenericError(xmlGenericErrorContext,
                   11548:                             "           searching for *\n");
                   11549:             break;
                   11550:         case NODE_TEST_NS:
                   11551:             xmlGenericError(xmlGenericErrorContext,
                   11552:                             "           searching for namespace %s\n",
                   11553:                             op->value5);
                   11554:             break;
                   11555:         case NODE_TEST_NAME:
                   11556:             xmlGenericError(xmlGenericErrorContext,
                   11557:                             "           searching for name %s\n", op->value5);
                   11558:             if (op->value4)
                   11559:                 xmlGenericError(xmlGenericErrorContext,
                   11560:                                 "           with namespace %s\n", op->value4);
                   11561:             break;
                   11562:     }
                   11563:     xmlGenericError(xmlGenericErrorContext, "Testing : ");
                   11564: }
                   11565: #endif /* DEBUG_STEP */
                   11566: 
                   11567: static int
                   11568: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
                   11569:                            xmlXPathStepOpPtr op,
                   11570:                            xmlNodeSetPtr set,
                   11571:                            int contextSize,
                   11572:                            int hasNsNodes)
                   11573: {
                   11574:     if (op->ch1 != -1) {
                   11575:        xmlXPathCompExprPtr comp = ctxt->comp;
                   11576:        /*
                   11577:        * Process inner predicates first.
                   11578:        */
                   11579:        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
                   11580:            /*
                   11581:            * TODO: raise an internal error.
                   11582:            */
                   11583:        }
                   11584:        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
                   11585:            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
                   11586:        CHECK_ERROR0;
                   11587:        if (contextSize <= 0)
                   11588:            return(0);
                   11589:     }
                   11590:     if (op->ch2 != -1) {
                   11591:        xmlXPathContextPtr xpctxt = ctxt->context;
                   11592:        xmlNodePtr contextNode, oldContextNode;
                   11593:        xmlDocPtr oldContextDoc;
                   11594:        int i, res, contextPos = 0, newContextSize;
                   11595:        xmlXPathStepOpPtr exprOp;
                   11596:        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
                   11597: 
                   11598: #ifdef LIBXML_XPTR_ENABLED
                   11599:        /*
                   11600:        * URGENT TODO: Check the following:
                   11601:        *  We don't expect location sets if evaluating prediates, right?
                   11602:        *  Only filters should expect location sets, right?
                   11603:        */
                   11604: #endif
                   11605:        /*
                   11606:        * SPEC XPath 1.0:
                   11607:        *  "For each node in the node-set to be filtered, the
                   11608:        *  PredicateExpr is evaluated with that node as the
                   11609:        *  context node, with the number of nodes in the
                   11610:        *  node-set as the context size, and with the proximity
                   11611:        *  position of the node in the node-set with respect to
                   11612:        *  the axis as the context position;"
                   11613:        * @oldset is the node-set" to be filtered.
                   11614:        *
                   11615:        * SPEC XPath 1.0:
                   11616:        *  "only predicates change the context position and
                   11617:        *  context size (see [2.4 Predicates])."
                   11618:        * Example:
                   11619:        *   node-set  context pos
                   11620:        *    nA         1
                   11621:        *    nB         2
                   11622:        *    nC         3
                   11623:        *   After applying predicate [position() > 1] :
                   11624:        *   node-set  context pos
                   11625:        *    nB         1
                   11626:        *    nC         2
                   11627:        */
                   11628:        oldContextNode = xpctxt->node;
                   11629:        oldContextDoc = xpctxt->doc;
                   11630:        /*
                   11631:        * Get the expression of this predicate.
                   11632:        */
                   11633:        exprOp = &ctxt->comp->steps[op->ch2];
                   11634:        newContextSize = 0;
                   11635:        for (i = 0; i < set->nodeNr; i++) {
                   11636:            if (set->nodeTab[i] == NULL)
                   11637:                continue;
                   11638: 
                   11639:            contextNode = set->nodeTab[i];
                   11640:            xpctxt->node = contextNode;
                   11641:            xpctxt->contextSize = contextSize;
                   11642:            xpctxt->proximityPosition = ++contextPos;
                   11643: 
                   11644:            /*
                   11645:            * Also set the xpath document in case things like
                   11646:            * key() are evaluated in the predicate.
                   11647:            */
                   11648:            if ((contextNode->type != XML_NAMESPACE_DECL) &&
                   11649:                (contextNode->doc != NULL))
                   11650:                xpctxt->doc = contextNode->doc;
                   11651:            /*
                   11652:            * Evaluate the predicate expression with 1 context node
                   11653:            * at a time; this node is packaged into a node set; this
                   11654:            * node set is handed over to the evaluation mechanism.
                   11655:            */
                   11656:            if (contextObj == NULL)
                   11657:                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
                   11658:            else
                   11659:                xmlXPathNodeSetAddUnique(contextObj->nodesetval,
                   11660:                    contextNode);
                   11661: 
                   11662:            valuePush(ctxt, contextObj);
                   11663: 
                   11664:            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
                   11665: 
                   11666:            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
                   11667:                xmlXPathNodeSetClear(set, hasNsNodes);
                   11668:                newContextSize = 0;
                   11669:                goto evaluation_exit;
                   11670:            }
                   11671: 
                   11672:            if (res != 0) {
                   11673:                newContextSize++;
                   11674:            } else {
                   11675:                /*
                   11676:                * Remove the entry from the initial node set.
                   11677:                */
                   11678:                set->nodeTab[i] = NULL;
                   11679:                if (contextNode->type == XML_NAMESPACE_DECL)
                   11680:                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
                   11681:            }
                   11682:            if (ctxt->value == contextObj) {
                   11683:                /*
                   11684:                * Don't free the temporary XPath object holding the
                   11685:                * context node, in order to avoid massive recreation
                   11686:                * inside this loop.
                   11687:                */
                   11688:                valuePop(ctxt);
                   11689:                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
                   11690:            } else {
                   11691:                /*
                   11692:                * TODO: The object was lost in the evaluation machinery.
                   11693:                *  Can this happen? Maybe in internal-error cases.
                   11694:                */
                   11695:                contextObj = NULL;
                   11696:            }
                   11697:        }
                   11698: 
                   11699:        if (contextObj != NULL) {
                   11700:            if (ctxt->value == contextObj)
                   11701:                valuePop(ctxt);
                   11702:            xmlXPathReleaseObject(xpctxt, contextObj);
                   11703:        }
                   11704: evaluation_exit:
                   11705:        if (exprRes != NULL)
                   11706:            xmlXPathReleaseObject(ctxt->context, exprRes);
                   11707:        /*
                   11708:        * Reset/invalidate the context.
                   11709:        */
                   11710:        xpctxt->node = oldContextNode;
                   11711:        xpctxt->doc = oldContextDoc;
                   11712:        xpctxt->contextSize = -1;
                   11713:        xpctxt->proximityPosition = -1;
                   11714:        return(newContextSize);
                   11715:     }
                   11716:     return(contextSize);
                   11717: }
                   11718: 
                   11719: static int
                   11720: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
                   11721:                                      xmlXPathStepOpPtr op,
                   11722:                                      xmlNodeSetPtr set,
                   11723:                                      int contextSize,
                   11724:                                      int minPos,
                   11725:                                      int maxPos,
                   11726:                                      int hasNsNodes)
                   11727: {
                   11728:     if (op->ch1 != -1) {
                   11729:        xmlXPathCompExprPtr comp = ctxt->comp;
                   11730:        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
                   11731:            /*
                   11732:            * TODO: raise an internal error.
                   11733:            */
                   11734:        }
                   11735:        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
                   11736:            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
                   11737:        CHECK_ERROR0;
                   11738:        if (contextSize <= 0)
                   11739:            return(0);
                   11740:     }
                   11741:     /*
                   11742:     * Check if the node set contains a sufficient number of nodes for
                   11743:     * the requested range.
                   11744:     */
                   11745:     if (contextSize < minPos) {
                   11746:        xmlXPathNodeSetClear(set, hasNsNodes);
                   11747:        return(0);
                   11748:     }
                   11749:     if (op->ch2 == -1) {
                   11750:        /*
                   11751:        * TODO: Can this ever happen?
                   11752:        */
                   11753:        return (contextSize);
                   11754:     } else {
                   11755:        xmlDocPtr oldContextDoc;
                   11756:        int i, pos = 0, newContextSize = 0, contextPos = 0, res;
                   11757:        xmlXPathStepOpPtr exprOp;
                   11758:        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
                   11759:        xmlNodePtr oldContextNode, contextNode = NULL;
                   11760:        xmlXPathContextPtr xpctxt = ctxt->context;
1.1.1.2 ! misho    11761:         int frame;
1.1       misho    11762: 
                   11763: #ifdef LIBXML_XPTR_ENABLED
                   11764:            /*
                   11765:            * URGENT TODO: Check the following:
                   11766:            *  We don't expect location sets if evaluating prediates, right?
                   11767:            *  Only filters should expect location sets, right?
                   11768:        */
                   11769: #endif /* LIBXML_XPTR_ENABLED */
                   11770: 
                   11771:        /*
                   11772:        * Save old context.
                   11773:        */
                   11774:        oldContextNode = xpctxt->node;
                   11775:        oldContextDoc = xpctxt->doc;
                   11776:        /*
                   11777:        * Get the expression of this predicate.
                   11778:        */
                   11779:        exprOp = &ctxt->comp->steps[op->ch2];
                   11780:        for (i = 0; i < set->nodeNr; i++) {
1.1.1.2 ! misho    11781:             xmlXPathObjectPtr tmp;
        !          11782: 
1.1       misho    11783:            if (set->nodeTab[i] == NULL)
                   11784:                continue;
                   11785: 
                   11786:            contextNode = set->nodeTab[i];
                   11787:            xpctxt->node = contextNode;
                   11788:            xpctxt->contextSize = contextSize;
                   11789:            xpctxt->proximityPosition = ++contextPos;
                   11790: 
                   11791:            /*
                   11792:            * Initialize the new set.
                   11793:            * Also set the xpath document in case things like
                   11794:            * key() evaluation are attempted on the predicate
                   11795:            */
                   11796:            if ((contextNode->type != XML_NAMESPACE_DECL) &&
                   11797:                (contextNode->doc != NULL))
                   11798:                xpctxt->doc = contextNode->doc;
                   11799:            /*
                   11800:            * Evaluate the predicate expression with 1 context node
                   11801:            * at a time; this node is packaged into a node set; this
                   11802:            * node set is handed over to the evaluation mechanism.
                   11803:            */
                   11804:            if (contextObj == NULL)
                   11805:                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
                   11806:            else
                   11807:                xmlXPathNodeSetAddUnique(contextObj->nodesetval,
                   11808:                    contextNode);
                   11809: 
1.1.1.2 ! misho    11810:             frame = xmlXPathSetFrame(ctxt);
1.1       misho    11811:            valuePush(ctxt, contextObj);
                   11812:            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
1.1.1.2 ! misho    11813:             tmp = valuePop(ctxt);
        !          11814:             xmlXPathPopFrame(ctxt, frame);
1.1       misho    11815: 
                   11816:            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
1.1.1.2 ! misho    11817:                 while (tmp != contextObj) {
        !          11818:                     /*
        !          11819:                      * Free up the result
        !          11820:                      * then pop off contextObj, which will be freed later
        !          11821:                      */
        !          11822:                     xmlXPathReleaseObject(xpctxt, tmp);
        !          11823:                     tmp = valuePop(ctxt);
        !          11824:                 }
1.1       misho    11825:                goto evaluation_error;
                   11826:            }
1.1.1.2 ! misho    11827:             /* push the result back onto the stack */
        !          11828:             valuePush(ctxt, tmp);
1.1       misho    11829: 
                   11830:            if (res)
                   11831:                pos++;
                   11832: 
                   11833:            if (res && (pos >= minPos) && (pos <= maxPos)) {
                   11834:                /*
                   11835:                * Fits in the requested range.
                   11836:                */
                   11837:                newContextSize++;
                   11838:                if (minPos == maxPos) {
                   11839:                    /*
                   11840:                    * Only 1 node was requested.
                   11841:                    */
                   11842:                    if (contextNode->type == XML_NAMESPACE_DECL) {
                   11843:                        /*
                   11844:                        * As always: take care of those nasty
                   11845:                        * namespace nodes.
                   11846:                        */
                   11847:                        set->nodeTab[i] = NULL;
                   11848:                    }
                   11849:                    xmlXPathNodeSetClear(set, hasNsNodes);
                   11850:                    set->nodeNr = 1;
                   11851:                    set->nodeTab[0] = contextNode;
                   11852:                    goto evaluation_exit;
                   11853:                }
                   11854:                if (pos == maxPos) {
                   11855:                    /*
                   11856:                    * We are done.
                   11857:                    */
                   11858:                    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
                   11859:                    goto evaluation_exit;
                   11860:                }
                   11861:            } else {
                   11862:                /*
                   11863:                * Remove the entry from the initial node set.
                   11864:                */
                   11865:                set->nodeTab[i] = NULL;
                   11866:                if (contextNode->type == XML_NAMESPACE_DECL)
                   11867:                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
                   11868:            }
                   11869:            if (exprRes != NULL) {
                   11870:                xmlXPathReleaseObject(ctxt->context, exprRes);
                   11871:                exprRes = NULL;
                   11872:            }
                   11873:            if (ctxt->value == contextObj) {
                   11874:                /*
                   11875:                * Don't free the temporary XPath object holding the
                   11876:                * context node, in order to avoid massive recreation
                   11877:                * inside this loop.
                   11878:                */
                   11879:                valuePop(ctxt);
                   11880:                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
                   11881:            } else {
                   11882:                /*
                   11883:                * The object was lost in the evaluation machinery.
                   11884:                * Can this happen? Maybe in case of internal-errors.
                   11885:                */
                   11886:                contextObj = NULL;
                   11887:            }
                   11888:        }
                   11889:        goto evaluation_exit;
                   11890: 
                   11891: evaluation_error:
                   11892:        xmlXPathNodeSetClear(set, hasNsNodes);
                   11893:        newContextSize = 0;
                   11894: 
                   11895: evaluation_exit:
                   11896:        if (contextObj != NULL) {
                   11897:            if (ctxt->value == contextObj)
                   11898:                valuePop(ctxt);
                   11899:            xmlXPathReleaseObject(xpctxt, contextObj);
                   11900:        }
                   11901:        if (exprRes != NULL)
                   11902:            xmlXPathReleaseObject(ctxt->context, exprRes);
                   11903:        /*
                   11904:        * Reset/invalidate the context.
                   11905:        */
                   11906:        xpctxt->node = oldContextNode;
                   11907:        xpctxt->doc = oldContextDoc;
                   11908:        xpctxt->contextSize = -1;
                   11909:        xpctxt->proximityPosition = -1;
                   11910:        return(newContextSize);
                   11911:     }
                   11912:     return(contextSize);
                   11913: }
                   11914: 
                   11915: static int
                   11916: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
                   11917:                            xmlXPathStepOpPtr op,
                   11918:                            int *maxPos)
                   11919: {
                   11920: 
                   11921:     xmlXPathStepOpPtr exprOp;
                   11922: 
                   11923:     /*
                   11924:     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
                   11925:     */
                   11926: 
                   11927:     /*
                   11928:     * If not -1, then ch1 will point to:
                   11929:     * 1) For predicates (XPATH_OP_PREDICATE):
                   11930:     *    - an inner predicate operator
                   11931:     * 2) For filters (XPATH_OP_FILTER):
                   11932:     *    - an inner filter operater OR
                   11933:     *    - an expression selecting the node set.
                   11934:     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
                   11935:     */
                   11936:     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
                   11937:        return(0);
                   11938: 
                   11939:     if (op->ch2 != -1) {
                   11940:        exprOp = &ctxt->comp->steps[op->ch2];
                   11941:     } else
                   11942:        return(0);
                   11943: 
                   11944:     if ((exprOp != NULL) &&
                   11945:        (exprOp->op == XPATH_OP_VALUE) &&
                   11946:        (exprOp->value4 != NULL) &&
                   11947:        (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
                   11948:     {
                   11949:        /*
                   11950:        * We have a "[n]" predicate here.
                   11951:        * TODO: Unfortunately this simplistic test here is not
                   11952:        * able to detect a position() predicate in compound
                   11953:        * expressions like "[@attr = 'a" and position() = 1],
                   11954:        * and even not the usage of position() in
                   11955:        * "[position() = 1]"; thus - obviously - a position-range,
                   11956:        * like it "[position() < 5]", is also not detected.
                   11957:        * Maybe we could rewrite the AST to ease the optimization.
                   11958:        */
                   11959:        *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
                   11960: 
                   11961:        if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
                   11962:            (float) *maxPos)
                   11963:        {
                   11964:            return(1);
                   11965:        }
                   11966:     }
                   11967:     return(0);
                   11968: }
                   11969: 
                   11970: static int
                   11971: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
                   11972:                            xmlXPathStepOpPtr op,
                   11973:                           xmlNodePtr * first, xmlNodePtr * last,
                   11974:                           int toBool)
                   11975: {
                   11976: 
                   11977: #define XP_TEST_HIT \
                   11978:     if (hasAxisRange != 0) { \
                   11979:        if (++pos == maxPos) { \
                   11980:            addNode(seq, cur); \
                   11981:        goto axis_range_end; } \
                   11982:     } else { \
                   11983:        addNode(seq, cur); \
                   11984:        if (breakOnFirstHit) goto first_hit; }
                   11985: 
                   11986: #define XP_TEST_HIT_NS \
                   11987:     if (hasAxisRange != 0) { \
                   11988:        if (++pos == maxPos) { \
                   11989:            hasNsNodes = 1; \
                   11990:            xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
                   11991:        goto axis_range_end; } \
                   11992:     } else { \
                   11993:        hasNsNodes = 1; \
                   11994:        xmlXPathNodeSetAddNs(seq, \
                   11995:        xpctxt->node, (xmlNsPtr) cur); \
                   11996:        if (breakOnFirstHit) goto first_hit; }
                   11997: 
                   11998:     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
                   11999:     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
                   12000:     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
                   12001:     const xmlChar *prefix = op->value4;
                   12002:     const xmlChar *name = op->value5;
                   12003:     const xmlChar *URI = NULL;
                   12004: 
                   12005: #ifdef DEBUG_STEP
                   12006:     int nbMatches = 0, prevMatches = 0;
                   12007: #endif
                   12008:     int total = 0, hasNsNodes = 0;
                   12009:     /* The popped object holding the context nodes */
                   12010:     xmlXPathObjectPtr obj;
                   12011:     /* The set of context nodes for the node tests */
                   12012:     xmlNodeSetPtr contextSeq;
                   12013:     int contextIdx;
                   12014:     xmlNodePtr contextNode;
                   12015:     /* The context node for a compound traversal */
                   12016:     xmlNodePtr outerContextNode;
                   12017:     /* The final resulting node set wrt to all context nodes */
                   12018:     xmlNodeSetPtr outSeq;
                   12019:     /*
                   12020:     * The temporary resulting node set wrt 1 context node.
                   12021:     * Used to feed predicate evaluation.
                   12022:     */
                   12023:     xmlNodeSetPtr seq;
                   12024:     xmlNodePtr cur;
                   12025:     /* First predicate operator */
                   12026:     xmlXPathStepOpPtr predOp;
                   12027:     int maxPos; /* The requested position() (when a "[n]" predicate) */
                   12028:     int hasPredicateRange, hasAxisRange, pos, size, newSize;
                   12029:     int breakOnFirstHit;
                   12030: 
                   12031:     xmlXPathTraversalFunction next = NULL;
                   12032:     /* compound axis traversal */
                   12033:     xmlXPathTraversalFunctionExt outerNext = NULL;
                   12034:     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
                   12035:     xmlXPathNodeSetMergeFunction mergeAndClear;
                   12036:     xmlNodePtr oldContextNode;
                   12037:     xmlXPathContextPtr xpctxt = ctxt->context;
                   12038: 
                   12039: 
                   12040:     CHECK_TYPE0(XPATH_NODESET);
                   12041:     obj = valuePop(ctxt);
                   12042:     /*
                   12043:     * Setup namespaces.
                   12044:     */
                   12045:     if (prefix != NULL) {
                   12046:         URI = xmlXPathNsLookup(xpctxt, prefix);
                   12047:         if (URI == NULL) {
                   12048:            xmlXPathReleaseObject(xpctxt, obj);
                   12049:             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
                   12050:        }
                   12051:     }
                   12052:     /*
                   12053:     * Setup axis.
                   12054:     *
                   12055:     * MAYBE FUTURE TODO: merging optimizations:
                   12056:     * - If the nodes to be traversed wrt to the initial nodes and
                   12057:     *   the current axis cannot overlap, then we could avoid searching
                   12058:     *   for duplicates during the merge.
                   12059:     *   But the question is how/when to evaluate if they cannot overlap.
                   12060:     *   Example: if we know that for two initial nodes, the one is
                   12061:     *   not in the ancestor-or-self axis of the other, then we could safely
                   12062:     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
                   12063:     *   the descendant-or-self axis.
                   12064:     */
                   12065:     mergeAndClear = xmlXPathNodeSetMergeAndClear;
                   12066:     switch (axis) {
                   12067:         case AXIS_ANCESTOR:
                   12068:             first = NULL;
                   12069:             next = xmlXPathNextAncestor;
                   12070:             break;
                   12071:         case AXIS_ANCESTOR_OR_SELF:
                   12072:             first = NULL;
                   12073:             next = xmlXPathNextAncestorOrSelf;
                   12074:             break;
                   12075:         case AXIS_ATTRIBUTE:
                   12076:             first = NULL;
                   12077:            last = NULL;
                   12078:             next = xmlXPathNextAttribute;
                   12079:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12080:             break;
                   12081:         case AXIS_CHILD:
                   12082:            last = NULL;
                   12083:            if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
                   12084:                /*
                   12085:                * This iterator will give us only nodes which can
                   12086:                * hold element nodes.
                   12087:                */
                   12088:                outerNext = xmlXPathNextDescendantOrSelfElemParent;
                   12089:            }
                   12090:            if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
                   12091:                (type == NODE_TYPE_NODE))
                   12092:            {
                   12093:                /*
                   12094:                * Optimization if an element node type is 'element'.
                   12095:                */
                   12096:                next = xmlXPathNextChildElement;
                   12097:            } else
                   12098:                next = xmlXPathNextChild;
                   12099:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12100:             break;
                   12101:         case AXIS_DESCENDANT:
                   12102:            last = NULL;
                   12103:             next = xmlXPathNextDescendant;
                   12104:             break;
                   12105:         case AXIS_DESCENDANT_OR_SELF:
                   12106:            last = NULL;
                   12107:             next = xmlXPathNextDescendantOrSelf;
                   12108:             break;
                   12109:         case AXIS_FOLLOWING:
                   12110:            last = NULL;
                   12111:             next = xmlXPathNextFollowing;
                   12112:             break;
                   12113:         case AXIS_FOLLOWING_SIBLING:
                   12114:            last = NULL;
                   12115:             next = xmlXPathNextFollowingSibling;
                   12116:             break;
                   12117:         case AXIS_NAMESPACE:
                   12118:             first = NULL;
                   12119:            last = NULL;
                   12120:             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
                   12121:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12122:             break;
                   12123:         case AXIS_PARENT:
                   12124:             first = NULL;
                   12125:             next = xmlXPathNextParent;
                   12126:             break;
                   12127:         case AXIS_PRECEDING:
                   12128:             first = NULL;
                   12129:             next = xmlXPathNextPrecedingInternal;
                   12130:             break;
                   12131:         case AXIS_PRECEDING_SIBLING:
                   12132:             first = NULL;
                   12133:             next = xmlXPathNextPrecedingSibling;
                   12134:             break;
                   12135:         case AXIS_SELF:
                   12136:             first = NULL;
                   12137:            last = NULL;
                   12138:             next = xmlXPathNextSelf;
                   12139:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12140:             break;
                   12141:     }
                   12142: 
                   12143: #ifdef DEBUG_STEP
                   12144:     xmlXPathDebugDumpStepAxis(op,
                   12145:        (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
                   12146: #endif
                   12147: 
                   12148:     if (next == NULL) {
                   12149:        xmlXPathReleaseObject(xpctxt, obj);
                   12150:         return(0);
                   12151:     }
                   12152:     contextSeq = obj->nodesetval;
                   12153:     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
                   12154:        xmlXPathReleaseObject(xpctxt, obj);
                   12155:         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
                   12156:         return(0);
                   12157:     }
                   12158:     /*
                   12159:     * Predicate optimization ---------------------------------------------
                   12160:     * If this step has a last predicate, which contains a position(),
                   12161:     * then we'll optimize (although not exactly "position()", but only
                   12162:     * the  short-hand form, i.e., "[n]".
                   12163:     *
                   12164:     * Example - expression "/foo[parent::bar][1]":
                   12165:     *
                   12166:     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
                   12167:     *   ROOT                               -- op->ch1
                   12168:     *   PREDICATE                          -- op->ch2 (predOp)
                   12169:     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
                   12170:     *       SORT
                   12171:     *         COLLECT  'parent' 'name' 'node' bar
                   12172:     *           NODE
                   12173:     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
                   12174:     *
                   12175:     */
                   12176:     maxPos = 0;
                   12177:     predOp = NULL;
                   12178:     hasPredicateRange = 0;
                   12179:     hasAxisRange = 0;
                   12180:     if (op->ch2 != -1) {
                   12181:        /*
                   12182:        * There's at least one predicate. 16 == XPATH_OP_PREDICATE
                   12183:        */
                   12184:        predOp = &ctxt->comp->steps[op->ch2];
                   12185:        if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
                   12186:            if (predOp->ch1 != -1) {
                   12187:                /*
                   12188:                * Use the next inner predicate operator.
                   12189:                */
                   12190:                predOp = &ctxt->comp->steps[predOp->ch1];
                   12191:                hasPredicateRange = 1;
                   12192:            } else {
                   12193:                /*
                   12194:                * There's no other predicate than the [n] predicate.
                   12195:                */
                   12196:                predOp = NULL;
                   12197:                hasAxisRange = 1;
                   12198:            }
                   12199:        }
                   12200:     }
                   12201:     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
                   12202:     /*
                   12203:     * Axis traversal -----------------------------------------------------
                   12204:     */
                   12205:     /*
                   12206:      * 2.3 Node Tests
                   12207:      *  - For the attribute axis, the principal node type is attribute.
                   12208:      *  - For the namespace axis, the principal node type is namespace.
                   12209:      *  - For other axes, the principal node type is element.
                   12210:      *
                   12211:      * A node test * is true for any node of the
                   12212:      * principal node type. For example, child::* will
                   12213:      * select all element children of the context node
                   12214:      */
                   12215:     oldContextNode = xpctxt->node;
                   12216:     addNode = xmlXPathNodeSetAddUnique;
                   12217:     outSeq = NULL;
                   12218:     seq = NULL;
                   12219:     outerContextNode = NULL;
                   12220:     contextNode = NULL;
                   12221:     contextIdx = 0;
                   12222: 
                   12223: 
                   12224:     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
                   12225:        if (outerNext != NULL) {
                   12226:            /*
                   12227:            * This is a compound traversal.
                   12228:            */
                   12229:            if (contextNode == NULL) {
                   12230:                /*
                   12231:                * Set the context for the outer traversal.
                   12232:                */
                   12233:                outerContextNode = contextSeq->nodeTab[contextIdx++];
                   12234:                contextNode = outerNext(NULL, outerContextNode);
                   12235:            } else
                   12236:                contextNode = outerNext(contextNode, outerContextNode);
                   12237:            if (contextNode == NULL)
                   12238:                continue;
                   12239:            /*
                   12240:            * Set the context for the main traversal.
                   12241:            */
                   12242:            xpctxt->node = contextNode;
                   12243:        } else
                   12244:            xpctxt->node = contextSeq->nodeTab[contextIdx++];
                   12245: 
                   12246:        if (seq == NULL) {
                   12247:            seq = xmlXPathNodeSetCreate(NULL);
                   12248:            if (seq == NULL) {
                   12249:                total = 0;
                   12250:                goto error;
                   12251:            }
                   12252:        }
                   12253:        /*
                   12254:        * Traverse the axis and test the nodes.
                   12255:        */
                   12256:        pos = 0;
                   12257:        cur = NULL;
                   12258:        hasNsNodes = 0;
                   12259:         do {
                   12260:             cur = next(ctxt, cur);
                   12261:             if (cur == NULL)
                   12262:                 break;
                   12263: 
                   12264:            /*
                   12265:            * QUESTION TODO: What does the "first" and "last" stuff do?
                   12266:            */
                   12267:             if ((first != NULL) && (*first != NULL)) {
                   12268:                if (*first == cur)
                   12269:                    break;
                   12270:                if (((total % 256) == 0) &&
                   12271: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   12272:                    (xmlXPathCmpNodesExt(*first, cur) >= 0))
                   12273: #else
                   12274:                    (xmlXPathCmpNodes(*first, cur) >= 0))
                   12275: #endif
                   12276:                {
                   12277:                    break;
                   12278:                }
                   12279:            }
                   12280:            if ((last != NULL) && (*last != NULL)) {
                   12281:                if (*last == cur)
                   12282:                    break;
                   12283:                if (((total % 256) == 0) &&
                   12284: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   12285:                    (xmlXPathCmpNodesExt(cur, *last) >= 0))
                   12286: #else
                   12287:                    (xmlXPathCmpNodes(cur, *last) >= 0))
                   12288: #endif
                   12289:                {
                   12290:                    break;
                   12291:                }
                   12292:            }
                   12293: 
                   12294:             total++;
                   12295: 
                   12296: #ifdef DEBUG_STEP
                   12297:             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
                   12298: #endif
                   12299: 
                   12300:            switch (test) {
                   12301:                 case NODE_TEST_NONE:
                   12302:                    total = 0;
                   12303:                     STRANGE
                   12304:                    goto error;
                   12305:                 case NODE_TEST_TYPE:
                   12306:                    /*
                   12307:                    * TODO: Don't we need to use
                   12308:                    *  xmlXPathNodeSetAddNs() for namespace nodes here?
                   12309:                    *  Surprisingly, some c14n tests fail, if we do this.
                   12310:                    */
                   12311:                    if (type == NODE_TYPE_NODE) {
                   12312:                        switch (cur->type) {
                   12313:                            case XML_DOCUMENT_NODE:
                   12314:                            case XML_HTML_DOCUMENT_NODE:
                   12315: #ifdef LIBXML_DOCB_ENABLED
                   12316:                            case XML_DOCB_DOCUMENT_NODE:
                   12317: #endif
                   12318:                            case XML_ELEMENT_NODE:
                   12319:                            case XML_ATTRIBUTE_NODE:
                   12320:                            case XML_PI_NODE:
                   12321:                            case XML_COMMENT_NODE:
                   12322:                            case XML_CDATA_SECTION_NODE:
                   12323:                            case XML_TEXT_NODE:
                   12324:                            case XML_NAMESPACE_DECL:
                   12325:                                XP_TEST_HIT
                   12326:                                break;
                   12327:                            default:
                   12328:                                break;
                   12329:                        }
                   12330:                    } else if (cur->type == type) {
                   12331:                        if (type == XML_NAMESPACE_DECL)
                   12332:                            XP_TEST_HIT_NS
                   12333:                        else
                   12334:                            XP_TEST_HIT
                   12335:                    } else if ((type == NODE_TYPE_TEXT) &&
                   12336:                         (cur->type == XML_CDATA_SECTION_NODE))
                   12337:                    {
                   12338:                        XP_TEST_HIT
                   12339:                    }
                   12340:                    break;
                   12341:                 case NODE_TEST_PI:
                   12342:                     if ((cur->type == XML_PI_NODE) &&
                   12343:                         ((name == NULL) || xmlStrEqual(name, cur->name)))
                   12344:                    {
                   12345:                        XP_TEST_HIT
                   12346:                     }
                   12347:                     break;
                   12348:                 case NODE_TEST_ALL:
                   12349:                     if (axis == AXIS_ATTRIBUTE) {
                   12350:                         if (cur->type == XML_ATTRIBUTE_NODE)
                   12351:                        {
                   12352:                            XP_TEST_HIT
                   12353:                         }
                   12354:                     } else if (axis == AXIS_NAMESPACE) {
                   12355:                         if (cur->type == XML_NAMESPACE_DECL)
                   12356:                        {
                   12357:                            XP_TEST_HIT_NS
                   12358:                         }
                   12359:                     } else {
                   12360:                         if (cur->type == XML_ELEMENT_NODE) {
                   12361:                             if (prefix == NULL)
                   12362:                            {
                   12363:                                XP_TEST_HIT
                   12364: 
                   12365:                             } else if ((cur->ns != NULL) &&
                   12366:                                (xmlStrEqual(URI, cur->ns->href)))
                   12367:                            {
                   12368:                                XP_TEST_HIT
                   12369:                             }
                   12370:                         }
                   12371:                     }
                   12372:                     break;
                   12373:                 case NODE_TEST_NS:{
                   12374:                         TODO;
                   12375:                         break;
                   12376:                     }
                   12377:                 case NODE_TEST_NAME:
                   12378:                     if (axis == AXIS_ATTRIBUTE) {
                   12379:                         if (cur->type != XML_ATTRIBUTE_NODE)
                   12380:                            break;
                   12381:                    } else if (axis == AXIS_NAMESPACE) {
                   12382:                         if (cur->type != XML_NAMESPACE_DECL)
                   12383:                            break;
                   12384:                    } else {
                   12385:                        if (cur->type != XML_ELEMENT_NODE)
                   12386:                            break;
                   12387:                    }
                   12388:                     switch (cur->type) {
                   12389:                         case XML_ELEMENT_NODE:
                   12390:                             if (xmlStrEqual(name, cur->name)) {
                   12391:                                 if (prefix == NULL) {
                   12392:                                     if (cur->ns == NULL)
                   12393:                                    {
                   12394:                                        XP_TEST_HIT
                   12395:                                     }
                   12396:                                 } else {
                   12397:                                     if ((cur->ns != NULL) &&
                   12398:                                         (xmlStrEqual(URI, cur->ns->href)))
                   12399:                                    {
                   12400:                                        XP_TEST_HIT
                   12401:                                     }
                   12402:                                 }
                   12403:                             }
                   12404:                             break;
                   12405:                         case XML_ATTRIBUTE_NODE:{
                   12406:                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
                   12407: 
                   12408:                                 if (xmlStrEqual(name, attr->name)) {
                   12409:                                     if (prefix == NULL) {
                   12410:                                         if ((attr->ns == NULL) ||
                   12411:                                             (attr->ns->prefix == NULL))
                   12412:                                        {
                   12413:                                            XP_TEST_HIT
                   12414:                                         }
                   12415:                                     } else {
                   12416:                                         if ((attr->ns != NULL) &&
                   12417:                                             (xmlStrEqual(URI,
                   12418:                                              attr->ns->href)))
                   12419:                                        {
                   12420:                                            XP_TEST_HIT
                   12421:                                         }
                   12422:                                     }
                   12423:                                 }
                   12424:                                 break;
                   12425:                             }
                   12426:                         case XML_NAMESPACE_DECL:
                   12427:                             if (cur->type == XML_NAMESPACE_DECL) {
                   12428:                                 xmlNsPtr ns = (xmlNsPtr) cur;
                   12429: 
                   12430:                                 if ((ns->prefix != NULL) && (name != NULL)
                   12431:                                     && (xmlStrEqual(ns->prefix, name)))
                   12432:                                {
                   12433:                                    XP_TEST_HIT_NS
                   12434:                                 }
                   12435:                             }
                   12436:                             break;
                   12437:                         default:
                   12438:                             break;
                   12439:                     }
                   12440:                     break;
                   12441:            } /* switch(test) */
                   12442:         } while (cur != NULL);
                   12443: 
                   12444:        goto apply_predicates;
                   12445: 
                   12446: axis_range_end: /* ----------------------------------------------------- */
                   12447:        /*
                   12448:        * We have a "/foo[n]", and position() = n was reached.
                   12449:        * Note that we can have as well "/foo/::parent::foo[1]", so
                   12450:        * a duplicate-aware merge is still needed.
                   12451:        * Merge with the result.
                   12452:        */
                   12453:        if (outSeq == NULL) {
                   12454:            outSeq = seq;
                   12455:            seq = NULL;
                   12456:        } else
                   12457:            outSeq = mergeAndClear(outSeq, seq, 0);
                   12458:        /*
                   12459:        * Break if only a true/false result was requested.
                   12460:        */
                   12461:        if (toBool)
                   12462:            break;
                   12463:        continue;
                   12464: 
                   12465: first_hit: /* ---------------------------------------------------------- */
                   12466:        /*
                   12467:        * Break if only a true/false result was requested and
                   12468:        * no predicates existed and a node test succeeded.
                   12469:        */
                   12470:        if (outSeq == NULL) {
                   12471:            outSeq = seq;
                   12472:            seq = NULL;
                   12473:        } else
                   12474:            outSeq = mergeAndClear(outSeq, seq, 0);
                   12475:        break;
                   12476: 
                   12477: #ifdef DEBUG_STEP
                   12478:        if (seq != NULL)
                   12479:            nbMatches += seq->nodeNr;
                   12480: #endif
                   12481: 
                   12482: apply_predicates: /* --------------------------------------------------- */
                   12483:         /*
                   12484:        * Apply predicates.
                   12485:        */
                   12486:         if ((predOp != NULL) && (seq->nodeNr > 0)) {
                   12487:            /*
                   12488:            * E.g. when we have a "/foo[some expression][n]".
                   12489:            */      
                   12490:            /*
                   12491:            * QUESTION TODO: The old predicate evaluation took into
                   12492:            *  account location-sets.
                   12493:            *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
                   12494:            *  Do we expect such a set here?
                   12495:            *  All what I learned now from the evaluation semantics
                   12496:            *  does not indicate that a location-set will be processed
                   12497:            *  here, so this looks OK.
                   12498:            */      
                   12499:            /*
                   12500:            * Iterate over all predicates, starting with the outermost
                   12501:            * predicate.
                   12502:            * TODO: Problem: we cannot execute the inner predicates first
                   12503:            *  since we cannot go back *up* the operator tree!
                   12504:            *  Options we have:
                   12505:            *  1) Use of recursive functions (like is it currently done
                   12506:            *     via xmlXPathCompOpEval())
                   12507:            *  2) Add a predicate evaluation information stack to the
                   12508:            *     context struct
                   12509:            *  3) Change the way the operators are linked; we need a
                   12510:            *     "parent" field on xmlXPathStepOp
                   12511:            *
                   12512:            * For the moment, I'll try to solve this with a recursive
                   12513:            * function: xmlXPathCompOpEvalPredicate().
                   12514:            */
                   12515:            size = seq->nodeNr;
                   12516:            if (hasPredicateRange != 0)
                   12517:                newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
                   12518:                    predOp, seq, size, maxPos, maxPos, hasNsNodes);
                   12519:            else
                   12520:                newSize = xmlXPathCompOpEvalPredicate(ctxt,
                   12521:                    predOp, seq, size, hasNsNodes);
                   12522: 
                   12523:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   12524:                total = 0;
                   12525:                goto error;
                   12526:            }
                   12527:            /*
                   12528:            * Add the filtered set of nodes to the result node set.
                   12529:            */
                   12530:            if (newSize == 0) {
                   12531:                /*
                   12532:                * The predicates filtered all nodes out.
                   12533:                */
                   12534:                xmlXPathNodeSetClear(seq, hasNsNodes);
                   12535:            } else if (seq->nodeNr > 0) {
                   12536:                /*
                   12537:                * Add to result set.
                   12538:                */
                   12539:                if (outSeq == NULL) {
                   12540:                    if (size != newSize) {
                   12541:                        /*
                   12542:                        * We need to merge and clear here, since
                   12543:                        * the sequence will contained NULLed entries.
                   12544:                        */
                   12545:                        outSeq = mergeAndClear(NULL, seq, 1);
                   12546:                    } else {
                   12547:                        outSeq = seq;
                   12548:                        seq = NULL;
                   12549:                    }
                   12550:                } else
                   12551:                    outSeq = mergeAndClear(outSeq, seq,
                   12552:                        (size != newSize) ? 1: 0);
                   12553:                /*
                   12554:                * Break if only a true/false result was requested.
                   12555:                */
                   12556:                if (toBool)
                   12557:                    break;
                   12558:            }
                   12559:         } else if (seq->nodeNr > 0) {
                   12560:            /*
                   12561:            * Add to result set.
                   12562:            */
                   12563:            if (outSeq == NULL) {
                   12564:                outSeq = seq;
                   12565:                seq = NULL;
                   12566:            } else {
                   12567:                outSeq = mergeAndClear(outSeq, seq, 0);
                   12568:            }
                   12569:        }
                   12570:     }
                   12571: 
                   12572: error:
                   12573:     if ((obj->boolval) && (obj->user != NULL)) {
                   12574:        /*
                   12575:        * QUESTION TODO: What does this do and why?
                   12576:        * TODO: Do we have to do this also for the "error"
                   12577:        * cleanup further down?
                   12578:        */
                   12579:        ctxt->value->boolval = 1;
                   12580:        ctxt->value->user = obj->user;
                   12581:        obj->user = NULL;
                   12582:        obj->boolval = 0;
                   12583:     }
                   12584:     xmlXPathReleaseObject(xpctxt, obj);
                   12585: 
                   12586:     /*
                   12587:     * Ensure we return at least an emtpy set.
                   12588:     */
                   12589:     if (outSeq == NULL) {
                   12590:        if ((seq != NULL) && (seq->nodeNr == 0))
                   12591:            outSeq = seq;
                   12592:        else
                   12593:            outSeq = xmlXPathNodeSetCreate(NULL);
                   12594:         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
                   12595:     }
                   12596:     if ((seq != NULL) && (seq != outSeq)) {
                   12597:         xmlXPathFreeNodeSet(seq);
                   12598:     }
                   12599:     /*
                   12600:     * Hand over the result. Better to push the set also in
                   12601:     * case of errors.
                   12602:     */
                   12603:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
                   12604:     /*
                   12605:     * Reset the context node.
                   12606:     */
                   12607:     xpctxt->node = oldContextNode;
                   12608: 
                   12609: #ifdef DEBUG_STEP
                   12610:     xmlGenericError(xmlGenericErrorContext,
                   12611:        "\nExamined %d nodes, found %d nodes at that step\n",
                   12612:        total, nbMatches);
                   12613: #endif
                   12614: 
                   12615:     return(total);
                   12616: }
                   12617: 
                   12618: static int
                   12619: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
                   12620:                              xmlXPathStepOpPtr op, xmlNodePtr * first);
                   12621: 
                   12622: /**
                   12623:  * xmlXPathCompOpEvalFirst:
                   12624:  * @ctxt:  the XPath parser context with the compiled expression
                   12625:  * @op:  an XPath compiled operation
                   12626:  * @first:  the first elem found so far
                   12627:  *
                   12628:  * Evaluate the Precompiled XPath operation searching only the first
                   12629:  * element in document order
                   12630:  *
                   12631:  * Returns the number of examined objects.
                   12632:  */
                   12633: static int
                   12634: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
                   12635:                         xmlXPathStepOpPtr op, xmlNodePtr * first)
                   12636: {
                   12637:     int total = 0, cur;
                   12638:     xmlXPathCompExprPtr comp;
                   12639:     xmlXPathObjectPtr arg1, arg2;
                   12640: 
                   12641:     CHECK_ERROR0;
                   12642:     comp = ctxt->comp;
                   12643:     switch (op->op) {
                   12644:         case XPATH_OP_END:
                   12645:             return (0);
                   12646:         case XPATH_OP_UNION:
                   12647:             total =
                   12648:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
                   12649:                                         first);
                   12650:            CHECK_ERROR0;
                   12651:             if ((ctxt->value != NULL)
                   12652:                 && (ctxt->value->type == XPATH_NODESET)
                   12653:                 && (ctxt->value->nodesetval != NULL)
                   12654:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
                   12655:                 /*
                   12656:                  * limit tree traversing to first node in the result
                   12657:                  */
                   12658:                /*
                   12659:                * OPTIMIZE TODO: This implicitely sorts
                   12660:                *  the result, even if not needed. E.g. if the argument
                   12661:                *  of the count() function, no sorting is needed.
                   12662:                * OPTIMIZE TODO: How do we know if the node-list wasn't
                   12663:                *  aready sorted?
                   12664:                */
                   12665:                if (ctxt->value->nodesetval->nodeNr > 1)
                   12666:                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12667:                 *first = ctxt->value->nodesetval->nodeTab[0];
                   12668:             }
                   12669:             cur =
                   12670:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
                   12671:                                         first);
                   12672:            CHECK_ERROR0;
                   12673:             CHECK_TYPE0(XPATH_NODESET);
                   12674:             arg2 = valuePop(ctxt);
                   12675: 
                   12676:             CHECK_TYPE0(XPATH_NODESET);
                   12677:             arg1 = valuePop(ctxt);
                   12678: 
                   12679:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                   12680:                                                     arg2->nodesetval);
                   12681:             valuePush(ctxt, arg1);
                   12682:            xmlXPathReleaseObject(ctxt->context, arg2);
                   12683:             /* optimizer */
                   12684:            if (total > cur)
                   12685:                xmlXPathCompSwap(op);
                   12686:             return (total + cur);
                   12687:         case XPATH_OP_ROOT:
                   12688:             xmlXPathRoot(ctxt);
                   12689:             return (0);
                   12690:         case XPATH_OP_NODE:
                   12691:             if (op->ch1 != -1)
                   12692:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12693:            CHECK_ERROR0;
                   12694:             if (op->ch2 != -1)
                   12695:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12696:            CHECK_ERROR0;
                   12697:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   12698:                ctxt->context->node));
                   12699:             return (total);
                   12700:         case XPATH_OP_RESET:
                   12701:             if (op->ch1 != -1)
                   12702:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12703:            CHECK_ERROR0;
                   12704:             if (op->ch2 != -1)
                   12705:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12706:            CHECK_ERROR0;
                   12707:             ctxt->context->node = NULL;
                   12708:             return (total);
                   12709:         case XPATH_OP_COLLECT:{
                   12710:                 if (op->ch1 == -1)
                   12711:                     return (total);
                   12712: 
                   12713:                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12714:                CHECK_ERROR0;
                   12715: 
                   12716:                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
                   12717:                 return (total);
                   12718:             }
                   12719:         case XPATH_OP_VALUE:
                   12720:             valuePush(ctxt,
                   12721:                       xmlXPathCacheObjectCopy(ctxt->context,
                   12722:                        (xmlXPathObjectPtr) op->value4));
                   12723:             return (0);
                   12724:         case XPATH_OP_SORT:
                   12725:             if (op->ch1 != -1)
                   12726:                 total +=
                   12727:                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
                   12728:                                             first);
                   12729:            CHECK_ERROR0;
                   12730:             if ((ctxt->value != NULL)
                   12731:                 && (ctxt->value->type == XPATH_NODESET)
                   12732:                 && (ctxt->value->nodesetval != NULL)
                   12733:                && (ctxt->value->nodesetval->nodeNr > 1))
                   12734:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12735:             return (total);
                   12736: #ifdef XP_OPTIMIZED_FILTER_FIRST
                   12737:        case XPATH_OP_FILTER:
                   12738:                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
                   12739:             return (total);
                   12740: #endif
                   12741:         default:
                   12742:             return (xmlXPathCompOpEval(ctxt, op));
                   12743:     }
                   12744: }
                   12745: 
                   12746: /**
                   12747:  * xmlXPathCompOpEvalLast:
                   12748:  * @ctxt:  the XPath parser context with the compiled expression
                   12749:  * @op:  an XPath compiled operation
                   12750:  * @last:  the last elem found so far
                   12751:  *
                   12752:  * Evaluate the Precompiled XPath operation searching only the last
                   12753:  * element in document order
                   12754:  *
                   12755:  * Returns the number of nodes traversed
                   12756:  */
                   12757: static int
                   12758: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
                   12759:                        xmlNodePtr * last)
                   12760: {
                   12761:     int total = 0, cur;
                   12762:     xmlXPathCompExprPtr comp;
                   12763:     xmlXPathObjectPtr arg1, arg2;
                   12764:     xmlNodePtr bak;
                   12765:     xmlDocPtr bakd;
                   12766:     int pp;
                   12767:     int cs;
                   12768: 
                   12769:     CHECK_ERROR0;
                   12770:     comp = ctxt->comp;
                   12771:     switch (op->op) {
                   12772:         case XPATH_OP_END:
                   12773:             return (0);
                   12774:         case XPATH_OP_UNION:
                   12775:            bakd = ctxt->context->doc;
                   12776:            bak = ctxt->context->node;
                   12777:            pp = ctxt->context->proximityPosition;
                   12778:            cs = ctxt->context->contextSize;
                   12779:             total =
                   12780:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
                   12781:            CHECK_ERROR0;
                   12782:             if ((ctxt->value != NULL)
                   12783:                 && (ctxt->value->type == XPATH_NODESET)
                   12784:                 && (ctxt->value->nodesetval != NULL)
                   12785:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
                   12786:                 /*
                   12787:                  * limit tree traversing to first node in the result
                   12788:                  */
                   12789:                if (ctxt->value->nodesetval->nodeNr > 1)
                   12790:                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12791:                 *last =
                   12792:                     ctxt->value->nodesetval->nodeTab[ctxt->value->
                   12793:                                                      nodesetval->nodeNr -
                   12794:                                                      1];
                   12795:             }
                   12796:            ctxt->context->doc = bakd;
                   12797:            ctxt->context->node = bak;
                   12798:            ctxt->context->proximityPosition = pp;
                   12799:            ctxt->context->contextSize = cs;
                   12800:             cur =
                   12801:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
                   12802:            CHECK_ERROR0;
                   12803:             if ((ctxt->value != NULL)
                   12804:                 && (ctxt->value->type == XPATH_NODESET)
                   12805:                 && (ctxt->value->nodesetval != NULL)
                   12806:                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
                   12807:             }
                   12808:             CHECK_TYPE0(XPATH_NODESET);
                   12809:             arg2 = valuePop(ctxt);
                   12810: 
                   12811:             CHECK_TYPE0(XPATH_NODESET);
                   12812:             arg1 = valuePop(ctxt);
                   12813: 
                   12814:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                   12815:                                                     arg2->nodesetval);
                   12816:             valuePush(ctxt, arg1);
                   12817:            xmlXPathReleaseObject(ctxt->context, arg2);
                   12818:             /* optimizer */
                   12819:            if (total > cur)
                   12820:                xmlXPathCompSwap(op);
                   12821:             return (total + cur);
                   12822:         case XPATH_OP_ROOT:
                   12823:             xmlXPathRoot(ctxt);
                   12824:             return (0);
                   12825:         case XPATH_OP_NODE:
                   12826:             if (op->ch1 != -1)
                   12827:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12828:            CHECK_ERROR0;
                   12829:             if (op->ch2 != -1)
                   12830:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12831:            CHECK_ERROR0;
                   12832:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   12833:                ctxt->context->node));
                   12834:             return (total);
                   12835:         case XPATH_OP_RESET:
                   12836:             if (op->ch1 != -1)
                   12837:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12838:            CHECK_ERROR0;
                   12839:             if (op->ch2 != -1)
                   12840:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12841:            CHECK_ERROR0;
                   12842:             ctxt->context->node = NULL;
                   12843:             return (total);
                   12844:         case XPATH_OP_COLLECT:{
                   12845:                 if (op->ch1 == -1)
                   12846:                     return (0);
                   12847: 
                   12848:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12849:                CHECK_ERROR0;
                   12850: 
                   12851:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
                   12852:                 return (total);
                   12853:             }
                   12854:         case XPATH_OP_VALUE:
                   12855:             valuePush(ctxt,
                   12856:                       xmlXPathCacheObjectCopy(ctxt->context,
                   12857:                        (xmlXPathObjectPtr) op->value4));
                   12858:             return (0);
                   12859:         case XPATH_OP_SORT:
                   12860:             if (op->ch1 != -1)
                   12861:                 total +=
                   12862:                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
                   12863:                                            last);
                   12864:            CHECK_ERROR0;
                   12865:             if ((ctxt->value != NULL)
                   12866:                 && (ctxt->value->type == XPATH_NODESET)
                   12867:                 && (ctxt->value->nodesetval != NULL)
                   12868:                && (ctxt->value->nodesetval->nodeNr > 1))
                   12869:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12870:             return (total);
                   12871:         default:
                   12872:             return (xmlXPathCompOpEval(ctxt, op));
                   12873:     }
                   12874: }
                   12875: 
                   12876: #ifdef XP_OPTIMIZED_FILTER_FIRST
                   12877: static int
                   12878: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
                   12879:                              xmlXPathStepOpPtr op, xmlNodePtr * first)
                   12880: {
                   12881:     int total = 0;
                   12882:     xmlXPathCompExprPtr comp;
                   12883:     xmlXPathObjectPtr res;
                   12884:     xmlXPathObjectPtr obj;
                   12885:     xmlNodeSetPtr oldset;
                   12886:     xmlNodePtr oldnode;
                   12887:     xmlDocPtr oldDoc;
                   12888:     int i;
                   12889: 
                   12890:     CHECK_ERROR0;
                   12891:     comp = ctxt->comp;
                   12892:     /*
                   12893:     * Optimization for ()[last()] selection i.e. the last elem
                   12894:     */
                   12895:     if ((op->ch1 != -1) && (op->ch2 != -1) &&
                   12896:        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
                   12897:        (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
                   12898:        int f = comp->steps[op->ch2].ch1;
                   12899: 
                   12900:        if ((f != -1) &&
                   12901:            (comp->steps[f].op == XPATH_OP_FUNCTION) &&
                   12902:            (comp->steps[f].value5 == NULL) &&
                   12903:            (comp->steps[f].value == 0) &&
                   12904:            (comp->steps[f].value4 != NULL) &&
                   12905:            (xmlStrEqual
                   12906:            (comp->steps[f].value4, BAD_CAST "last"))) {
                   12907:            xmlNodePtr last = NULL;
                   12908: 
                   12909:            total +=
                   12910:                xmlXPathCompOpEvalLast(ctxt,
                   12911:                    &comp->steps[op->ch1],
                   12912:                    &last);
                   12913:            CHECK_ERROR0;
                   12914:            /*
                   12915:            * The nodeset should be in document order,
                   12916:            * Keep only the last value
                   12917:            */
                   12918:            if ((ctxt->value != NULL) &&
                   12919:                (ctxt->value->type == XPATH_NODESET) &&
                   12920:                (ctxt->value->nodesetval != NULL) &&
                   12921:                (ctxt->value->nodesetval->nodeTab != NULL) &&
                   12922:                (ctxt->value->nodesetval->nodeNr > 1)) {
                   12923:                ctxt->value->nodesetval->nodeTab[0] =
                   12924:                    ctxt->value->nodesetval->nodeTab[ctxt->
                   12925:                    value->
                   12926:                    nodesetval->
                   12927:                    nodeNr -
                   12928:                    1];
                   12929:                ctxt->value->nodesetval->nodeNr = 1;
                   12930:                *first = *(ctxt->value->nodesetval->nodeTab);
                   12931:            }
                   12932:            return (total);
                   12933:        }
                   12934:     }
                   12935: 
                   12936:     if (op->ch1 != -1)
                   12937:        total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12938:     CHECK_ERROR0;
                   12939:     if (op->ch2 == -1)
                   12940:        return (total);
                   12941:     if (ctxt->value == NULL)
                   12942:        return (total);
                   12943: 
                   12944: #ifdef LIBXML_XPTR_ENABLED
                   12945:     oldnode = ctxt->context->node;
                   12946:     /*
                   12947:     * Hum are we filtering the result of an XPointer expression
                   12948:     */
                   12949:     if (ctxt->value->type == XPATH_LOCATIONSET) {
                   12950:        xmlXPathObjectPtr tmp = NULL;
                   12951:        xmlLocationSetPtr newlocset = NULL;
                   12952:        xmlLocationSetPtr oldlocset;
                   12953: 
                   12954:        /*
                   12955:        * Extract the old locset, and then evaluate the result of the
                   12956:        * expression for all the element in the locset. use it to grow
                   12957:        * up a new locset.
                   12958:        */
                   12959:        CHECK_TYPE0(XPATH_LOCATIONSET);
                   12960:        obj = valuePop(ctxt);
                   12961:        oldlocset = obj->user;
                   12962:        ctxt->context->node = NULL;
                   12963: 
                   12964:        if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
                   12965:            ctxt->context->contextSize = 0;
                   12966:            ctxt->context->proximityPosition = 0;
                   12967:            if (op->ch2 != -1)
                   12968:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12969:            res = valuePop(ctxt);
                   12970:            if (res != NULL) {
                   12971:                xmlXPathReleaseObject(ctxt->context, res);
                   12972:            }
                   12973:            valuePush(ctxt, obj);
                   12974:            CHECK_ERROR0;
                   12975:            return (total);
                   12976:        }
                   12977:        newlocset = xmlXPtrLocationSetCreate(NULL);
                   12978: 
                   12979:        for (i = 0; i < oldlocset->locNr; i++) {
                   12980:            /*
                   12981:            * Run the evaluation with a node list made of a
                   12982:            * single item in the nodelocset.
                   12983:            */
                   12984:            ctxt->context->node = oldlocset->locTab[i]->user;
                   12985:            ctxt->context->contextSize = oldlocset->locNr;
                   12986:            ctxt->context->proximityPosition = i + 1;
                   12987:            if (tmp == NULL) {
                   12988:                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   12989:                    ctxt->context->node);
                   12990:            } else {
                   12991:                xmlXPathNodeSetAddUnique(tmp->nodesetval,
                   12992:                    ctxt->context->node);
                   12993:            }
                   12994:            valuePush(ctxt, tmp);
                   12995:            if (op->ch2 != -1)
                   12996:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12997:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   12998:                xmlXPathFreeObject(obj);
                   12999:                return(0);
                   13000:            }
                   13001:            /*
                   13002:            * The result of the evaluation need to be tested to
                   13003:            * decided whether the filter succeeded or not
                   13004:            */
                   13005:            res = valuePop(ctxt);
                   13006:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   13007:                xmlXPtrLocationSetAdd(newlocset,
                   13008:                    xmlXPathCacheObjectCopy(ctxt->context,
                   13009:                        oldlocset->locTab[i]));
                   13010:            }
                   13011:            /*
                   13012:            * Cleanup
                   13013:            */
                   13014:            if (res != NULL) {
                   13015:                xmlXPathReleaseObject(ctxt->context, res);
                   13016:            }
                   13017:            if (ctxt->value == tmp) {
                   13018:                valuePop(ctxt);
                   13019:                xmlXPathNodeSetClear(tmp->nodesetval, 1);
                   13020:                /*
                   13021:                * REVISIT TODO: Don't create a temporary nodeset
                   13022:                * for everly iteration.
                   13023:                */
                   13024:                /* OLD: xmlXPathFreeObject(res); */
                   13025:            } else
                   13026:                tmp = NULL;
                   13027:            ctxt->context->node = NULL;
                   13028:            /*
                   13029:            * Only put the first node in the result, then leave.
                   13030:            */
                   13031:            if (newlocset->locNr > 0) {
                   13032:                *first = (xmlNodePtr) oldlocset->locTab[i]->user;
                   13033:                break;
                   13034:            }
                   13035:        }
                   13036:        if (tmp != NULL) {
                   13037:            xmlXPathReleaseObject(ctxt->context, tmp);
                   13038:        }
                   13039:        /*
                   13040:        * The result is used as the new evaluation locset.
                   13041:        */
                   13042:        xmlXPathReleaseObject(ctxt->context, obj);
                   13043:        ctxt->context->node = NULL;
                   13044:        ctxt->context->contextSize = -1;
                   13045:        ctxt->context->proximityPosition = -1;
                   13046:        valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
                   13047:        ctxt->context->node = oldnode;
                   13048:        return (total);
                   13049:     }
                   13050: #endif /* LIBXML_XPTR_ENABLED */
                   13051: 
                   13052:     /*
                   13053:     * Extract the old set, and then evaluate the result of the
                   13054:     * expression for all the element in the set. use it to grow
                   13055:     * up a new set.
                   13056:     */
                   13057:     CHECK_TYPE0(XPATH_NODESET);
                   13058:     obj = valuePop(ctxt);
                   13059:     oldset = obj->nodesetval;
                   13060: 
                   13061:     oldnode = ctxt->context->node;
                   13062:     oldDoc = ctxt->context->doc;
                   13063:     ctxt->context->node = NULL;
                   13064: 
                   13065:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
                   13066:        ctxt->context->contextSize = 0;
                   13067:        ctxt->context->proximityPosition = 0;
                   13068:        /* QUESTION TODO: Why was this code commented out?
                   13069:            if (op->ch2 != -1)
                   13070:                total +=
                   13071:                    xmlXPathCompOpEval(ctxt,
                   13072:                        &comp->steps[op->ch2]);
                   13073:            CHECK_ERROR0;
                   13074:            res = valuePop(ctxt);
                   13075:            if (res != NULL)
                   13076:                xmlXPathFreeObject(res);
                   13077:        */
                   13078:        valuePush(ctxt, obj);
                   13079:        ctxt->context->node = oldnode;
                   13080:        CHECK_ERROR0;
                   13081:     } else {
                   13082:        xmlNodeSetPtr newset;
                   13083:        xmlXPathObjectPtr tmp = NULL;
                   13084:        /*
                   13085:        * Initialize the new set.
                   13086:        * Also set the xpath document in case things like
                   13087:        * key() evaluation are attempted on the predicate
                   13088:        */
                   13089:        newset = xmlXPathNodeSetCreate(NULL);
                   13090:         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
                   13091: 
                   13092:        for (i = 0; i < oldset->nodeNr; i++) {
                   13093:            /*
                   13094:            * Run the evaluation with a node list made of
                   13095:            * a single item in the nodeset.
                   13096:            */
                   13097:            ctxt->context->node = oldset->nodeTab[i];
                   13098:            if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
                   13099:                (oldset->nodeTab[i]->doc != NULL))
                   13100:                ctxt->context->doc = oldset->nodeTab[i]->doc;
                   13101:            if (tmp == NULL) {
                   13102:                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13103:                    ctxt->context->node);
                   13104:            } else {
                   13105:                xmlXPathNodeSetAddUnique(tmp->nodesetval,
                   13106:                    ctxt->context->node);
                   13107:            }
                   13108:            valuePush(ctxt, tmp);
                   13109:            ctxt->context->contextSize = oldset->nodeNr;
                   13110:            ctxt->context->proximityPosition = i + 1;
                   13111:            if (op->ch2 != -1)
                   13112:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13113:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13114:                xmlXPathFreeNodeSet(newset);
                   13115:                xmlXPathFreeObject(obj);
                   13116:                return(0);
                   13117:            }
                   13118:            /*
                   13119:            * The result of the evaluation needs to be tested to
                   13120:            * decide whether the filter succeeded or not
                   13121:            */
                   13122:            res = valuePop(ctxt);
                   13123:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   13124:                xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
                   13125:            }
                   13126:            /*
                   13127:            * Cleanup
                   13128:            */
                   13129:            if (res != NULL) {
                   13130:                xmlXPathReleaseObject(ctxt->context, res);
                   13131:            }
                   13132:            if (ctxt->value == tmp) {
                   13133:                valuePop(ctxt);
                   13134:                /*
                   13135:                * Don't free the temporary nodeset
                   13136:                * in order to avoid massive recreation inside this
                   13137:                * loop.
                   13138:                */
                   13139:                xmlXPathNodeSetClear(tmp->nodesetval, 1);
                   13140:            } else
                   13141:                tmp = NULL;
                   13142:            ctxt->context->node = NULL;
                   13143:            /*
                   13144:            * Only put the first node in the result, then leave.
                   13145:            */
                   13146:            if (newset->nodeNr > 0) {
                   13147:                *first = *(newset->nodeTab);
                   13148:                break;
                   13149:            }
                   13150:        }
                   13151:        if (tmp != NULL) {
                   13152:            xmlXPathReleaseObject(ctxt->context, tmp);
                   13153:        }
                   13154:        /*
                   13155:        * The result is used as the new evaluation set.
                   13156:        */
                   13157:        xmlXPathReleaseObject(ctxt->context, obj);
                   13158:        ctxt->context->node = NULL;
                   13159:        ctxt->context->contextSize = -1;
                   13160:        ctxt->context->proximityPosition = -1;
                   13161:        /* may want to move this past the '}' later */
                   13162:        ctxt->context->doc = oldDoc;
                   13163:        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
                   13164:     }
                   13165:     ctxt->context->node = oldnode;
                   13166:     return(total);
                   13167: }
                   13168: #endif /* XP_OPTIMIZED_FILTER_FIRST */
                   13169: 
                   13170: /**
                   13171:  * xmlXPathCompOpEval:
                   13172:  * @ctxt:  the XPath parser context with the compiled expression
                   13173:  * @op:  an XPath compiled operation
                   13174:  *
                   13175:  * Evaluate the Precompiled XPath operation
                   13176:  * Returns the number of nodes traversed
                   13177:  */
                   13178: static int
                   13179: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
                   13180: {
                   13181:     int total = 0;
                   13182:     int equal, ret;
                   13183:     xmlXPathCompExprPtr comp;
                   13184:     xmlXPathObjectPtr arg1, arg2;
                   13185:     xmlNodePtr bak;
                   13186:     xmlDocPtr bakd;
                   13187:     int pp;
                   13188:     int cs;
                   13189: 
                   13190:     CHECK_ERROR0;
                   13191:     comp = ctxt->comp;
                   13192:     switch (op->op) {
                   13193:         case XPATH_OP_END:
                   13194:             return (0);
                   13195:         case XPATH_OP_AND:
                   13196:            bakd = ctxt->context->doc;
                   13197:            bak = ctxt->context->node;
                   13198:            pp = ctxt->context->proximityPosition;
                   13199:            cs = ctxt->context->contextSize;
                   13200:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13201:            CHECK_ERROR0;
                   13202:             xmlXPathBooleanFunction(ctxt, 1);
                   13203:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
                   13204:                 return (total);
                   13205:             arg2 = valuePop(ctxt);
                   13206:            ctxt->context->doc = bakd;
                   13207:            ctxt->context->node = bak;
                   13208:            ctxt->context->proximityPosition = pp;
                   13209:            ctxt->context->contextSize = cs;
                   13210:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13211:            if (ctxt->error) {
                   13212:                xmlXPathFreeObject(arg2);
                   13213:                return(0);
                   13214:            }
                   13215:             xmlXPathBooleanFunction(ctxt, 1);
                   13216:             arg1 = valuePop(ctxt);
                   13217:             arg1->boolval &= arg2->boolval;
                   13218:             valuePush(ctxt, arg1);
                   13219:            xmlXPathReleaseObject(ctxt->context, arg2);
                   13220:             return (total);
                   13221:         case XPATH_OP_OR:
                   13222:            bakd = ctxt->context->doc;
                   13223:            bak = ctxt->context->node;
                   13224:            pp = ctxt->context->proximityPosition;
                   13225:            cs = ctxt->context->contextSize;
                   13226:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13227:            CHECK_ERROR0;
                   13228:             xmlXPathBooleanFunction(ctxt, 1);
                   13229:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
                   13230:                 return (total);
                   13231:             arg2 = valuePop(ctxt);
                   13232:            ctxt->context->doc = bakd;
                   13233:            ctxt->context->node = bak;
                   13234:            ctxt->context->proximityPosition = pp;
                   13235:            ctxt->context->contextSize = cs;
                   13236:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13237:            if (ctxt->error) {
                   13238:                xmlXPathFreeObject(arg2);
                   13239:                return(0);
                   13240:            }
                   13241:             xmlXPathBooleanFunction(ctxt, 1);
                   13242:             arg1 = valuePop(ctxt);
                   13243:             arg1->boolval |= arg2->boolval;
                   13244:             valuePush(ctxt, arg1);
                   13245:            xmlXPathReleaseObject(ctxt->context, arg2);
                   13246:             return (total);
                   13247:         case XPATH_OP_EQUAL:
                   13248:            bakd = ctxt->context->doc;
                   13249:            bak = ctxt->context->node;
                   13250:            pp = ctxt->context->proximityPosition;
                   13251:            cs = ctxt->context->contextSize;
                   13252:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13253:            CHECK_ERROR0;
                   13254:            ctxt->context->doc = bakd;
                   13255:            ctxt->context->node = bak;
                   13256:            ctxt->context->proximityPosition = pp;
                   13257:            ctxt->context->contextSize = cs;
                   13258:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13259:            CHECK_ERROR0;
                   13260:            if (op->value)
                   13261:                equal = xmlXPathEqualValues(ctxt);
                   13262:            else
                   13263:                equal = xmlXPathNotEqualValues(ctxt);
                   13264:            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
                   13265:             return (total);
                   13266:         case XPATH_OP_CMP:
                   13267:            bakd = ctxt->context->doc;
                   13268:            bak = ctxt->context->node;
                   13269:            pp = ctxt->context->proximityPosition;
                   13270:            cs = ctxt->context->contextSize;
                   13271:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13272:            CHECK_ERROR0;
                   13273:            ctxt->context->doc = bakd;
                   13274:            ctxt->context->node = bak;
                   13275:            ctxt->context->proximityPosition = pp;
                   13276:            ctxt->context->contextSize = cs;
                   13277:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13278:            CHECK_ERROR0;
                   13279:             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
                   13280:            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
                   13281:             return (total);
                   13282:         case XPATH_OP_PLUS:
                   13283:            bakd = ctxt->context->doc;
                   13284:            bak = ctxt->context->node;
                   13285:            pp = ctxt->context->proximityPosition;
                   13286:            cs = ctxt->context->contextSize;
                   13287:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13288:            CHECK_ERROR0;
                   13289:             if (op->ch2 != -1) {
                   13290:                ctxt->context->doc = bakd;
                   13291:                ctxt->context->node = bak;
                   13292:                ctxt->context->proximityPosition = pp;
                   13293:                ctxt->context->contextSize = cs;
                   13294:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13295:            }
                   13296:            CHECK_ERROR0;
                   13297:             if (op->value == 0)
                   13298:                 xmlXPathSubValues(ctxt);
                   13299:             else if (op->value == 1)
                   13300:                 xmlXPathAddValues(ctxt);
                   13301:             else if (op->value == 2)
                   13302:                 xmlXPathValueFlipSign(ctxt);
                   13303:             else if (op->value == 3) {
                   13304:                 CAST_TO_NUMBER;
                   13305:                 CHECK_TYPE0(XPATH_NUMBER);
                   13306:             }
                   13307:             return (total);
                   13308:         case XPATH_OP_MULT:
                   13309:            bakd = ctxt->context->doc;
                   13310:            bak = ctxt->context->node;
                   13311:            pp = ctxt->context->proximityPosition;
                   13312:            cs = ctxt->context->contextSize;
                   13313:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13314:            CHECK_ERROR0;
                   13315:            ctxt->context->doc = bakd;
                   13316:            ctxt->context->node = bak;
                   13317:            ctxt->context->proximityPosition = pp;
                   13318:            ctxt->context->contextSize = cs;
                   13319:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13320:            CHECK_ERROR0;
                   13321:             if (op->value == 0)
                   13322:                 xmlXPathMultValues(ctxt);
                   13323:             else if (op->value == 1)
                   13324:                 xmlXPathDivValues(ctxt);
                   13325:             else if (op->value == 2)
                   13326:                 xmlXPathModValues(ctxt);
                   13327:             return (total);
                   13328:         case XPATH_OP_UNION:
                   13329:            bakd = ctxt->context->doc;
                   13330:            bak = ctxt->context->node;
                   13331:            pp = ctxt->context->proximityPosition;
                   13332:            cs = ctxt->context->contextSize;
                   13333:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13334:            CHECK_ERROR0;
                   13335:            ctxt->context->doc = bakd;
                   13336:            ctxt->context->node = bak;
                   13337:            ctxt->context->proximityPosition = pp;
                   13338:            ctxt->context->contextSize = cs;
                   13339:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13340:            CHECK_ERROR0;
                   13341:             CHECK_TYPE0(XPATH_NODESET);
                   13342:             arg2 = valuePop(ctxt);
                   13343: 
                   13344:             CHECK_TYPE0(XPATH_NODESET);
                   13345:             arg1 = valuePop(ctxt);
                   13346: 
                   13347:            if ((arg1->nodesetval == NULL) ||
                   13348:                ((arg2->nodesetval != NULL) &&
                   13349:                 (arg2->nodesetval->nodeNr != 0)))
                   13350:            {
                   13351:                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                   13352:                                                        arg2->nodesetval);
                   13353:            }
                   13354: 
                   13355:             valuePush(ctxt, arg1);
                   13356:            xmlXPathReleaseObject(ctxt->context, arg2);
                   13357:             return (total);
                   13358:         case XPATH_OP_ROOT:
                   13359:             xmlXPathRoot(ctxt);
                   13360:             return (total);
                   13361:         case XPATH_OP_NODE:
                   13362:             if (op->ch1 != -1)
                   13363:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13364:            CHECK_ERROR0;
                   13365:             if (op->ch2 != -1)
                   13366:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13367:            CHECK_ERROR0;
                   13368:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   13369:                ctxt->context->node));
                   13370:             return (total);
                   13371:         case XPATH_OP_RESET:
                   13372:             if (op->ch1 != -1)
                   13373:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13374:            CHECK_ERROR0;
                   13375:             if (op->ch2 != -1)
                   13376:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13377:            CHECK_ERROR0;
                   13378:             ctxt->context->node = NULL;
                   13379:             return (total);
                   13380:         case XPATH_OP_COLLECT:{
                   13381:                 if (op->ch1 == -1)
                   13382:                     return (total);
                   13383: 
                   13384:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13385:                CHECK_ERROR0;
                   13386: 
                   13387:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
                   13388:                 return (total);
                   13389:             }
                   13390:         case XPATH_OP_VALUE:
                   13391:             valuePush(ctxt,
                   13392:                       xmlXPathCacheObjectCopy(ctxt->context,
                   13393:                        (xmlXPathObjectPtr) op->value4));
                   13394:             return (total);
                   13395:         case XPATH_OP_VARIABLE:{
                   13396:                xmlXPathObjectPtr val;
                   13397: 
                   13398:                 if (op->ch1 != -1)
                   13399:                     total +=
                   13400:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13401:                 if (op->value5 == NULL) {
                   13402:                    val = xmlXPathVariableLookup(ctxt->context, op->value4);
                   13403:                    if (val == NULL) {
                   13404:                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
                   13405:                        return(0);
                   13406:                    }
                   13407:                     valuePush(ctxt, val);
                   13408:                } else {
                   13409:                     const xmlChar *URI;
                   13410: 
                   13411:                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
                   13412:                     if (URI == NULL) {
                   13413:                         xmlGenericError(xmlGenericErrorContext,
                   13414:             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
                   13415:                                     (char *) op->value4, (char *)op->value5);
1.1.1.2 ! misho    13416:                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
1.1       misho    13417:                         return (total);
                   13418:                     }
                   13419:                    val = xmlXPathVariableLookupNS(ctxt->context,
                   13420:                                                        op->value4, URI);
                   13421:                    if (val == NULL) {
                   13422:                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
                   13423:                        return(0);
                   13424:                    }
                   13425:                     valuePush(ctxt, val);
                   13426:                 }
                   13427:                 return (total);
                   13428:             }
                   13429:         case XPATH_OP_FUNCTION:{
                   13430:                 xmlXPathFunction func;
                   13431:                 const xmlChar *oldFunc, *oldFuncURI;
                   13432:                int i;
1.1.1.2 ! misho    13433:                 int frame;
1.1       misho    13434: 
1.1.1.2 ! misho    13435:                 frame = xmlXPathSetFrame(ctxt);
1.1       misho    13436:                 if (op->ch1 != -1)
                   13437:                     total +=
                   13438:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13439:                if (ctxt->valueNr < op->value) {
                   13440:                    xmlGenericError(xmlGenericErrorContext,
                   13441:                            "xmlXPathCompOpEval: parameter error\n");
                   13442:                    ctxt->error = XPATH_INVALID_OPERAND;
1.1.1.2 ! misho    13443:                     xmlXPathPopFrame(ctxt, frame);
1.1       misho    13444:                    return (total);
                   13445:                }
1.1.1.2 ! misho    13446:                for (i = 0; i < op->value; i++) {
1.1       misho    13447:                    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
                   13448:                        xmlGenericError(xmlGenericErrorContext,
                   13449:                                "xmlXPathCompOpEval: parameter error\n");
                   13450:                        ctxt->error = XPATH_INVALID_OPERAND;
1.1.1.2 ! misho    13451:                         xmlXPathPopFrame(ctxt, frame);
1.1       misho    13452:                        return (total);
                   13453:                    }
1.1.1.2 ! misho    13454:                 }
1.1       misho    13455:                 if (op->cache != NULL)
                   13456:                     XML_CAST_FPTR(func) = op->cache;
                   13457:                 else {
                   13458:                     const xmlChar *URI = NULL;
                   13459: 
                   13460:                     if (op->value5 == NULL)
                   13461:                         func =
                   13462:                             xmlXPathFunctionLookup(ctxt->context,
                   13463:                                                    op->value4);
                   13464:                     else {
                   13465:                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
                   13466:                         if (URI == NULL) {
                   13467:                             xmlGenericError(xmlGenericErrorContext,
                   13468:             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
                   13469:                                     (char *)op->value4, (char *)op->value5);
1.1.1.2 ! misho    13470:                             xmlXPathPopFrame(ctxt, frame);
        !          13471:                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
1.1       misho    13472:                             return (total);
                   13473:                         }
                   13474:                         func = xmlXPathFunctionLookupNS(ctxt->context,
                   13475:                                                         op->value4, URI);
                   13476:                     }
                   13477:                     if (func == NULL) {
                   13478:                         xmlGenericError(xmlGenericErrorContext,
                   13479:                                 "xmlXPathCompOpEval: function %s not found\n",
                   13480:                                         (char *)op->value4);
                   13481:                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
                   13482:                     }
                   13483:                     op->cache = XML_CAST_FPTR(func);
                   13484:                     op->cacheURI = (void *) URI;
                   13485:                 }
                   13486:                 oldFunc = ctxt->context->function;
                   13487:                 oldFuncURI = ctxt->context->functionURI;
                   13488:                 ctxt->context->function = op->value4;
                   13489:                 ctxt->context->functionURI = op->cacheURI;
                   13490:                 func(ctxt, op->value);
                   13491:                 ctxt->context->function = oldFunc;
                   13492:                 ctxt->context->functionURI = oldFuncURI;
1.1.1.2 ! misho    13493:                 xmlXPathPopFrame(ctxt, frame);
1.1       misho    13494:                 return (total);
                   13495:             }
                   13496:         case XPATH_OP_ARG:
                   13497:            bakd = ctxt->context->doc;
                   13498:            bak = ctxt->context->node;
                   13499:            pp = ctxt->context->proximityPosition;
                   13500:            cs = ctxt->context->contextSize;
                   13501:             if (op->ch1 != -1)
                   13502:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13503:            ctxt->context->contextSize = cs;
                   13504:            ctxt->context->proximityPosition = pp;
                   13505:            ctxt->context->node = bak;
                   13506:            ctxt->context->doc = bakd;
                   13507:            CHECK_ERROR0;
                   13508:             if (op->ch2 != -1) {
                   13509:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13510:                ctxt->context->doc = bakd;
                   13511:                ctxt->context->node = bak;
                   13512:                CHECK_ERROR0;
                   13513:            }
                   13514:             return (total);
                   13515:         case XPATH_OP_PREDICATE:
                   13516:         case XPATH_OP_FILTER:{
                   13517:                 xmlXPathObjectPtr res;
                   13518:                 xmlXPathObjectPtr obj, tmp;
                   13519:                 xmlNodeSetPtr newset = NULL;
                   13520:                 xmlNodeSetPtr oldset;
                   13521:                 xmlNodePtr oldnode;
                   13522:                xmlDocPtr oldDoc;
                   13523:                 int i;
                   13524: 
                   13525:                 /*
                   13526:                  * Optimization for ()[1] selection i.e. the first elem
                   13527:                  */
                   13528:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
                   13529: #ifdef XP_OPTIMIZED_FILTER_FIRST
                   13530:                    /*
                   13531:                    * FILTER TODO: Can we assume that the inner processing
                   13532:                    *  will result in an ordered list if we have an
                   13533:                    *  XPATH_OP_FILTER?
                   13534:                    *  What about an additional field or flag on
                   13535:                    *  xmlXPathObject like @sorted ? This way we wouln'd need
                   13536:                    *  to assume anything, so it would be more robust and
                   13537:                    *  easier to optimize.
                   13538:                    */
                   13539:                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
                   13540:                     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
                   13541: #else
                   13542:                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
                   13543: #endif
                   13544:                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
                   13545:                     xmlXPathObjectPtr val;
                   13546: 
                   13547:                     val = comp->steps[op->ch2].value4;
                   13548:                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
                   13549:                         (val->floatval == 1.0)) {
                   13550:                         xmlNodePtr first = NULL;
                   13551: 
                   13552:                         total +=
                   13553:                             xmlXPathCompOpEvalFirst(ctxt,
                   13554:                                                     &comp->steps[op->ch1],
                   13555:                                                     &first);
                   13556:                        CHECK_ERROR0;
                   13557:                         /*
                   13558:                          * The nodeset should be in document order,
                   13559:                          * Keep only the first value
                   13560:                          */
                   13561:                         if ((ctxt->value != NULL) &&
                   13562:                             (ctxt->value->type == XPATH_NODESET) &&
                   13563:                             (ctxt->value->nodesetval != NULL) &&
                   13564:                             (ctxt->value->nodesetval->nodeNr > 1))
                   13565:                             ctxt->value->nodesetval->nodeNr = 1;
                   13566:                         return (total);
                   13567:                     }
                   13568:                 }
                   13569:                 /*
                   13570:                  * Optimization for ()[last()] selection i.e. the last elem
                   13571:                  */
                   13572:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
                   13573:                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
                   13574:                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
                   13575:                     int f = comp->steps[op->ch2].ch1;
                   13576: 
                   13577:                     if ((f != -1) &&
                   13578:                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
                   13579:                         (comp->steps[f].value5 == NULL) &&
                   13580:                         (comp->steps[f].value == 0) &&
                   13581:                         (comp->steps[f].value4 != NULL) &&
                   13582:                         (xmlStrEqual
                   13583:                          (comp->steps[f].value4, BAD_CAST "last"))) {
                   13584:                         xmlNodePtr last = NULL;
                   13585: 
                   13586:                         total +=
                   13587:                             xmlXPathCompOpEvalLast(ctxt,
                   13588:                                                    &comp->steps[op->ch1],
                   13589:                                                    &last);
                   13590:                        CHECK_ERROR0;
                   13591:                         /*
                   13592:                          * The nodeset should be in document order,
                   13593:                          * Keep only the last value
                   13594:                          */
                   13595:                         if ((ctxt->value != NULL) &&
                   13596:                             (ctxt->value->type == XPATH_NODESET) &&
                   13597:                             (ctxt->value->nodesetval != NULL) &&
                   13598:                             (ctxt->value->nodesetval->nodeTab != NULL) &&
                   13599:                             (ctxt->value->nodesetval->nodeNr > 1)) {
                   13600:                             ctxt->value->nodesetval->nodeTab[0] =
                   13601:                                 ctxt->value->nodesetval->nodeTab[ctxt->
                   13602:                                                                  value->
                   13603:                                                                  nodesetval->
                   13604:                                                                  nodeNr -
                   13605:                                                                  1];
                   13606:                             ctxt->value->nodesetval->nodeNr = 1;
                   13607:                         }
                   13608:                         return (total);
                   13609:                     }
                   13610:                 }
                   13611:                /*
                   13612:                * Process inner predicates first.
                   13613:                * Example "index[parent::book][1]":
                   13614:                * ...
                   13615:                *   PREDICATE   <-- we are here "[1]"
                   13616:                *     PREDICATE <-- process "[parent::book]" first
                   13617:                *       SORT
                   13618:                *         COLLECT  'parent' 'name' 'node' book
                   13619:                *           NODE
                   13620:                *     ELEM Object is a number : 1
                   13621:                */
                   13622:                 if (op->ch1 != -1)
                   13623:                     total +=
                   13624:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13625:                CHECK_ERROR0;
                   13626:                 if (op->ch2 == -1)
                   13627:                     return (total);
                   13628:                 if (ctxt->value == NULL)
                   13629:                     return (total);
                   13630: 
                   13631:                 oldnode = ctxt->context->node;
                   13632: 
                   13633: #ifdef LIBXML_XPTR_ENABLED
                   13634:                 /*
                   13635:                  * Hum are we filtering the result of an XPointer expression
                   13636:                  */
                   13637:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
                   13638:                     xmlLocationSetPtr newlocset = NULL;
                   13639:                     xmlLocationSetPtr oldlocset;
                   13640: 
                   13641:                     /*
                   13642:                      * Extract the old locset, and then evaluate the result of the
                   13643:                      * expression for all the element in the locset. use it to grow
                   13644:                      * up a new locset.
                   13645:                      */
                   13646:                     CHECK_TYPE0(XPATH_LOCATIONSET);
                   13647:                     obj = valuePop(ctxt);
                   13648:                     oldlocset = obj->user;
                   13649:                     ctxt->context->node = NULL;
                   13650: 
                   13651:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
                   13652:                         ctxt->context->contextSize = 0;
                   13653:                         ctxt->context->proximityPosition = 0;
                   13654:                         if (op->ch2 != -1)
                   13655:                             total +=
                   13656:                                 xmlXPathCompOpEval(ctxt,
                   13657:                                                    &comp->steps[op->ch2]);
                   13658:                         res = valuePop(ctxt);
                   13659:                         if (res != NULL) {
                   13660:                            xmlXPathReleaseObject(ctxt->context, res);
                   13661:                        }
                   13662:                         valuePush(ctxt, obj);
                   13663:                         CHECK_ERROR0;
                   13664:                         return (total);
                   13665:                     }
                   13666:                     newlocset = xmlXPtrLocationSetCreate(NULL);
                   13667: 
                   13668:                     for (i = 0; i < oldlocset->locNr; i++) {
                   13669:                         /*
                   13670:                          * Run the evaluation with a node list made of a
                   13671:                          * single item in the nodelocset.
                   13672:                          */
                   13673:                         ctxt->context->node = oldlocset->locTab[i]->user;
                   13674:                         ctxt->context->contextSize = oldlocset->locNr;
                   13675:                         ctxt->context->proximityPosition = i + 1;
                   13676:                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13677:                            ctxt->context->node);
                   13678:                         valuePush(ctxt, tmp);
                   13679: 
                   13680:                         if (op->ch2 != -1)
                   13681:                             total +=
                   13682:                                 xmlXPathCompOpEval(ctxt,
                   13683:                                                    &comp->steps[op->ch2]);
                   13684:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13685:                            xmlXPathFreeObject(obj);
                   13686:                            return(0);
                   13687:                        }
                   13688: 
                   13689:                         /*
                   13690:                          * The result of the evaluation need to be tested to
                   13691:                          * decided whether the filter succeeded or not
                   13692:                          */
                   13693:                         res = valuePop(ctxt);
                   13694:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   13695:                             xmlXPtrLocationSetAdd(newlocset,
                   13696:                                                   xmlXPathObjectCopy
                   13697:                                                   (oldlocset->locTab[i]));
                   13698:                         }
                   13699: 
                   13700:                         /*
                   13701:                          * Cleanup
                   13702:                          */
                   13703:                         if (res != NULL) {
                   13704:                            xmlXPathReleaseObject(ctxt->context, res);
                   13705:                        }
                   13706:                         if (ctxt->value == tmp) {
                   13707:                             res = valuePop(ctxt);
                   13708:                            xmlXPathReleaseObject(ctxt->context, res);
                   13709:                         }
                   13710: 
                   13711:                         ctxt->context->node = NULL;
                   13712:                     }
                   13713: 
                   13714:                     /*
                   13715:                      * The result is used as the new evaluation locset.
                   13716:                      */
                   13717:                    xmlXPathReleaseObject(ctxt->context, obj);
                   13718:                     ctxt->context->node = NULL;
                   13719:                     ctxt->context->contextSize = -1;
                   13720:                     ctxt->context->proximityPosition = -1;
                   13721:                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
                   13722:                     ctxt->context->node = oldnode;
                   13723:                     return (total);
                   13724:                 }
                   13725: #endif /* LIBXML_XPTR_ENABLED */
                   13726: 
                   13727:                 /*
                   13728:                  * Extract the old set, and then evaluate the result of the
                   13729:                  * expression for all the element in the set. use it to grow
                   13730:                  * up a new set.
                   13731:                  */
                   13732:                 CHECK_TYPE0(XPATH_NODESET);
                   13733:                 obj = valuePop(ctxt);
                   13734:                 oldset = obj->nodesetval;
                   13735: 
                   13736:                 oldnode = ctxt->context->node;
                   13737:                oldDoc = ctxt->context->doc;
                   13738:                 ctxt->context->node = NULL;
                   13739: 
                   13740:                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
                   13741:                     ctxt->context->contextSize = 0;
                   13742:                     ctxt->context->proximityPosition = 0;
                   13743: /*
                   13744:                     if (op->ch2 != -1)
                   13745:                         total +=
                   13746:                             xmlXPathCompOpEval(ctxt,
                   13747:                                                &comp->steps[op->ch2]);
                   13748:                    CHECK_ERROR0;
                   13749:                     res = valuePop(ctxt);
                   13750:                     if (res != NULL)
                   13751:                         xmlXPathFreeObject(res);
                   13752: */
                   13753:                     valuePush(ctxt, obj);
                   13754:                     ctxt->context->node = oldnode;
                   13755:                     CHECK_ERROR0;
                   13756:                 } else {
                   13757:                    tmp = NULL;
                   13758:                     /*
                   13759:                      * Initialize the new set.
                   13760:                     * Also set the xpath document in case things like
                   13761:                     * key() evaluation are attempted on the predicate
                   13762:                      */
                   13763:                     newset = xmlXPathNodeSetCreate(NULL);
                   13764:                    /*
                   13765:                    * SPEC XPath 1.0:
                   13766:                    *  "For each node in the node-set to be filtered, the
                   13767:                    *  PredicateExpr is evaluated with that node as the
                   13768:                    *  context node, with the number of nodes in the
                   13769:                    *  node-set as the context size, and with the proximity
                   13770:                    *  position of the node in the node-set with respect to
                   13771:                    *  the axis as the context position;"
                   13772:                    * @oldset is the node-set" to be filtered.
                   13773:                    *
                   13774:                    * SPEC XPath 1.0:
                   13775:                    *  "only predicates change the context position and
                   13776:                    *  context size (see [2.4 Predicates])."
                   13777:                    * Example:
                   13778:                    *   node-set  context pos
                   13779:                    *    nA         1
                   13780:                    *    nB         2
                   13781:                    *    nC         3
                   13782:                    *   After applying predicate [position() > 1] :
                   13783:                    *   node-set  context pos
                   13784:                    *    nB         1
                   13785:                    *    nC         2
                   13786:                    *
                   13787:                    * removed the first node in the node-set, then
                   13788:                    * the context position of the
                   13789:                    */
                   13790:                     for (i = 0; i < oldset->nodeNr; i++) {
                   13791:                         /*
                   13792:                          * Run the evaluation with a node list made of
                   13793:                          * a single item in the nodeset.
                   13794:                          */
                   13795:                         ctxt->context->node = oldset->nodeTab[i];
                   13796:                        if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
                   13797:                            (oldset->nodeTab[i]->doc != NULL))
                   13798:                            ctxt->context->doc = oldset->nodeTab[i]->doc;
                   13799:                        if (tmp == NULL) {
                   13800:                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13801:                                ctxt->context->node);
                   13802:                        } else {
                   13803:                            xmlXPathNodeSetAddUnique(tmp->nodesetval,
                   13804:                                ctxt->context->node);
                   13805:                        }
                   13806:                         valuePush(ctxt, tmp);
                   13807:                         ctxt->context->contextSize = oldset->nodeNr;
                   13808:                         ctxt->context->proximityPosition = i + 1;
                   13809:                        /*
                   13810:                        * Evaluate the predicate against the context node.
                   13811:                        * Can/should we optimize position() predicates
                   13812:                        * here (e.g. "[1]")?
                   13813:                        */
                   13814:                         if (op->ch2 != -1)
                   13815:                             total +=
                   13816:                                 xmlXPathCompOpEval(ctxt,
                   13817:                                                    &comp->steps[op->ch2]);
                   13818:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13819:                            xmlXPathFreeNodeSet(newset);
                   13820:                            xmlXPathFreeObject(obj);
                   13821:                            return(0);
                   13822:                        }
                   13823: 
                   13824:                         /*
                   13825:                          * The result of the evaluation needs to be tested to
                   13826:                          * decide whether the filter succeeded or not
                   13827:                          */
                   13828:                        /*
                   13829:                        * OPTIMIZE TODO: Can we use
                   13830:                        * xmlXPathNodeSetAdd*Unique()* instead?
                   13831:                        */
                   13832:                         res = valuePop(ctxt);
                   13833:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   13834:                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
                   13835:                         }
                   13836: 
                   13837:                         /*
                   13838:                          * Cleanup
                   13839:                          */
                   13840:                         if (res != NULL) {
                   13841:                            xmlXPathReleaseObject(ctxt->context, res);
                   13842:                        }
                   13843:                         if (ctxt->value == tmp) {
                   13844:                             valuePop(ctxt);
                   13845:                            xmlXPathNodeSetClear(tmp->nodesetval, 1);
                   13846:                            /*
                   13847:                            * Don't free the temporary nodeset
                   13848:                            * in order to avoid massive recreation inside this
                   13849:                            * loop.
                   13850:                            */
                   13851:                         } else
                   13852:                            tmp = NULL;
                   13853:                         ctxt->context->node = NULL;
                   13854:                     }
                   13855:                    if (tmp != NULL)
                   13856:                        xmlXPathReleaseObject(ctxt->context, tmp);
                   13857:                     /*
                   13858:                      * The result is used as the new evaluation set.
                   13859:                      */
                   13860:                    xmlXPathReleaseObject(ctxt->context, obj);
                   13861:                     ctxt->context->node = NULL;
                   13862:                     ctxt->context->contextSize = -1;
                   13863:                     ctxt->context->proximityPosition = -1;
                   13864:                    /* may want to move this past the '}' later */
                   13865:                    ctxt->context->doc = oldDoc;
                   13866:                    valuePush(ctxt,
                   13867:                        xmlXPathCacheWrapNodeSet(ctxt->context, newset));
                   13868:                 }
                   13869:                 ctxt->context->node = oldnode;
                   13870:                 return (total);
                   13871:             }
                   13872:         case XPATH_OP_SORT:
                   13873:             if (op->ch1 != -1)
                   13874:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13875:            CHECK_ERROR0;
                   13876:             if ((ctxt->value != NULL) &&
                   13877:                 (ctxt->value->type == XPATH_NODESET) &&
                   13878:                 (ctxt->value->nodesetval != NULL) &&
                   13879:                (ctxt->value->nodesetval->nodeNr > 1))
                   13880:            {
                   13881:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   13882:            }
                   13883:             return (total);
                   13884: #ifdef LIBXML_XPTR_ENABLED
                   13885:         case XPATH_OP_RANGETO:{
                   13886:                 xmlXPathObjectPtr range;
                   13887:                 xmlXPathObjectPtr res, obj;
                   13888:                 xmlXPathObjectPtr tmp;
                   13889:                 xmlLocationSetPtr newlocset = NULL;
                   13890:                    xmlLocationSetPtr oldlocset;
                   13891:                 xmlNodeSetPtr oldset;
                   13892:                 int i, j;
                   13893: 
                   13894:                 if (op->ch1 != -1)
                   13895:                     total +=
                   13896:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13897:                 if (op->ch2 == -1)
                   13898:                     return (total);
                   13899: 
                   13900:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
                   13901:                     /*
                   13902:                      * Extract the old locset, and then evaluate the result of the
                   13903:                      * expression for all the element in the locset. use it to grow
                   13904:                      * up a new locset.
                   13905:                      */
                   13906:                     CHECK_TYPE0(XPATH_LOCATIONSET);
                   13907:                     obj = valuePop(ctxt);
                   13908:                     oldlocset = obj->user;
                   13909: 
                   13910:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
                   13911:                        ctxt->context->node = NULL;
                   13912:                         ctxt->context->contextSize = 0;
                   13913:                         ctxt->context->proximityPosition = 0;
                   13914:                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
                   13915:                         res = valuePop(ctxt);
                   13916:                         if (res != NULL) {
                   13917:                            xmlXPathReleaseObject(ctxt->context, res);
                   13918:                        }
                   13919:                         valuePush(ctxt, obj);
                   13920:                         CHECK_ERROR0;
                   13921:                         return (total);
                   13922:                     }
                   13923:                     newlocset = xmlXPtrLocationSetCreate(NULL);
                   13924: 
                   13925:                     for (i = 0; i < oldlocset->locNr; i++) {
                   13926:                         /*
                   13927:                          * Run the evaluation with a node list made of a
                   13928:                          * single item in the nodelocset.
                   13929:                          */
                   13930:                         ctxt->context->node = oldlocset->locTab[i]->user;
                   13931:                         ctxt->context->contextSize = oldlocset->locNr;
                   13932:                         ctxt->context->proximityPosition = i + 1;
                   13933:                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13934:                            ctxt->context->node);
                   13935:                         valuePush(ctxt, tmp);
                   13936: 
                   13937:                         if (op->ch2 != -1)
                   13938:                             total +=
                   13939:                                 xmlXPathCompOpEval(ctxt,
                   13940:                                                    &comp->steps[op->ch2]);
                   13941:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13942:                            xmlXPathFreeObject(obj);
                   13943:                            return(0);
                   13944:                        }
                   13945: 
                   13946:                         res = valuePop(ctxt);
                   13947:                        if (res->type == XPATH_LOCATIONSET) {
                   13948:                            xmlLocationSetPtr rloc =
                   13949:                                (xmlLocationSetPtr)res->user;
                   13950:                            for (j=0; j<rloc->locNr; j++) {
                   13951:                                range = xmlXPtrNewRange(
                   13952:                                  oldlocset->locTab[i]->user,
                   13953:                                  oldlocset->locTab[i]->index,
                   13954:                                  rloc->locTab[j]->user2,
                   13955:                                  rloc->locTab[j]->index2);
                   13956:                                if (range != NULL) {
                   13957:                                    xmlXPtrLocationSetAdd(newlocset, range);
                   13958:                                }
                   13959:                            }
                   13960:                        } else {
                   13961:                            range = xmlXPtrNewRangeNodeObject(
                   13962:                                (xmlNodePtr)oldlocset->locTab[i]->user, res);
                   13963:                             if (range != NULL) {
                   13964:                                 xmlXPtrLocationSetAdd(newlocset,range);
                   13965:                            }
                   13966:                         }
                   13967: 
                   13968:                         /*
                   13969:                          * Cleanup
                   13970:                          */
                   13971:                         if (res != NULL) {
                   13972:                            xmlXPathReleaseObject(ctxt->context, res);
                   13973:                        }
                   13974:                         if (ctxt->value == tmp) {
                   13975:                             res = valuePop(ctxt);
                   13976:                            xmlXPathReleaseObject(ctxt->context, res);
                   13977:                         }
                   13978: 
                   13979:                         ctxt->context->node = NULL;
                   13980:                     }
                   13981:                } else {        /* Not a location set */
                   13982:                     CHECK_TYPE0(XPATH_NODESET);
                   13983:                     obj = valuePop(ctxt);
                   13984:                     oldset = obj->nodesetval;
                   13985:                     ctxt->context->node = NULL;
                   13986: 
                   13987:                     newlocset = xmlXPtrLocationSetCreate(NULL);
                   13988: 
                   13989:                     if (oldset != NULL) {
                   13990:                         for (i = 0; i < oldset->nodeNr; i++) {
                   13991:                             /*
                   13992:                              * Run the evaluation with a node list made of a single item
                   13993:                              * in the nodeset.
                   13994:                              */
                   13995:                             ctxt->context->node = oldset->nodeTab[i];
                   13996:                            /*
                   13997:                            * OPTIMIZE TODO: Avoid recreation for every iteration.
                   13998:                            */
                   13999:                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   14000:                                ctxt->context->node);
                   14001:                             valuePush(ctxt, tmp);
                   14002: 
                   14003:                             if (op->ch2 != -1)
                   14004:                                 total +=
                   14005:                                     xmlXPathCompOpEval(ctxt,
                   14006:                                                    &comp->steps[op->ch2]);
                   14007:                            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   14008:                                xmlXPathFreeObject(obj);
                   14009:                                return(0);
                   14010:                            }
                   14011: 
                   14012:                             res = valuePop(ctxt);
                   14013:                             range =
                   14014:                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
                   14015:                                                       res);
                   14016:                             if (range != NULL) {
                   14017:                                 xmlXPtrLocationSetAdd(newlocset, range);
                   14018:                             }
                   14019: 
                   14020:                             /*
                   14021:                              * Cleanup
                   14022:                              */
                   14023:                             if (res != NULL) {
                   14024:                                xmlXPathReleaseObject(ctxt->context, res);
                   14025:                            }
                   14026:                             if (ctxt->value == tmp) {
                   14027:                                 res = valuePop(ctxt);
                   14028:                                xmlXPathReleaseObject(ctxt->context, res);
                   14029:                             }
                   14030: 
                   14031:                             ctxt->context->node = NULL;
                   14032:                         }
                   14033:                     }
                   14034:                 }
                   14035: 
                   14036:                 /*
                   14037:                  * The result is used as the new evaluation set.
                   14038:                  */
                   14039:                xmlXPathReleaseObject(ctxt->context, obj);
                   14040:                 ctxt->context->node = NULL;
                   14041:                 ctxt->context->contextSize = -1;
                   14042:                 ctxt->context->proximityPosition = -1;
                   14043:                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
                   14044:                 return (total);
                   14045:             }
                   14046: #endif /* LIBXML_XPTR_ENABLED */
                   14047:     }
                   14048:     xmlGenericError(xmlGenericErrorContext,
                   14049:                     "XPath: unknown precompiled operation %d\n", op->op);
1.1.1.2 ! misho    14050:     ctxt->error = XPATH_INVALID_OPERAND;
1.1       misho    14051:     return (total);
                   14052: }
                   14053: 
                   14054: /**
                   14055:  * xmlXPathCompOpEvalToBoolean:
                   14056:  * @ctxt:  the XPath parser context
                   14057:  *
                   14058:  * Evaluates if the expression evaluates to true.
                   14059:  *
                   14060:  * Returns 1 if true, 0 if false and -1 on API or internal errors.
                   14061:  */
                   14062: static int
                   14063: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
                   14064:                            xmlXPathStepOpPtr op,
                   14065:                            int isPredicate)
                   14066: {
                   14067:     xmlXPathObjectPtr resObj = NULL;
                   14068: 
                   14069: start:
                   14070:     /* comp = ctxt->comp; */
                   14071:     switch (op->op) {
                   14072:         case XPATH_OP_END:
                   14073:             return (0);
                   14074:        case XPATH_OP_VALUE:
                   14075:            resObj = (xmlXPathObjectPtr) op->value4;
                   14076:            if (isPredicate)
                   14077:                return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
                   14078:            return(xmlXPathCastToBoolean(resObj));
                   14079:        case XPATH_OP_SORT:
                   14080:            /*
                   14081:            * We don't need sorting for boolean results. Skip this one.
                   14082:            */
                   14083:             if (op->ch1 != -1) {
                   14084:                op = &ctxt->comp->steps[op->ch1];
                   14085:                goto start;
                   14086:            }
                   14087:            return(0);
                   14088:        case XPATH_OP_COLLECT:
                   14089:            if (op->ch1 == -1)
                   14090:                return(0);
                   14091: 
                   14092:             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
                   14093:            if (ctxt->error != XPATH_EXPRESSION_OK)
                   14094:                return(-1);
                   14095: 
                   14096:             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
                   14097:            if (ctxt->error != XPATH_EXPRESSION_OK)
                   14098:                return(-1);
                   14099: 
                   14100:            resObj = valuePop(ctxt);
                   14101:            if (resObj == NULL)
                   14102:                return(-1);
                   14103:            break;
                   14104:        default:
                   14105:            /*
                   14106:            * Fallback to call xmlXPathCompOpEval().
                   14107:            */
                   14108:            xmlXPathCompOpEval(ctxt, op);
                   14109:            if (ctxt->error != XPATH_EXPRESSION_OK)
                   14110:                return(-1);
                   14111: 
                   14112:            resObj = valuePop(ctxt);
                   14113:            if (resObj == NULL)
                   14114:                return(-1);
                   14115:            break;
                   14116:     }
                   14117: 
                   14118:     if (resObj) {
                   14119:        int res;
                   14120: 
                   14121:        if (resObj->type == XPATH_BOOLEAN) {
                   14122:            res = resObj->boolval;
                   14123:        } else if (isPredicate) {
                   14124:            /*
                   14125:            * For predicates a result of type "number" is handled
                   14126:            * differently:
                   14127:            * SPEC XPath 1.0:
                   14128:            * "If the result is a number, the result will be converted
                   14129:            *  to true if the number is equal to the context position
                   14130:            *  and will be converted to false otherwise;"
                   14131:            */
                   14132:            res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
                   14133:        } else {
                   14134:            res = xmlXPathCastToBoolean(resObj);
                   14135:        }
                   14136:        xmlXPathReleaseObject(ctxt->context, resObj);
                   14137:        return(res);
                   14138:     }
                   14139: 
                   14140:     return(0);
                   14141: }
                   14142: 
                   14143: #ifdef XPATH_STREAMING
                   14144: /**
                   14145:  * xmlXPathRunStreamEval:
                   14146:  * @ctxt:  the XPath parser context with the compiled expression
                   14147:  *
                   14148:  * Evaluate the Precompiled Streamable XPath expression in the given context.
                   14149:  */
                   14150: static int
                   14151: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
                   14152:                      xmlXPathObjectPtr *resultSeq, int toBool)
                   14153: {
                   14154:     int max_depth, min_depth;
                   14155:     int from_root;
                   14156:     int ret, depth;
                   14157:     int eval_all_nodes;
                   14158:     xmlNodePtr cur = NULL, limit = NULL;
                   14159:     xmlStreamCtxtPtr patstream = NULL;
                   14160: 
                   14161:     int nb_nodes = 0;
                   14162: 
                   14163:     if ((ctxt == NULL) || (comp == NULL))
                   14164:         return(-1);
                   14165:     max_depth = xmlPatternMaxDepth(comp);
                   14166:     if (max_depth == -1)
                   14167:         return(-1);
                   14168:     if (max_depth == -2)
                   14169:         max_depth = 10000;
                   14170:     min_depth = xmlPatternMinDepth(comp);
                   14171:     if (min_depth == -1)
                   14172:         return(-1);
                   14173:     from_root = xmlPatternFromRoot(comp);
                   14174:     if (from_root < 0)
                   14175:         return(-1);
                   14176: #if 0
                   14177:     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
                   14178: #endif
                   14179: 
                   14180:     if (! toBool) {
                   14181:        if (resultSeq == NULL)
                   14182:            return(-1);
                   14183:        *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
                   14184:        if (*resultSeq == NULL)
                   14185:            return(-1);
                   14186:     }
                   14187: 
                   14188:     /*
                   14189:      * handle the special cases of "/" amd "." being matched
                   14190:      */
                   14191:     if (min_depth == 0) {
                   14192:        if (from_root) {
                   14193:            /* Select "/" */
                   14194:            if (toBool)
                   14195:                return(1);
                   14196:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
                   14197:                (xmlNodePtr) ctxt->doc);
                   14198:        } else {
                   14199:            /* Select "self::node()" */
                   14200:            if (toBool)
                   14201:                return(1);
                   14202:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
                   14203:        }
                   14204:     }
                   14205:     if (max_depth == 0) {
                   14206:        return(0);
                   14207:     }
                   14208: 
                   14209:     if (from_root) {
                   14210:         cur = (xmlNodePtr)ctxt->doc;
                   14211:     } else if (ctxt->node != NULL) {
                   14212:         switch (ctxt->node->type) {
                   14213:             case XML_ELEMENT_NODE:
                   14214:             case XML_DOCUMENT_NODE:
                   14215:             case XML_DOCUMENT_FRAG_NODE:
                   14216:             case XML_HTML_DOCUMENT_NODE:
                   14217: #ifdef LIBXML_DOCB_ENABLED
                   14218:             case XML_DOCB_DOCUMENT_NODE:
                   14219: #endif
                   14220:                cur = ctxt->node;
                   14221:                break;
                   14222:             case XML_ATTRIBUTE_NODE:
                   14223:             case XML_TEXT_NODE:
                   14224:             case XML_CDATA_SECTION_NODE:
                   14225:             case XML_ENTITY_REF_NODE:
                   14226:             case XML_ENTITY_NODE:
                   14227:             case XML_PI_NODE:
                   14228:             case XML_COMMENT_NODE:
                   14229:             case XML_NOTATION_NODE:
                   14230:             case XML_DTD_NODE:
                   14231:             case XML_DOCUMENT_TYPE_NODE:
                   14232:             case XML_ELEMENT_DECL:
                   14233:             case XML_ATTRIBUTE_DECL:
                   14234:             case XML_ENTITY_DECL:
                   14235:             case XML_NAMESPACE_DECL:
                   14236:             case XML_XINCLUDE_START:
                   14237:             case XML_XINCLUDE_END:
                   14238:                break;
                   14239:        }
                   14240:        limit = cur;
                   14241:     }
                   14242:     if (cur == NULL) {
                   14243:         return(0);
                   14244:     }
                   14245: 
                   14246:     patstream = xmlPatternGetStreamCtxt(comp);
                   14247:     if (patstream == NULL) {
                   14248:        /*
                   14249:        * QUESTION TODO: Is this an error?
                   14250:        */
                   14251:        return(0);
                   14252:     }
                   14253: 
                   14254:     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
                   14255: 
                   14256:     if (from_root) {
                   14257:        ret = xmlStreamPush(patstream, NULL, NULL);
                   14258:        if (ret < 0) {
                   14259:        } else if (ret == 1) {
                   14260:            if (toBool)
                   14261:                goto return_1;
                   14262:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
                   14263:        }
                   14264:     }
                   14265:     depth = 0;
                   14266:     goto scan_children;
                   14267: next_node:
                   14268:     do {
                   14269:         nb_nodes++;
                   14270: 
                   14271:        switch (cur->type) {
                   14272:            case XML_ELEMENT_NODE:
                   14273:            case XML_TEXT_NODE:
                   14274:            case XML_CDATA_SECTION_NODE:
                   14275:            case XML_COMMENT_NODE:
                   14276:            case XML_PI_NODE:
                   14277:                if (cur->type == XML_ELEMENT_NODE) {
                   14278:                    ret = xmlStreamPush(patstream, cur->name,
                   14279:                                (cur->ns ? cur->ns->href : NULL));
                   14280:                } else if (eval_all_nodes)
                   14281:                    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
                   14282:                else
                   14283:                    break;
                   14284: 
                   14285:                if (ret < 0) {
                   14286:                    /* NOP. */
                   14287:                } else if (ret == 1) {
                   14288:                    if (toBool)
                   14289:                        goto return_1;
                   14290:                    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
                   14291:                }
                   14292:                if ((cur->children == NULL) || (depth >= max_depth)) {
                   14293:                    ret = xmlStreamPop(patstream);
                   14294:                    while (cur->next != NULL) {
                   14295:                        cur = cur->next;
                   14296:                        if ((cur->type != XML_ENTITY_DECL) &&
                   14297:                            (cur->type != XML_DTD_NODE))
                   14298:                            goto next_node;
                   14299:                    }
                   14300:                }
                   14301:            default:
                   14302:                break;
                   14303:        }
                   14304: 
                   14305: scan_children:
                   14306:        if ((cur->children != NULL) && (depth < max_depth)) {
                   14307:            /*
                   14308:             * Do not descend on entities declarations
                   14309:             */
                   14310:            if (cur->children->type != XML_ENTITY_DECL) {
                   14311:                cur = cur->children;
                   14312:                depth++;
                   14313:                /*
                   14314:                 * Skip DTDs
                   14315:                 */
                   14316:                if (cur->type != XML_DTD_NODE)
                   14317:                    continue;
                   14318:            }
                   14319:        }
                   14320: 
                   14321:        if (cur == limit)
                   14322:            break;
                   14323: 
                   14324:        while (cur->next != NULL) {
                   14325:            cur = cur->next;
                   14326:            if ((cur->type != XML_ENTITY_DECL) &&
                   14327:                (cur->type != XML_DTD_NODE))
                   14328:                goto next_node;
                   14329:        }
                   14330: 
                   14331:        do {
                   14332:            cur = cur->parent;
                   14333:            depth--;
                   14334:            if ((cur == NULL) || (cur == limit))
                   14335:                goto done;
                   14336:            if (cur->type == XML_ELEMENT_NODE) {
                   14337:                ret = xmlStreamPop(patstream);
                   14338:            } else if ((eval_all_nodes) &&
                   14339:                ((cur->type == XML_TEXT_NODE) ||
                   14340:                 (cur->type == XML_CDATA_SECTION_NODE) ||
                   14341:                 (cur->type == XML_COMMENT_NODE) ||
                   14342:                 (cur->type == XML_PI_NODE)))
                   14343:            {
                   14344:                ret = xmlStreamPop(patstream);
                   14345:            }
                   14346:            if (cur->next != NULL) {
                   14347:                cur = cur->next;
                   14348:                break;
                   14349:            }
                   14350:        } while (cur != NULL);
                   14351: 
                   14352:     } while ((cur != NULL) && (depth >= 0));
                   14353: 
                   14354: done:
                   14355: 
                   14356: #if 0
                   14357:     printf("stream eval: checked %d nodes selected %d\n",
                   14358:            nb_nodes, retObj->nodesetval->nodeNr);
                   14359: #endif
                   14360: 
                   14361:     if (patstream)
                   14362:        xmlFreeStreamCtxt(patstream);
                   14363:     return(0);
                   14364: 
                   14365: return_1:
                   14366:     if (patstream)
                   14367:        xmlFreeStreamCtxt(patstream);
                   14368:     return(1);
                   14369: }
                   14370: #endif /* XPATH_STREAMING */
                   14371: 
                   14372: /**
                   14373:  * xmlXPathRunEval:
                   14374:  * @ctxt:  the XPath parser context with the compiled expression
                   14375:  * @toBool:  evaluate to a boolean result
                   14376:  *
                   14377:  * Evaluate the Precompiled XPath expression in the given context.
                   14378:  */
                   14379: static int
                   14380: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
                   14381: {
                   14382:     xmlXPathCompExprPtr comp;
                   14383: 
                   14384:     if ((ctxt == NULL) || (ctxt->comp == NULL))
                   14385:        return(-1);
                   14386: 
                   14387:     if (ctxt->valueTab == NULL) {
                   14388:        /* Allocate the value stack */
                   14389:        ctxt->valueTab = (xmlXPathObjectPtr *)
                   14390:                         xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
                   14391:        if (ctxt->valueTab == NULL) {
                   14392:            xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
                   14393:            xmlFree(ctxt);
                   14394:        }
                   14395:        ctxt->valueNr = 0;
                   14396:        ctxt->valueMax = 10;
                   14397:        ctxt->value = NULL;
1.1.1.2 ! misho    14398:         ctxt->valueFrame = 0;
1.1       misho    14399:     }
                   14400: #ifdef XPATH_STREAMING
                   14401:     if (ctxt->comp->stream) {
                   14402:        int res;
                   14403: 
                   14404:        if (toBool) {
                   14405:            /*
                   14406:            * Evaluation to boolean result.
                   14407:            */
                   14408:            res = xmlXPathRunStreamEval(ctxt->context,
                   14409:                ctxt->comp->stream, NULL, 1);
                   14410:            if (res != -1)
                   14411:                return(res);
                   14412:        } else {
                   14413:            xmlXPathObjectPtr resObj = NULL;
                   14414: 
                   14415:            /*
                   14416:            * Evaluation to a sequence.
                   14417:            */
                   14418:            res = xmlXPathRunStreamEval(ctxt->context,
                   14419:                ctxt->comp->stream, &resObj, 0);
                   14420: 
                   14421:            if ((res != -1) && (resObj != NULL)) {
                   14422:                valuePush(ctxt, resObj);
                   14423:                return(0);
                   14424:            }
                   14425:            if (resObj != NULL)
                   14426:                xmlXPathReleaseObject(ctxt->context, resObj);
                   14427:        }
                   14428:        /*
                   14429:        * QUESTION TODO: This falls back to normal XPath evaluation
                   14430:        * if res == -1. Is this intended?
                   14431:        */
                   14432:     }
                   14433: #endif
                   14434:     comp = ctxt->comp;
                   14435:     if (comp->last < 0) {
                   14436:        xmlGenericError(xmlGenericErrorContext,
                   14437:            "xmlXPathRunEval: last is less than zero\n");
                   14438:        return(-1);
                   14439:     }
                   14440:     if (toBool)
                   14441:        return(xmlXPathCompOpEvalToBoolean(ctxt,
                   14442:            &comp->steps[comp->last], 0));
                   14443:     else
                   14444:        xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
                   14445: 
                   14446:     return(0);
                   14447: }
                   14448: 
                   14449: /************************************************************************
                   14450:  *                                                                     *
                   14451:  *                     Public interfaces                               *
                   14452:  *                                                                     *
                   14453:  ************************************************************************/
                   14454: 
                   14455: /**
                   14456:  * xmlXPathEvalPredicate:
                   14457:  * @ctxt:  the XPath context
                   14458:  * @res:  the Predicate Expression evaluation result
                   14459:  *
                   14460:  * Evaluate a predicate result for the current node.
                   14461:  * A PredicateExpr is evaluated by evaluating the Expr and converting
                   14462:  * the result to a boolean. If the result is a number, the result will
                   14463:  * be converted to true if the number is equal to the position of the
                   14464:  * context node in the context node list (as returned by the position
                   14465:  * function) and will be converted to false otherwise; if the result
                   14466:  * is not a number, then the result will be converted as if by a call
                   14467:  * to the boolean function.
                   14468:  *
                   14469:  * Returns 1 if predicate is true, 0 otherwise
                   14470:  */
                   14471: int
                   14472: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
                   14473:     if ((ctxt == NULL) || (res == NULL)) return(0);
                   14474:     switch (res->type) {
                   14475:         case XPATH_BOOLEAN:
                   14476:            return(res->boolval);
                   14477:         case XPATH_NUMBER:
                   14478:            return(res->floatval == ctxt->proximityPosition);
                   14479:         case XPATH_NODESET:
                   14480:         case XPATH_XSLT_TREE:
                   14481:            if (res->nodesetval == NULL)
                   14482:                return(0);
                   14483:            return(res->nodesetval->nodeNr != 0);
                   14484:         case XPATH_STRING:
                   14485:            return((res->stringval != NULL) &&
                   14486:                   (xmlStrlen(res->stringval) != 0));
                   14487:         default:
                   14488:            STRANGE
                   14489:     }
                   14490:     return(0);
                   14491: }
                   14492: 
                   14493: /**
                   14494:  * xmlXPathEvaluatePredicateResult:
                   14495:  * @ctxt:  the XPath Parser context
                   14496:  * @res:  the Predicate Expression evaluation result
                   14497:  *
                   14498:  * Evaluate a predicate result for the current node.
                   14499:  * A PredicateExpr is evaluated by evaluating the Expr and converting
                   14500:  * the result to a boolean. If the result is a number, the result will
                   14501:  * be converted to true if the number is equal to the position of the
                   14502:  * context node in the context node list (as returned by the position
                   14503:  * function) and will be converted to false otherwise; if the result
                   14504:  * is not a number, then the result will be converted as if by a call
                   14505:  * to the boolean function.
                   14506:  *
                   14507:  * Returns 1 if predicate is true, 0 otherwise
                   14508:  */
                   14509: int
                   14510: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
                   14511:                                 xmlXPathObjectPtr res) {
                   14512:     if ((ctxt == NULL) || (res == NULL)) return(0);
                   14513:     switch (res->type) {
                   14514:         case XPATH_BOOLEAN:
                   14515:            return(res->boolval);
                   14516:         case XPATH_NUMBER:
                   14517: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
                   14518:            return((res->floatval == ctxt->context->proximityPosition) &&
                   14519:                   (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
                   14520: #else
                   14521:            return(res->floatval == ctxt->context->proximityPosition);
                   14522: #endif
                   14523:         case XPATH_NODESET:
                   14524:         case XPATH_XSLT_TREE:
                   14525:            if (res->nodesetval == NULL)
                   14526:                return(0);
                   14527:            return(res->nodesetval->nodeNr != 0);
                   14528:         case XPATH_STRING:
                   14529:            return((res->stringval != NULL) && (res->stringval[0] != 0));
                   14530: #ifdef LIBXML_XPTR_ENABLED
                   14531:        case XPATH_LOCATIONSET:{
                   14532:            xmlLocationSetPtr ptr = res->user;
                   14533:            if (ptr == NULL)
                   14534:                return(0);
                   14535:            return (ptr->locNr != 0);
                   14536:            }
                   14537: #endif
                   14538:         default:
                   14539:            STRANGE
                   14540:     }
                   14541:     return(0);
                   14542: }
                   14543: 
                   14544: #ifdef XPATH_STREAMING
                   14545: /**
                   14546:  * xmlXPathTryStreamCompile:
                   14547:  * @ctxt: an XPath context
                   14548:  * @str:  the XPath expression
                   14549:  *
                   14550:  * Try to compile the XPath expression as a streamable subset.
                   14551:  *
                   14552:  * Returns the compiled expression or NULL if failed to compile.
                   14553:  */
                   14554: static xmlXPathCompExprPtr
                   14555: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
                   14556:     /*
                   14557:      * Optimization: use streaming patterns when the XPath expression can
                   14558:      * be compiled to a stream lookup
                   14559:      */
                   14560:     xmlPatternPtr stream;
                   14561:     xmlXPathCompExprPtr comp;
                   14562:     xmlDictPtr dict = NULL;
                   14563:     const xmlChar **namespaces = NULL;
                   14564:     xmlNsPtr ns;
                   14565:     int i, j;
                   14566: 
                   14567:     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
                   14568:         (!xmlStrchr(str, '@'))) {
                   14569:        const xmlChar *tmp;
                   14570: 
                   14571:        /*
                   14572:         * We don't try to handle expressions using the verbose axis
                   14573:         * specifiers ("::"), just the simplied form at this point.
                   14574:         * Additionally, if there is no list of namespaces available and
                   14575:         *  there's a ":" in the expression, indicating a prefixed QName,
                   14576:         *  then we won't try to compile either. xmlPatterncompile() needs
                   14577:         *  to have a list of namespaces at compilation time in order to
                   14578:         *  compile prefixed name tests.
                   14579:         */
                   14580:        tmp = xmlStrchr(str, ':');
                   14581:        if ((tmp != NULL) &&
                   14582:            ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
                   14583:            return(NULL);
                   14584: 
                   14585:        if (ctxt != NULL) {
                   14586:            dict = ctxt->dict;
                   14587:            if (ctxt->nsNr > 0) {
                   14588:                namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
                   14589:                if (namespaces == NULL) {
                   14590:                    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
                   14591:                    return(NULL);
                   14592:                }
                   14593:                for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
                   14594:                    ns = ctxt->namespaces[j];
                   14595:                    namespaces[i++] = ns->href;
                   14596:                    namespaces[i++] = ns->prefix;
                   14597:                }
                   14598:                namespaces[i++] = NULL;
                   14599:                namespaces[i] = NULL;
                   14600:            }
                   14601:        }
                   14602: 
                   14603:        stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
                   14604:                        &namespaces[0]);
                   14605:        if (namespaces != NULL) {
                   14606:            xmlFree((xmlChar **)namespaces);
                   14607:        }
                   14608:        if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
                   14609:            comp = xmlXPathNewCompExpr();
                   14610:            if (comp == NULL) {
                   14611:                xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
                   14612:                return(NULL);
                   14613:            }
                   14614:            comp->stream = stream;
                   14615:            comp->dict = dict;
                   14616:            if (comp->dict)
                   14617:                xmlDictReference(comp->dict);
                   14618:            return(comp);
                   14619:        }
                   14620:        xmlFreePattern(stream);
                   14621:     }
                   14622:     return(NULL);
                   14623: }
                   14624: #endif /* XPATH_STREAMING */
                   14625: 
                   14626: static int
                   14627: xmlXPathCanRewriteDosExpression(xmlChar *expr)
                   14628: {
                   14629:     if (expr == NULL)
                   14630:        return(0);
                   14631:     do {
                   14632:         if ((*expr == '/') && (*(++expr) == '/'))
                   14633:            return(1);
                   14634:     } while (*expr++);
                   14635:     return(0);
                   14636: }
                   14637: static void
                   14638: xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
                   14639: {
                   14640:     /*
                   14641:     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
                   14642:     * internal representation.
                   14643:     */
                   14644:     if (op->ch1 != -1) {
                   14645:        if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
                   14646:            ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
                   14647:            ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
                   14648:            ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
                   14649:        {
                   14650:            /*
                   14651:            * This is a "child::foo"
                   14652:            */
                   14653:            xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
                   14654: 
                   14655:            if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
                   14656:                (prevop->ch1 != -1) &&
                   14657:                ((xmlXPathAxisVal) prevop->value ==
                   14658:                    AXIS_DESCENDANT_OR_SELF) &&
                   14659:                (prevop->ch2 == -1) &&
                   14660:                ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
                   14661:                ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
                   14662:                (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
                   14663:            {
                   14664:                /*
                   14665:                * This is a "/descendant-or-self::node()" without predicates.
                   14666:                * Eliminate it.
                   14667:                */
                   14668:                op->ch1 = prevop->ch1;
                   14669:                op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
                   14670:            }
                   14671:        }
                   14672:        if (op->ch1 != -1)
                   14673:            xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
                   14674:     }
                   14675:     if (op->ch2 != -1)
                   14676:        xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
                   14677: }
                   14678: 
                   14679: /**
                   14680:  * xmlXPathCtxtCompile:
                   14681:  * @ctxt: an XPath context
                   14682:  * @str:  the XPath expression
                   14683:  *
                   14684:  * Compile an XPath expression
                   14685:  *
                   14686:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
                   14687:  *         the caller has to free the object.
                   14688:  */
                   14689: xmlXPathCompExprPtr
                   14690: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
                   14691:     xmlXPathParserContextPtr pctxt;
                   14692:     xmlXPathCompExprPtr comp;
                   14693: 
                   14694: #ifdef XPATH_STREAMING
                   14695:     comp = xmlXPathTryStreamCompile(ctxt, str);
                   14696:     if (comp != NULL)
                   14697:         return(comp);
                   14698: #endif
                   14699: 
                   14700:     xmlXPathInit();
                   14701: 
                   14702:     pctxt = xmlXPathNewParserContext(str, ctxt);
                   14703:     if (pctxt == NULL)
                   14704:         return NULL;
                   14705:     xmlXPathCompileExpr(pctxt, 1);
                   14706: 
                   14707:     if( pctxt->error != XPATH_EXPRESSION_OK )
                   14708:     {
                   14709:         xmlXPathFreeParserContext(pctxt);
                   14710:         return(NULL);
                   14711:     }
                   14712: 
                   14713:     if (*pctxt->cur != 0) {
                   14714:        /*
                   14715:         * aleksey: in some cases this line prints *second* error message
                   14716:         * (see bug #78858) and probably this should be fixed.
                   14717:         * However, we are not sure that all error messages are printed
                   14718:         * out in other places. It's not critical so we leave it as-is for now
                   14719:         */
                   14720:        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
                   14721:        comp = NULL;
                   14722:     } else {
                   14723:        comp = pctxt->comp;
                   14724:        pctxt->comp = NULL;
                   14725:     }
                   14726:     xmlXPathFreeParserContext(pctxt);
                   14727: 
                   14728:     if (comp != NULL) {
                   14729:        comp->expr = xmlStrdup(str);
                   14730: #ifdef DEBUG_EVAL_COUNTS
                   14731:        comp->string = xmlStrdup(str);
                   14732:        comp->nb = 0;
                   14733: #endif
                   14734:        if ((comp->expr != NULL) &&
                   14735:            (comp->nbStep > 2) &&
                   14736:            (comp->last >= 0) &&
                   14737:            (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
                   14738:        {
                   14739:            xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
                   14740:        }
                   14741:     }
                   14742:     return(comp);
                   14743: }
                   14744: 
                   14745: /**
                   14746:  * xmlXPathCompile:
                   14747:  * @str:  the XPath expression
                   14748:  *
                   14749:  * Compile an XPath expression
                   14750:  *
                   14751:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
                   14752:  *         the caller has to free the object.
                   14753:  */
                   14754: xmlXPathCompExprPtr
                   14755: xmlXPathCompile(const xmlChar *str) {
                   14756:     return(xmlXPathCtxtCompile(NULL, str));
                   14757: }
                   14758: 
                   14759: /**
                   14760:  * xmlXPathCompiledEvalInternal:
                   14761:  * @comp:  the compiled XPath expression
                   14762:  * @ctxt:  the XPath context
                   14763:  * @resObj: the resulting XPath object or NULL
                   14764:  * @toBool: 1 if only a boolean result is requested
                   14765:  *
                   14766:  * Evaluate the Precompiled XPath expression in the given context.
                   14767:  * The caller has to free @resObj.
                   14768:  *
                   14769:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   14770:  *         the caller has to free the object.
                   14771:  */
                   14772: static int
                   14773: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
                   14774:                             xmlXPathContextPtr ctxt,
                   14775:                             xmlXPathObjectPtr *resObj,
                   14776:                             int toBool)
                   14777: {
                   14778:     xmlXPathParserContextPtr pctxt;
                   14779: #ifndef LIBXML_THREAD_ENABLED
                   14780:     static int reentance = 0;
                   14781: #endif
                   14782:     int res;
                   14783: 
                   14784:     CHECK_CTXT_NEG(ctxt)
                   14785: 
                   14786:     if (comp == NULL)
                   14787:        return(-1);
                   14788:     xmlXPathInit();
                   14789: 
                   14790: #ifndef LIBXML_THREAD_ENABLED
                   14791:     reentance++;
                   14792:     if (reentance > 1)
                   14793:        xmlXPathDisableOptimizer = 1;
                   14794: #endif
                   14795: 
                   14796: #ifdef DEBUG_EVAL_COUNTS
                   14797:     comp->nb++;
                   14798:     if ((comp->string != NULL) && (comp->nb > 100)) {
                   14799:        fprintf(stderr, "100 x %s\n", comp->string);
                   14800:        comp->nb = 0;
                   14801:     }
                   14802: #endif
                   14803:     pctxt = xmlXPathCompParserContext(comp, ctxt);
                   14804:     res = xmlXPathRunEval(pctxt, toBool);
                   14805: 
                   14806:     if (resObj) {
                   14807:        if (pctxt->value == NULL) {
                   14808:            xmlGenericError(xmlGenericErrorContext,
                   14809:                "xmlXPathCompiledEval: evaluation failed\n");
                   14810:            *resObj = NULL;
                   14811:        } else {
                   14812:            *resObj = valuePop(pctxt);
                   14813:        }
                   14814:     }
                   14815: 
                   14816:     /*
                   14817:     * Pop all remaining objects from the stack.
                   14818:     */
                   14819:     if (pctxt->valueNr > 0) {
                   14820:        xmlXPathObjectPtr tmp;
                   14821:        int stack = 0;
                   14822: 
                   14823:        do {
                   14824:            tmp = valuePop(pctxt);
                   14825:            if (tmp != NULL) {
                   14826:                stack++;
                   14827:                xmlXPathReleaseObject(ctxt, tmp);
                   14828:            }
                   14829:        } while (tmp != NULL);
                   14830:        if ((stack != 0) &&
                   14831:            ((toBool) || ((resObj) && (*resObj))))
                   14832:        {
                   14833:            xmlGenericError(xmlGenericErrorContext,
                   14834:                "xmlXPathCompiledEval: %d objects left on the stack.\n",
                   14835:                stack);
                   14836:        }
                   14837:     }
                   14838: 
                   14839:     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
                   14840:        xmlXPathFreeObject(*resObj);
                   14841:        *resObj = NULL;
                   14842:     }
                   14843:     pctxt->comp = NULL;
                   14844:     xmlXPathFreeParserContext(pctxt);
                   14845: #ifndef LIBXML_THREAD_ENABLED
                   14846:     reentance--;
                   14847: #endif
                   14848: 
                   14849:     return(res);
                   14850: }
                   14851: 
                   14852: /**
                   14853:  * xmlXPathCompiledEval:
                   14854:  * @comp:  the compiled XPath expression
                   14855:  * @ctx:  the XPath context
                   14856:  *
                   14857:  * Evaluate the Precompiled XPath expression in the given context.
                   14858:  *
                   14859:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   14860:  *         the caller has to free the object.
                   14861:  */
                   14862: xmlXPathObjectPtr
                   14863: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
                   14864: {
                   14865:     xmlXPathObjectPtr res = NULL;
                   14866: 
                   14867:     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
                   14868:     return(res);
                   14869: }
                   14870: 
                   14871: /**
                   14872:  * xmlXPathCompiledEvalToBoolean:
                   14873:  * @comp:  the compiled XPath expression
                   14874:  * @ctxt:  the XPath context
                   14875:  *
                   14876:  * Applies the XPath boolean() function on the result of the given
                   14877:  * compiled expression.
                   14878:  *
                   14879:  * Returns 1 if the expression evaluated to true, 0 if to false and
                   14880:  *         -1 in API and internal errors.
                   14881:  */
                   14882: int
                   14883: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
                   14884:                              xmlXPathContextPtr ctxt)
                   14885: {
                   14886:     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
                   14887: }
                   14888: 
                   14889: /**
                   14890:  * xmlXPathEvalExpr:
                   14891:  * @ctxt:  the XPath Parser context
                   14892:  *
                   14893:  * Parse and evaluate an XPath expression in the given context,
                   14894:  * then push the result on the context stack
                   14895:  */
                   14896: void
                   14897: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
                   14898: #ifdef XPATH_STREAMING
                   14899:     xmlXPathCompExprPtr comp;
                   14900: #endif
                   14901: 
                   14902:     if (ctxt == NULL) return;
                   14903: 
                   14904: #ifdef XPATH_STREAMING
                   14905:     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
                   14906:     if (comp != NULL) {
                   14907:         if (ctxt->comp != NULL)
                   14908:            xmlXPathFreeCompExpr(ctxt->comp);
                   14909:         ctxt->comp = comp;
                   14910:        if (ctxt->cur != NULL)
                   14911:            while (*ctxt->cur != 0) ctxt->cur++;
                   14912:     } else
                   14913: #endif
                   14914:     {
                   14915:        xmlXPathCompileExpr(ctxt, 1);
                   14916:        /*
                   14917:        * In this scenario the expression string will sit in ctxt->base.
                   14918:        */
                   14919:        if ((ctxt->error == XPATH_EXPRESSION_OK) &&
                   14920:            (ctxt->comp != NULL) &&
                   14921:            (ctxt->base != NULL) &&
                   14922:            (ctxt->comp->nbStep > 2) &&
                   14923:            (ctxt->comp->last >= 0) &&
                   14924:            (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
                   14925:        {
                   14926:            xmlXPathRewriteDOSExpression(ctxt->comp,
                   14927:                &ctxt->comp->steps[ctxt->comp->last]);
                   14928:        }
                   14929:     }
                   14930:     CHECK_ERROR;
                   14931:     xmlXPathRunEval(ctxt, 0);
                   14932: }
                   14933: 
                   14934: /**
                   14935:  * xmlXPathEval:
                   14936:  * @str:  the XPath expression
                   14937:  * @ctx:  the XPath context
                   14938:  *
                   14939:  * Evaluate the XPath Location Path in the given context.
                   14940:  *
                   14941:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   14942:  *         the caller has to free the object.
                   14943:  */
                   14944: xmlXPathObjectPtr
                   14945: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
                   14946:     xmlXPathParserContextPtr ctxt;
                   14947:     xmlXPathObjectPtr res, tmp, init = NULL;
                   14948:     int stack = 0;
                   14949: 
                   14950:     CHECK_CTXT(ctx)
                   14951: 
                   14952:     xmlXPathInit();
                   14953: 
                   14954:     ctxt = xmlXPathNewParserContext(str, ctx);
                   14955:     if (ctxt == NULL)
                   14956:         return NULL;
                   14957:     xmlXPathEvalExpr(ctxt);
                   14958: 
                   14959:     if (ctxt->value == NULL) {
                   14960:        xmlGenericError(xmlGenericErrorContext,
                   14961:                "xmlXPathEval: evaluation failed\n");
                   14962:        res = NULL;
                   14963:     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
                   14964: #ifdef XPATH_STREAMING
                   14965:             && (ctxt->comp->stream == NULL)
                   14966: #endif
                   14967:              ) {
                   14968:        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
                   14969:        res = NULL;
                   14970:     } else {
                   14971:        res = valuePop(ctxt);
                   14972:     }
                   14973: 
                   14974:     do {
                   14975:         tmp = valuePop(ctxt);
                   14976:        if (tmp != NULL) {
                   14977:            if (tmp != init)
                   14978:                stack++;
                   14979:            xmlXPathReleaseObject(ctx, tmp);
                   14980:         }
                   14981:     } while (tmp != NULL);
                   14982:     if ((stack != 0) && (res != NULL)) {
                   14983:        xmlGenericError(xmlGenericErrorContext,
                   14984:                "xmlXPathEval: %d object left on the stack\n",
                   14985:                stack);
                   14986:     }
                   14987:     if (ctxt->error != XPATH_EXPRESSION_OK) {
                   14988:        xmlXPathFreeObject(res);
                   14989:        res = NULL;
                   14990:     }
                   14991: 
                   14992:     xmlXPathFreeParserContext(ctxt);
                   14993:     return(res);
                   14994: }
                   14995: 
                   14996: /**
                   14997:  * xmlXPathEvalExpression:
                   14998:  * @str:  the XPath expression
                   14999:  * @ctxt:  the XPath context
                   15000:  *
                   15001:  * Evaluate the XPath expression in the given context.
                   15002:  *
                   15003:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   15004:  *         the caller has to free the object.
                   15005:  */
                   15006: xmlXPathObjectPtr
                   15007: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
                   15008:     xmlXPathParserContextPtr pctxt;
                   15009:     xmlXPathObjectPtr res, tmp;
                   15010:     int stack = 0;
                   15011: 
                   15012:     CHECK_CTXT(ctxt)
                   15013: 
                   15014:     xmlXPathInit();
                   15015: 
                   15016:     pctxt = xmlXPathNewParserContext(str, ctxt);
                   15017:     if (pctxt == NULL)
                   15018:         return NULL;
                   15019:     xmlXPathEvalExpr(pctxt);
                   15020: 
                   15021:     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
                   15022:        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
                   15023:        res = NULL;
                   15024:     } else {
                   15025:        res = valuePop(pctxt);
                   15026:     }
                   15027:     do {
                   15028:         tmp = valuePop(pctxt);
                   15029:        if (tmp != NULL) {
                   15030:            xmlXPathReleaseObject(ctxt, tmp);
                   15031:            stack++;
                   15032:        }
                   15033:     } while (tmp != NULL);
                   15034:     if ((stack != 0) && (res != NULL)) {
                   15035:        xmlGenericError(xmlGenericErrorContext,
                   15036:                "xmlXPathEvalExpression: %d object left on the stack\n",
                   15037:                stack);
                   15038:     }
                   15039:     xmlXPathFreeParserContext(pctxt);
                   15040:     return(res);
                   15041: }
                   15042: 
                   15043: /************************************************************************
                   15044:  *                                                                     *
                   15045:  *     Extra functions not pertaining to the XPath spec                *
                   15046:  *                                                                     *
                   15047:  ************************************************************************/
                   15048: /**
                   15049:  * xmlXPathEscapeUriFunction:
                   15050:  * @ctxt:  the XPath Parser context
                   15051:  * @nargs:  the number of arguments
                   15052:  *
                   15053:  * Implement the escape-uri() XPath function
                   15054:  *    string escape-uri(string $str, bool $escape-reserved)
                   15055:  *
                   15056:  * This function applies the URI escaping rules defined in section 2 of [RFC
                   15057:  * 2396] to the string supplied as $uri-part, which typically represents all
                   15058:  * or part of a URI. The effect of the function is to replace any special
                   15059:  * character in the string by an escape sequence of the form %xx%yy...,
                   15060:  * where xxyy... is the hexadecimal representation of the octets used to
                   15061:  * represent the character in UTF-8.
                   15062:  *
                   15063:  * The set of characters that are escaped depends on the setting of the
                   15064:  * boolean argument $escape-reserved.
                   15065:  *
                   15066:  * If $escape-reserved is true, all characters are escaped other than lower
                   15067:  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
                   15068:  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
                   15069:  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
                   15070:  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
                   15071:  * A-F).
                   15072:  *
                   15073:  * If $escape-reserved is false, the behavior differs in that characters
                   15074:  * referred to in [RFC 2396] as reserved characters are not escaped. These
                   15075:  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
                   15076:  *
                   15077:  * [RFC 2396] does not define whether escaped URIs should use lower case or
                   15078:  * upper case for hexadecimal digits. To ensure that escaped URIs can be
                   15079:  * compared using string comparison functions, this function must always use
                   15080:  * the upper-case letters A-F.
                   15081:  *
                   15082:  * Generally, $escape-reserved should be set to true when escaping a string
                   15083:  * that is to form a single part of a URI, and to false when escaping an
                   15084:  * entire URI or URI reference.
                   15085:  *
                   15086:  * In the case of non-ascii characters, the string is encoded according to
                   15087:  * utf-8 and then converted according to RFC 2396.
                   15088:  *
                   15089:  * Examples
                   15090:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
                   15091:  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
                   15092:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
                   15093:  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
                   15094:  *
                   15095:  */
                   15096: static void
                   15097: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   15098:     xmlXPathObjectPtr str;
                   15099:     int escape_reserved;
                   15100:     xmlBufferPtr target;
                   15101:     xmlChar *cptr;
                   15102:     xmlChar escape[4];
                   15103: 
                   15104:     CHECK_ARITY(2);
                   15105: 
                   15106:     escape_reserved = xmlXPathPopBoolean(ctxt);
                   15107: 
                   15108:     CAST_TO_STRING;
                   15109:     str = valuePop(ctxt);
                   15110: 
                   15111:     target = xmlBufferCreate();
                   15112: 
                   15113:     escape[0] = '%';
                   15114:     escape[3] = 0;
                   15115: 
                   15116:     if (target) {
                   15117:        for (cptr = str->stringval; *cptr; cptr++) {
                   15118:            if ((*cptr >= 'A' && *cptr <= 'Z') ||
                   15119:                (*cptr >= 'a' && *cptr <= 'z') ||
                   15120:                (*cptr >= '0' && *cptr <= '9') ||
                   15121:                *cptr == '-' || *cptr == '_' || *cptr == '.' ||
                   15122:                *cptr == '!' || *cptr == '~' || *cptr == '*' ||
                   15123:                *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
                   15124:                (*cptr == '%' &&
                   15125:                 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
                   15126:                  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
                   15127:                  (cptr[1] >= '0' && cptr[1] <= '9')) &&
                   15128:                 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
                   15129:                  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
                   15130:                  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
                   15131:                (!escape_reserved &&
                   15132:                 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
                   15133:                  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
                   15134:                  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
                   15135:                  *cptr == ','))) {
                   15136:                xmlBufferAdd(target, cptr, 1);
                   15137:            } else {
                   15138:                if ((*cptr >> 4) < 10)
                   15139:                    escape[1] = '0' + (*cptr >> 4);
                   15140:                else
                   15141:                    escape[1] = 'A' - 10 + (*cptr >> 4);
                   15142:                if ((*cptr & 0xF) < 10)
                   15143:                    escape[2] = '0' + (*cptr & 0xF);
                   15144:                else
                   15145:                    escape[2] = 'A' - 10 + (*cptr & 0xF);
                   15146: 
                   15147:                xmlBufferAdd(target, &escape[0], 3);
                   15148:            }
                   15149:        }
                   15150:     }
                   15151:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   15152:        xmlBufferContent(target)));
                   15153:     xmlBufferFree(target);
                   15154:     xmlXPathReleaseObject(ctxt->context, str);
                   15155: }
                   15156: 
                   15157: /**
                   15158:  * xmlXPathRegisterAllFunctions:
                   15159:  * @ctxt:  the XPath context
                   15160:  *
                   15161:  * Registers all default XPath functions in this context
                   15162:  */
                   15163: void
                   15164: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
                   15165: {
                   15166:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
                   15167:                          xmlXPathBooleanFunction);
                   15168:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
                   15169:                          xmlXPathCeilingFunction);
                   15170:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
                   15171:                          xmlXPathCountFunction);
                   15172:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
                   15173:                          xmlXPathConcatFunction);
                   15174:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
                   15175:                          xmlXPathContainsFunction);
                   15176:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
                   15177:                          xmlXPathIdFunction);
                   15178:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
                   15179:                          xmlXPathFalseFunction);
                   15180:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
                   15181:                          xmlXPathFloorFunction);
                   15182:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
                   15183:                          xmlXPathLastFunction);
                   15184:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
                   15185:                          xmlXPathLangFunction);
                   15186:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
                   15187:                          xmlXPathLocalNameFunction);
                   15188:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
                   15189:                          xmlXPathNotFunction);
                   15190:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
                   15191:                          xmlXPathNameFunction);
                   15192:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
                   15193:                          xmlXPathNamespaceURIFunction);
                   15194:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
                   15195:                          xmlXPathNormalizeFunction);
                   15196:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
                   15197:                          xmlXPathNumberFunction);
                   15198:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
                   15199:                          xmlXPathPositionFunction);
                   15200:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
                   15201:                          xmlXPathRoundFunction);
                   15202:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
                   15203:                          xmlXPathStringFunction);
                   15204:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
                   15205:                          xmlXPathStringLengthFunction);
                   15206:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
                   15207:                          xmlXPathStartsWithFunction);
                   15208:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
                   15209:                          xmlXPathSubstringFunction);
                   15210:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
                   15211:                          xmlXPathSubstringBeforeFunction);
                   15212:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
                   15213:                          xmlXPathSubstringAfterFunction);
                   15214:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
                   15215:                          xmlXPathSumFunction);
                   15216:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
                   15217:                          xmlXPathTrueFunction);
                   15218:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
                   15219:                          xmlXPathTranslateFunction);
                   15220: 
                   15221:     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
                   15222:         (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
                   15223:                          xmlXPathEscapeUriFunction);
                   15224: }
                   15225: 
                   15226: #endif /* LIBXML_XPATH_ENABLED */
                   15227: #define bottom_xpath
                   15228: #include "elfgcchack.h"

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