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

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: 
1.1.1.3 ! misho      58: #include "buf.h"
        !            59: 
1.1       misho      60: #ifdef LIBXML_PATTERN_ENABLED
                     61: #define XPATH_STREAMING
                     62: #endif
                     63: 
                     64: #define TODO                                                           \
                     65:     xmlGenericError(xmlGenericErrorContext,                            \
                     66:            "Unimplemented block at %s:%d\n",                           \
                     67:             __FILE__, __LINE__);
                     68: 
1.1.1.3 ! misho      69: /**
        !            70:  * WITH_TIM_SORT:
        !            71:  *
        !            72:  * Use the Timsort algorithm provided in timsort.h to sort
        !            73:  * nodeset as this is a great improvement over the old Shell sort
        !            74:  * used in xmlXPathNodeSetSort()
        !            75:  */
        !            76: #define WITH_TIM_SORT
        !            77: 
1.1       misho      78: /*
                     79: * XP_OPTIMIZED_NON_ELEM_COMPARISON:
                     80: * If defined, this will use xmlXPathCmpNodesExt() instead of
                     81: * xmlXPathCmpNodes(). The new function is optimized comparison of
                     82: * non-element nodes; actually it will speed up comparison only if
                     83: * xmlXPathOrderDocElems() was called in order to index the elements of
                     84: * a tree in document order; Libxslt does such an indexing, thus it will
                     85: * benefit from this optimization.
                     86: */
                     87: #define XP_OPTIMIZED_NON_ELEM_COMPARISON
                     88: 
                     89: /*
                     90: * XP_OPTIMIZED_FILTER_FIRST:
                     91: * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
                     92: * in a way, that it stop evaluation at the first node.
                     93: */
                     94: #define XP_OPTIMIZED_FILTER_FIRST
                     95: 
                     96: /*
                     97: * XP_DEBUG_OBJ_USAGE:
                     98: * Internal flag to enable tracking of how much XPath objects have been
                     99: * created.
                    100: */
                    101: /* #define XP_DEBUG_OBJ_USAGE */
                    102: 
                    103: /*
1.1.1.3 ! misho     104:  * XPATH_MAX_STEPS:
        !           105:  * when compiling an XPath expression we arbitrary limit the maximum
        !           106:  * number of step operation in the compiled expression. 1000000 is
        !           107:  * an insanely large value which should never be reached under normal
        !           108:  * circumstances
        !           109:  */
        !           110: #define XPATH_MAX_STEPS 1000000
        !           111: 
        !           112: /*
        !           113:  * XPATH_MAX_STACK_DEPTH:
        !           114:  * when evaluating an XPath expression we arbitrary limit the maximum
        !           115:  * number of object allowed to be pushed on the stack. 1000000 is
        !           116:  * an insanely large value which should never be reached under normal
        !           117:  * circumstances
        !           118:  */
        !           119: #define XPATH_MAX_STACK_DEPTH 1000000
        !           120: 
        !           121: /*
        !           122:  * XPATH_MAX_NODESET_LENGTH:
        !           123:  * when evaluating an XPath expression nodesets are created and we
        !           124:  * arbitrary limit the maximum length of those node set. 10000000 is
        !           125:  * an insanely large value which should never be reached under normal
        !           126:  * circumstances, one would first need to construct an in memory tree
        !           127:  * with more than 10 millions nodes.
        !           128:  */
        !           129: #define XPATH_MAX_NODESET_LENGTH 10000000
        !           130: 
        !           131: /*
1.1       misho     132:  * TODO:
                    133:  * There are a few spots where some tests are done which depend upon ascii
                    134:  * data.  These should be enhanced for full UTF8 support (see particularly
                    135:  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
                    136:  */
                    137: 
1.1.1.3 ! misho     138: /*
        !           139:  * Wrapper for the Timsort argorithm from timsort.h
        !           140:  */
        !           141: #ifdef WITH_TIM_SORT
        !           142: #define SORT_NAME libxml_domnode
        !           143: #define SORT_TYPE xmlNodePtr
        !           144: /**
        !           145:  * wrap_cmp:
        !           146:  * @x: a node
        !           147:  * @y: another node
        !           148:  *
        !           149:  * Comparison function for the Timsort implementation
        !           150:  *
        !           151:  * Returns -2 in case of error -1 if first point < second point, 0 if
        !           152:  *         it's the same node, +1 otherwise
        !           153:  */
        !           154: static
        !           155: int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
        !           156: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
        !           157:     static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
        !           158:     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
        !           159:     {
        !           160:         int res = xmlXPathCmpNodesExt(x, y);
        !           161:         return res == -2 ? res : -res;
        !           162:     }
        !           163: #else
        !           164:     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
        !           165:     {
        !           166:         int res = xmlXPathCmpNodes(x, y);
        !           167:         return res == -2 ? res : -res;
        !           168:     }
        !           169: #endif
        !           170: #define SORT_CMP(x, y)  (wrap_cmp(x, y))
        !           171: #include "timsort.h"
        !           172: #endif /* WITH_TIM_SORT */
        !           173: 
1.1       misho     174: #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
                    175: 
                    176: /************************************************************************
                    177:  *                                                                     *
                    178:  *                     Floating point stuff                            *
                    179:  *                                                                     *
                    180:  ************************************************************************/
                    181: 
                    182: #ifndef TRIO_REPLACE_STDIO
                    183: #define TRIO_PUBLIC static
                    184: #endif
                    185: #include "trionan.c"
                    186: 
                    187: /*
                    188:  * The lack of portability of this section of the libc is annoying !
                    189:  */
                    190: double xmlXPathNAN = 0;
                    191: double xmlXPathPINF = 1;
                    192: double xmlXPathNINF = -1;
                    193: static double xmlXPathNZERO = 0; /* not exported from headers */
                    194: static int xmlXPathInitialized = 0;
                    195: 
                    196: /**
                    197:  * xmlXPathInit:
                    198:  *
                    199:  * Initialize the XPath environment
                    200:  */
                    201: void
                    202: xmlXPathInit(void) {
                    203:     if (xmlXPathInitialized) return;
                    204: 
                    205:     xmlXPathPINF = trio_pinf();
                    206:     xmlXPathNINF = trio_ninf();
                    207:     xmlXPathNAN = trio_nan();
                    208:     xmlXPathNZERO = trio_nzero();
                    209: 
                    210:     xmlXPathInitialized = 1;
                    211: }
                    212: 
                    213: /**
                    214:  * xmlXPathIsNaN:
                    215:  * @val:  a double value
                    216:  *
                    217:  * Provides a portable isnan() function to detect whether a double
                    218:  * is a NotaNumber. Based on trio code
                    219:  * http://sourceforge.net/projects/ctrio/
                    220:  *
                    221:  * Returns 1 if the value is a NaN, 0 otherwise
                    222:  */
                    223: int
                    224: xmlXPathIsNaN(double val) {
                    225:     return(trio_isnan(val));
                    226: }
                    227: 
                    228: /**
                    229:  * xmlXPathIsInf:
                    230:  * @val:  a double value
                    231:  *
                    232:  * Provides a portable isinf() function to detect whether a double
                    233:  * is a +Infinite or -Infinite. Based on trio code
                    234:  * http://sourceforge.net/projects/ctrio/
                    235:  *
                    236:  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
                    237:  */
                    238: int
                    239: xmlXPathIsInf(double val) {
                    240:     return(trio_isinf(val));
                    241: }
                    242: 
                    243: #endif /* SCHEMAS or XPATH */
                    244: #ifdef LIBXML_XPATH_ENABLED
                    245: /**
                    246:  * xmlXPathGetSign:
                    247:  * @val:  a double value
                    248:  *
                    249:  * Provides a portable function to detect the sign of a double
                    250:  * Modified from trio code
                    251:  * http://sourceforge.net/projects/ctrio/
                    252:  *
                    253:  * Returns 1 if the value is Negative, 0 if positive
                    254:  */
                    255: static int
                    256: xmlXPathGetSign(double val) {
                    257:     return(trio_signbit(val));
                    258: }
                    259: 
                    260: 
                    261: /*
                    262:  * TODO: when compatibility allows remove all "fake node libxslt" strings
                    263:  *       the test should just be name[0] = ' '
                    264:  */
                    265: #ifdef DEBUG_XPATH_EXPRESSION
                    266: #define DEBUG_STEP
                    267: #define DEBUG_EXPR
                    268: #define DEBUG_EVAL_COUNTS
                    269: #endif
                    270: 
                    271: static xmlNs xmlXPathXMLNamespaceStruct = {
                    272:     NULL,
                    273:     XML_NAMESPACE_DECL,
                    274:     XML_XML_NAMESPACE,
                    275:     BAD_CAST "xml",
                    276:     NULL,
                    277:     NULL
                    278: };
                    279: static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
                    280: #ifndef LIBXML_THREAD_ENABLED
                    281: /*
                    282:  * Optimizer is disabled only when threaded apps are detected while
                    283:  * the library ain't compiled for thread safety.
                    284:  */
                    285: static int xmlXPathDisableOptimizer = 0;
                    286: #endif
                    287: 
                    288: /************************************************************************
                    289:  *                                                                     *
                    290:  *                     Error handling routines                         *
                    291:  *                                                                     *
                    292:  ************************************************************************/
                    293: 
                    294: /**
                    295:  * XP_ERRORNULL:
                    296:  * @X:  the error code
                    297:  *
                    298:  * Macro to raise an XPath error and return NULL.
                    299:  */
                    300: #define XP_ERRORNULL(X)                                                        \
                    301:     { xmlXPathErr(ctxt, X); return(NULL); }
                    302: 
                    303: /*
                    304:  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
                    305:  */
                    306: static const char *xmlXPathErrorMessages[] = {
                    307:     "Ok\n",
                    308:     "Number encoding\n",
                    309:     "Unfinished literal\n",
                    310:     "Start of literal\n",
                    311:     "Expected $ for variable reference\n",
                    312:     "Undefined variable\n",
                    313:     "Invalid predicate\n",
                    314:     "Invalid expression\n",
                    315:     "Missing closing curly brace\n",
                    316:     "Unregistered function\n",
                    317:     "Invalid operand\n",
                    318:     "Invalid type\n",
                    319:     "Invalid number of arguments\n",
                    320:     "Invalid context size\n",
                    321:     "Invalid context position\n",
                    322:     "Memory allocation error\n",
                    323:     "Syntax error\n",
                    324:     "Resource error\n",
                    325:     "Sub resource error\n",
                    326:     "Undefined namespace prefix\n",
                    327:     "Encoding error\n",
                    328:     "Char out of XML range\n",
                    329:     "Invalid or incomplete context\n",
1.1.1.2   misho     330:     "Stack usage errror\n",
1.1.1.3 ! misho     331:     "Forbidden variable\n",
1.1       misho     332:     "?? Unknown error ??\n"    /* Must be last in the list! */
                    333: };
                    334: #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /        \
                    335:                   sizeof(xmlXPathErrorMessages[0])) - 1)
                    336: /**
                    337:  * xmlXPathErrMemory:
                    338:  * @ctxt:  an XPath context
                    339:  * @extra:  extra informations
                    340:  *
                    341:  * Handle a redefinition of attribute error
                    342:  */
                    343: static void
                    344: xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
                    345: {
                    346:     if (ctxt != NULL) {
                    347:         if (extra) {
                    348:             xmlChar buf[200];
                    349: 
                    350:             xmlStrPrintf(buf, 200,
                    351:                          BAD_CAST "Memory allocation failed : %s\n",
                    352:                          extra);
                    353:             ctxt->lastError.message = (char *) xmlStrdup(buf);
                    354:         } else {
                    355:             ctxt->lastError.message = (char *)
                    356:               xmlStrdup(BAD_CAST "Memory allocation failed\n");
                    357:         }
                    358:         ctxt->lastError.domain = XML_FROM_XPATH;
                    359:         ctxt->lastError.code = XML_ERR_NO_MEMORY;
                    360:        if (ctxt->error != NULL)
                    361:            ctxt->error(ctxt->userData, &ctxt->lastError);
                    362:     } else {
                    363:         if (extra)
                    364:             __xmlRaiseError(NULL, NULL, NULL,
                    365:                             NULL, NULL, XML_FROM_XPATH,
                    366:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
                    367:                             extra, NULL, NULL, 0, 0,
                    368:                             "Memory allocation failed : %s\n", extra);
                    369:         else
                    370:             __xmlRaiseError(NULL, NULL, NULL,
                    371:                             NULL, NULL, XML_FROM_XPATH,
                    372:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
                    373:                             NULL, NULL, NULL, 0, 0,
                    374:                             "Memory allocation failed\n");
                    375:     }
                    376: }
                    377: 
                    378: /**
                    379:  * xmlXPathPErrMemory:
                    380:  * @ctxt:  an XPath parser context
                    381:  * @extra:  extra informations
                    382:  *
                    383:  * Handle a redefinition of attribute error
                    384:  */
                    385: static void
                    386: xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
                    387: {
                    388:     if (ctxt == NULL)
                    389:        xmlXPathErrMemory(NULL, extra);
                    390:     else {
                    391:        ctxt->error = XPATH_MEMORY_ERROR;
                    392:        xmlXPathErrMemory(ctxt->context, extra);
                    393:     }
                    394: }
                    395: 
                    396: /**
                    397:  * xmlXPathErr:
                    398:  * @ctxt:  a XPath parser context
                    399:  * @error:  the error code
                    400:  *
                    401:  * Handle an XPath error
                    402:  */
                    403: void
                    404: xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
                    405: {
                    406:     if ((error < 0) || (error > MAXERRNO))
                    407:        error = MAXERRNO;
                    408:     if (ctxt == NULL) {
                    409:        __xmlRaiseError(NULL, NULL, NULL,
                    410:                        NULL, NULL, XML_FROM_XPATH,
                    411:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
                    412:                        XML_ERR_ERROR, NULL, 0,
                    413:                        NULL, NULL, NULL, 0, 0,
                    414:                        "%s", xmlXPathErrorMessages[error]);
                    415:        return;
                    416:     }
                    417:     ctxt->error = error;
                    418:     if (ctxt->context == NULL) {
                    419:        __xmlRaiseError(NULL, NULL, NULL,
                    420:                        NULL, NULL, XML_FROM_XPATH,
                    421:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
                    422:                        XML_ERR_ERROR, NULL, 0,
                    423:                        (const char *) ctxt->base, NULL, NULL,
                    424:                        ctxt->cur - ctxt->base, 0,
                    425:                        "%s", xmlXPathErrorMessages[error]);
                    426:        return;
                    427:     }
                    428: 
                    429:     /* cleanup current last error */
                    430:     xmlResetError(&ctxt->context->lastError);
                    431: 
                    432:     ctxt->context->lastError.domain = XML_FROM_XPATH;
                    433:     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
                    434:                            XPATH_EXPRESSION_OK;
                    435:     ctxt->context->lastError.level = XML_ERR_ERROR;
                    436:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
                    437:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
                    438:     ctxt->context->lastError.node = ctxt->context->debugNode;
                    439:     if (ctxt->context->error != NULL) {
                    440:        ctxt->context->error(ctxt->context->userData,
                    441:                             &ctxt->context->lastError);
                    442:     } else {
                    443:        __xmlRaiseError(NULL, NULL, NULL,
                    444:                        NULL, ctxt->context->debugNode, XML_FROM_XPATH,
                    445:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
                    446:                        XML_ERR_ERROR, NULL, 0,
                    447:                        (const char *) ctxt->base, NULL, NULL,
                    448:                        ctxt->cur - ctxt->base, 0,
                    449:                        "%s", xmlXPathErrorMessages[error]);
                    450:     }
                    451: 
                    452: }
                    453: 
                    454: /**
                    455:  * xmlXPatherror:
                    456:  * @ctxt:  the XPath Parser context
                    457:  * @file:  the file name
                    458:  * @line:  the line number
                    459:  * @no:  the error number
                    460:  *
                    461:  * Formats an error message.
                    462:  */
                    463: void
                    464: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
                    465:               int line ATTRIBUTE_UNUSED, int no) {
                    466:     xmlXPathErr(ctxt, no);
                    467: }
                    468: 
                    469: /************************************************************************
                    470:  *                                                                     *
                    471:  *                     Utilities                                       *
                    472:  *                                                                     *
                    473:  ************************************************************************/
                    474: 
                    475: /**
                    476:  * xsltPointerList:
                    477:  *
                    478:  * Pointer-list for various purposes.
                    479:  */
                    480: typedef struct _xmlPointerList xmlPointerList;
                    481: typedef xmlPointerList *xmlPointerListPtr;
                    482: struct _xmlPointerList {
                    483:     void **items;
                    484:     int number;
                    485:     int size;
                    486: };
                    487: /*
                    488: * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
                    489: * and here, we should make the functions public.
                    490: */
                    491: static int
                    492: xmlPointerListAddSize(xmlPointerListPtr list,
                    493:                       void *item,
                    494:                       int initialSize)
                    495: {
                    496:     if (list->items == NULL) {
                    497:        if (initialSize <= 0)
                    498:            initialSize = 1;
1.1.1.3 ! misho     499:        list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
1.1       misho     500:        if (list->items == NULL) {
                    501:            xmlXPathErrMemory(NULL,
                    502:                "xmlPointerListCreate: allocating item\n");
                    503:            return(-1);
                    504:        }
                    505:        list->number = 0;
                    506:        list->size = initialSize;
                    507:     } else if (list->size <= list->number) {
1.1.1.3 ! misho     508:         if (list->size > 50000000) {
        !           509:            xmlXPathErrMemory(NULL,
        !           510:                "xmlPointerListAddSize: re-allocating item\n");
        !           511:             return(-1);
        !           512:         }
1.1       misho     513:        list->size *= 2;
                    514:        list->items = (void **) xmlRealloc(list->items,
                    515:            list->size * sizeof(void *));
                    516:        if (list->items == NULL) {
                    517:            xmlXPathErrMemory(NULL,
1.1.1.3 ! misho     518:                "xmlPointerListAddSize: re-allocating item\n");
1.1       misho     519:            list->size = 0;
                    520:            return(-1);
                    521:        }
                    522:     }
                    523:     list->items[list->number++] = item;
                    524:     return(0);
                    525: }
                    526: 
                    527: /**
                    528:  * xsltPointerListCreate:
                    529:  *
                    530:  * Creates an xsltPointerList structure.
                    531:  *
                    532:  * Returns a xsltPointerList structure or NULL in case of an error.
                    533:  */
                    534: static xmlPointerListPtr
                    535: xmlPointerListCreate(int initialSize)
                    536: {
                    537:     xmlPointerListPtr ret;
                    538: 
                    539:     ret = xmlMalloc(sizeof(xmlPointerList));
                    540:     if (ret == NULL) {
                    541:        xmlXPathErrMemory(NULL,
                    542:            "xmlPointerListCreate: allocating item\n");
                    543:        return (NULL);
                    544:     }
                    545:     memset(ret, 0, sizeof(xmlPointerList));
                    546:     if (initialSize > 0) {
                    547:        xmlPointerListAddSize(ret, NULL, initialSize);
                    548:        ret->number = 0;
                    549:     }
                    550:     return (ret);
                    551: }
                    552: 
                    553: /**
                    554:  * xsltPointerListFree:
                    555:  *
                    556:  * Frees the xsltPointerList structure. This does not free
                    557:  * the content of the list.
                    558:  */
                    559: static void
                    560: xmlPointerListFree(xmlPointerListPtr list)
                    561: {
                    562:     if (list == NULL)
                    563:        return;
                    564:     if (list->items != NULL)
                    565:        xmlFree(list->items);
                    566:     xmlFree(list);
                    567: }
                    568: 
                    569: /************************************************************************
                    570:  *                                                                     *
                    571:  *                     Parser Types                                    *
                    572:  *                                                                     *
                    573:  ************************************************************************/
                    574: 
                    575: /*
                    576:  * Types are private:
                    577:  */
                    578: 
                    579: typedef enum {
                    580:     XPATH_OP_END=0,
                    581:     XPATH_OP_AND,
                    582:     XPATH_OP_OR,
                    583:     XPATH_OP_EQUAL,
                    584:     XPATH_OP_CMP,
                    585:     XPATH_OP_PLUS,
                    586:     XPATH_OP_MULT,
                    587:     XPATH_OP_UNION,
                    588:     XPATH_OP_ROOT,
                    589:     XPATH_OP_NODE,
                    590:     XPATH_OP_RESET, /* 10 */
                    591:     XPATH_OP_COLLECT,
                    592:     XPATH_OP_VALUE, /* 12 */
                    593:     XPATH_OP_VARIABLE,
                    594:     XPATH_OP_FUNCTION,
                    595:     XPATH_OP_ARG,
                    596:     XPATH_OP_PREDICATE,
                    597:     XPATH_OP_FILTER, /* 17 */
                    598:     XPATH_OP_SORT /* 18 */
                    599: #ifdef LIBXML_XPTR_ENABLED
                    600:     ,XPATH_OP_RANGETO
                    601: #endif
                    602: } xmlXPathOp;
                    603: 
                    604: typedef enum {
                    605:     AXIS_ANCESTOR = 1,
                    606:     AXIS_ANCESTOR_OR_SELF,
                    607:     AXIS_ATTRIBUTE,
                    608:     AXIS_CHILD,
                    609:     AXIS_DESCENDANT,
                    610:     AXIS_DESCENDANT_OR_SELF,
                    611:     AXIS_FOLLOWING,
                    612:     AXIS_FOLLOWING_SIBLING,
                    613:     AXIS_NAMESPACE,
                    614:     AXIS_PARENT,
                    615:     AXIS_PRECEDING,
                    616:     AXIS_PRECEDING_SIBLING,
                    617:     AXIS_SELF
                    618: } xmlXPathAxisVal;
                    619: 
                    620: typedef enum {
                    621:     NODE_TEST_NONE = 0,
                    622:     NODE_TEST_TYPE = 1,
                    623:     NODE_TEST_PI = 2,
                    624:     NODE_TEST_ALL = 3,
                    625:     NODE_TEST_NS = 4,
                    626:     NODE_TEST_NAME = 5
                    627: } xmlXPathTestVal;
                    628: 
                    629: typedef enum {
                    630:     NODE_TYPE_NODE = 0,
                    631:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
                    632:     NODE_TYPE_TEXT = XML_TEXT_NODE,
                    633:     NODE_TYPE_PI = XML_PI_NODE
                    634: } xmlXPathTypeVal;
                    635: 
                    636: typedef struct _xmlXPathStepOp xmlXPathStepOp;
                    637: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
                    638: struct _xmlXPathStepOp {
                    639:     xmlXPathOp op;             /* The identifier of the operation */
                    640:     int ch1;                   /* First child */
                    641:     int ch2;                   /* Second child */
                    642:     int value;
                    643:     int value2;
                    644:     int value3;
                    645:     void *value4;
                    646:     void *value5;
                    647:     void *cache;
                    648:     void *cacheURI;
                    649: };
                    650: 
                    651: struct _xmlXPathCompExpr {
                    652:     int nbStep;                        /* Number of steps in this expression */
                    653:     int maxStep;               /* Maximum number of steps allocated */
                    654:     xmlXPathStepOp *steps;     /* ops for computation of this expression */
                    655:     int last;                  /* index of last step in expression */
                    656:     xmlChar *expr;             /* the expression being computed */
                    657:     xmlDictPtr dict;           /* the dictionnary to use if any */
                    658: #ifdef DEBUG_EVAL_COUNTS
                    659:     int nb;
                    660:     xmlChar *string;
                    661: #endif
                    662: #ifdef XPATH_STREAMING
                    663:     xmlPatternPtr stream;
                    664: #endif
                    665: };
                    666: 
                    667: /************************************************************************
                    668:  *                                                                     *
                    669:  *                     Forward declarations                            *
                    670:  *                                                                     *
                    671:  ************************************************************************/
                    672: static void
                    673: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
                    674: static void
                    675: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
                    676: static int
                    677: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
                    678:                         xmlXPathStepOpPtr op, xmlNodePtr *first);
                    679: static int
                    680: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
                    681:                            xmlXPathStepOpPtr op,
                    682:                            int isPredicate);
                    683: 
                    684: /************************************************************************
                    685:  *                                                                     *
                    686:  *                     Parser Type functions                           *
                    687:  *                                                                     *
                    688:  ************************************************************************/
                    689: 
                    690: /**
                    691:  * xmlXPathNewCompExpr:
                    692:  *
                    693:  * Create a new Xpath component
                    694:  *
                    695:  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
                    696:  */
                    697: static xmlXPathCompExprPtr
                    698: xmlXPathNewCompExpr(void) {
                    699:     xmlXPathCompExprPtr cur;
                    700: 
                    701:     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
                    702:     if (cur == NULL) {
                    703:         xmlXPathErrMemory(NULL, "allocating component\n");
                    704:        return(NULL);
                    705:     }
                    706:     memset(cur, 0, sizeof(xmlXPathCompExpr));
                    707:     cur->maxStep = 10;
                    708:     cur->nbStep = 0;
                    709:     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
                    710:                                           sizeof(xmlXPathStepOp));
                    711:     if (cur->steps == NULL) {
                    712:         xmlXPathErrMemory(NULL, "allocating steps\n");
                    713:        xmlFree(cur);
                    714:        return(NULL);
                    715:     }
                    716:     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
                    717:     cur->last = -1;
                    718: #ifdef DEBUG_EVAL_COUNTS
                    719:     cur->nb = 0;
                    720: #endif
                    721:     return(cur);
                    722: }
                    723: 
                    724: /**
                    725:  * xmlXPathFreeCompExpr:
                    726:  * @comp:  an XPATH comp
                    727:  *
                    728:  * Free up the memory allocated by @comp
                    729:  */
                    730: void
                    731: xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
                    732: {
                    733:     xmlXPathStepOpPtr op;
                    734:     int i;
                    735: 
                    736:     if (comp == NULL)
                    737:         return;
                    738:     if (comp->dict == NULL) {
                    739:        for (i = 0; i < comp->nbStep; i++) {
                    740:            op = &comp->steps[i];
                    741:            if (op->value4 != NULL) {
                    742:                if (op->op == XPATH_OP_VALUE)
                    743:                    xmlXPathFreeObject(op->value4);
                    744:                else
                    745:                    xmlFree(op->value4);
                    746:            }
                    747:            if (op->value5 != NULL)
                    748:                xmlFree(op->value5);
                    749:        }
                    750:     } else {
                    751:        for (i = 0; i < comp->nbStep; i++) {
                    752:            op = &comp->steps[i];
                    753:            if (op->value4 != NULL) {
                    754:                if (op->op == XPATH_OP_VALUE)
                    755:                    xmlXPathFreeObject(op->value4);
                    756:            }
                    757:        }
                    758:         xmlDictFree(comp->dict);
                    759:     }
                    760:     if (comp->steps != NULL) {
                    761:         xmlFree(comp->steps);
                    762:     }
                    763: #ifdef DEBUG_EVAL_COUNTS
                    764:     if (comp->string != NULL) {
                    765:         xmlFree(comp->string);
                    766:     }
                    767: #endif
                    768: #ifdef XPATH_STREAMING
                    769:     if (comp->stream != NULL) {
                    770:         xmlFreePatternList(comp->stream);
                    771:     }
                    772: #endif
                    773:     if (comp->expr != NULL) {
                    774:         xmlFree(comp->expr);
                    775:     }
                    776: 
                    777:     xmlFree(comp);
                    778: }
                    779: 
                    780: /**
                    781:  * xmlXPathCompExprAdd:
                    782:  * @comp:  the compiled expression
                    783:  * @ch1: first child index
                    784:  * @ch2: second child index
                    785:  * @op:  an op
                    786:  * @value:  the first int value
                    787:  * @value2:  the second int value
                    788:  * @value3:  the third int value
                    789:  * @value4:  the first string value
                    790:  * @value5:  the second string value
                    791:  *
                    792:  * Add a step to an XPath Compiled Expression
                    793:  *
                    794:  * Returns -1 in case of failure, the index otherwise
                    795:  */
                    796: static int
                    797: xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
                    798:    xmlXPathOp op, int value,
                    799:    int value2, int value3, void *value4, void *value5) {
                    800:     if (comp->nbStep >= comp->maxStep) {
                    801:        xmlXPathStepOp *real;
                    802: 
1.1.1.3 ! misho     803:         if (comp->maxStep >= XPATH_MAX_STEPS) {
        !           804:            xmlXPathErrMemory(NULL, "adding step\n");
        !           805:            return(-1);
        !           806:         }
1.1       misho     807:        comp->maxStep *= 2;
                    808:        real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
                    809:                                      comp->maxStep * sizeof(xmlXPathStepOp));
                    810:        if (real == NULL) {
                    811:            comp->maxStep /= 2;
                    812:            xmlXPathErrMemory(NULL, "adding step\n");
                    813:            return(-1);
                    814:        }
                    815:        comp->steps = real;
                    816:     }
                    817:     comp->last = comp->nbStep;
                    818:     comp->steps[comp->nbStep].ch1 = ch1;
                    819:     comp->steps[comp->nbStep].ch2 = ch2;
                    820:     comp->steps[comp->nbStep].op = op;
                    821:     comp->steps[comp->nbStep].value = value;
                    822:     comp->steps[comp->nbStep].value2 = value2;
                    823:     comp->steps[comp->nbStep].value3 = value3;
                    824:     if ((comp->dict != NULL) &&
                    825:         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
                    826:         (op == XPATH_OP_COLLECT))) {
                    827:         if (value4 != NULL) {
                    828:            comp->steps[comp->nbStep].value4 = (xmlChar *)
                    829:                (void *)xmlDictLookup(comp->dict, value4, -1);
                    830:            xmlFree(value4);
                    831:        } else
                    832:            comp->steps[comp->nbStep].value4 = NULL;
                    833:         if (value5 != NULL) {
                    834:            comp->steps[comp->nbStep].value5 = (xmlChar *)
                    835:                (void *)xmlDictLookup(comp->dict, value5, -1);
                    836:            xmlFree(value5);
                    837:        } else
                    838:            comp->steps[comp->nbStep].value5 = NULL;
                    839:     } else {
                    840:        comp->steps[comp->nbStep].value4 = value4;
                    841:        comp->steps[comp->nbStep].value5 = value5;
                    842:     }
                    843:     comp->steps[comp->nbStep].cache = NULL;
                    844:     return(comp->nbStep++);
                    845: }
                    846: 
                    847: /**
                    848:  * xmlXPathCompSwap:
                    849:  * @comp:  the compiled expression
                    850:  * @op: operation index
                    851:  *
                    852:  * Swaps 2 operations in the compiled expression
                    853:  */
                    854: static void
                    855: xmlXPathCompSwap(xmlXPathStepOpPtr op) {
                    856:     int tmp;
                    857: 
                    858: #ifndef LIBXML_THREAD_ENABLED
                    859:     /*
                    860:      * Since this manipulates possibly shared variables, this is
                    861:      * disabled if one detects that the library is used in a multithreaded
                    862:      * application
                    863:      */
                    864:     if (xmlXPathDisableOptimizer)
                    865:        return;
                    866: #endif
                    867: 
                    868:     tmp = op->ch1;
                    869:     op->ch1 = op->ch2;
                    870:     op->ch2 = tmp;
                    871: }
                    872: 
                    873: #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)      \
                    874:     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                      \
                    875:                        (op), (val), (val2), (val3), (val4), (val5))
                    876: #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                        \
                    877:     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,              \
                    878:                        (op), (val), (val2), (val3), (val4), (val5))
                    879: 
                    880: #define PUSH_LEAVE_EXPR(op, val, val2)                                 \
                    881: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
                    882: 
                    883: #define PUSH_UNARY_EXPR(op, ch, val, val2)                             \
                    884: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
                    885: 
                    886: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                      \
                    887: xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                    \
                    888:                        (val), (val2), 0 ,NULL ,NULL)
                    889: 
                    890: /************************************************************************
                    891:  *                                                                     *
                    892:  *             XPath object cache structures                           *
                    893:  *                                                                     *
                    894:  ************************************************************************/
                    895: 
                    896: /* #define XP_DEFAULT_CACHE_ON */
                    897: 
                    898: #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
                    899: 
                    900: typedef struct _xmlXPathContextCache xmlXPathContextCache;
                    901: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
                    902: struct _xmlXPathContextCache {
                    903:     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
                    904:     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
                    905:     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
                    906:     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
                    907:     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
                    908:     int maxNodeset;
                    909:     int maxString;
                    910:     int maxBoolean;
                    911:     int maxNumber;
                    912:     int maxMisc;
                    913: #ifdef XP_DEBUG_OBJ_USAGE
                    914:     int dbgCachedAll;
                    915:     int dbgCachedNodeset;
                    916:     int dbgCachedString;
                    917:     int dbgCachedBool;
                    918:     int dbgCachedNumber;
                    919:     int dbgCachedPoint;
                    920:     int dbgCachedRange;
                    921:     int dbgCachedLocset;
                    922:     int dbgCachedUsers;
                    923:     int dbgCachedXSLTTree;
                    924:     int dbgCachedUndefined;
                    925: 
                    926: 
                    927:     int dbgReusedAll;
                    928:     int dbgReusedNodeset;
                    929:     int dbgReusedString;
                    930:     int dbgReusedBool;
                    931:     int dbgReusedNumber;
                    932:     int dbgReusedPoint;
                    933:     int dbgReusedRange;
                    934:     int dbgReusedLocset;
                    935:     int dbgReusedUsers;
                    936:     int dbgReusedXSLTTree;
                    937:     int dbgReusedUndefined;
                    938: 
                    939: #endif
                    940: };
                    941: 
                    942: /************************************************************************
                    943:  *                                                                     *
                    944:  *             Debugging related functions                             *
                    945:  *                                                                     *
                    946:  ************************************************************************/
                    947: 
                    948: #define STRANGE                                                        \
                    949:     xmlGenericError(xmlGenericErrorContext,                            \
                    950:            "Internal error at %s:%d\n",                                \
                    951:             __FILE__, __LINE__);
                    952: 
                    953: #ifdef LIBXML_DEBUG_ENABLED
                    954: static void
                    955: xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
                    956:     int i;
                    957:     char shift[100];
                    958: 
                    959:     for (i = 0;((i < depth) && (i < 25));i++)
                    960:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    961:     shift[2 * i] = shift[2 * i + 1] = 0;
                    962:     if (cur == NULL) {
                    963:        fprintf(output, "%s", shift);
                    964:        fprintf(output, "Node is NULL !\n");
                    965:        return;
                    966: 
                    967:     }
                    968: 
                    969:     if ((cur->type == XML_DOCUMENT_NODE) ||
                    970:             (cur->type == XML_HTML_DOCUMENT_NODE)) {
                    971:        fprintf(output, "%s", shift);
                    972:        fprintf(output, " /\n");
                    973:     } else if (cur->type == XML_ATTRIBUTE_NODE)
                    974:        xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
                    975:     else
                    976:        xmlDebugDumpOneNode(output, cur, depth);
                    977: }
                    978: static void
                    979: xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
                    980:     xmlNodePtr tmp;
                    981:     int i;
                    982:     char shift[100];
                    983: 
                    984:     for (i = 0;((i < depth) && (i < 25));i++)
                    985:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    986:     shift[2 * i] = shift[2 * i + 1] = 0;
                    987:     if (cur == NULL) {
                    988:        fprintf(output, "%s", shift);
                    989:        fprintf(output, "Node is NULL !\n");
                    990:        return;
                    991: 
                    992:     }
                    993: 
                    994:     while (cur != NULL) {
                    995:        tmp = cur;
                    996:        cur = cur->next;
                    997:        xmlDebugDumpOneNode(output, tmp, depth);
                    998:     }
                    999: }
                   1000: 
                   1001: static void
                   1002: xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
                   1003:     int i;
                   1004:     char shift[100];
                   1005: 
                   1006:     for (i = 0;((i < depth) && (i < 25));i++)
                   1007:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1008:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1009: 
                   1010:     if (cur == NULL) {
                   1011:        fprintf(output, "%s", shift);
                   1012:        fprintf(output, "NodeSet is NULL !\n");
                   1013:        return;
                   1014: 
                   1015:     }
                   1016: 
                   1017:     if (cur != NULL) {
                   1018:        fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
                   1019:        for (i = 0;i < cur->nodeNr;i++) {
                   1020:            fprintf(output, "%s", shift);
                   1021:            fprintf(output, "%d", i + 1);
                   1022:            xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
                   1023:        }
                   1024:     }
                   1025: }
                   1026: 
                   1027: static void
                   1028: xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
                   1029:     int i;
                   1030:     char shift[100];
                   1031: 
                   1032:     for (i = 0;((i < depth) && (i < 25));i++)
                   1033:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1034:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1035: 
                   1036:     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
                   1037:        fprintf(output, "%s", shift);
                   1038:        fprintf(output, "Value Tree is NULL !\n");
                   1039:        return;
                   1040: 
                   1041:     }
                   1042: 
                   1043:     fprintf(output, "%s", shift);
                   1044:     fprintf(output, "%d", i + 1);
                   1045:     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
                   1046: }
                   1047: #if defined(LIBXML_XPTR_ENABLED)
                   1048: static void
                   1049: xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
                   1050:     int i;
                   1051:     char shift[100];
                   1052: 
                   1053:     for (i = 0;((i < depth) && (i < 25));i++)
                   1054:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1055:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1056: 
                   1057:     if (cur == NULL) {
                   1058:        fprintf(output, "%s", shift);
                   1059:        fprintf(output, "LocationSet is NULL !\n");
                   1060:        return;
                   1061: 
                   1062:     }
                   1063: 
                   1064:     for (i = 0;i < cur->locNr;i++) {
                   1065:        fprintf(output, "%s", shift);
                   1066:         fprintf(output, "%d : ", i + 1);
                   1067:        xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
                   1068:     }
                   1069: }
                   1070: #endif /* LIBXML_XPTR_ENABLED */
                   1071: 
                   1072: /**
                   1073:  * xmlXPathDebugDumpObject:
                   1074:  * @output:  the FILE * to dump the output
                   1075:  * @cur:  the object to inspect
                   1076:  * @depth:  indentation level
                   1077:  *
                   1078:  * Dump the content of the object for debugging purposes
                   1079:  */
                   1080: void
                   1081: xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
                   1082:     int i;
                   1083:     char shift[100];
                   1084: 
                   1085:     if (output == NULL) return;
                   1086: 
                   1087:     for (i = 0;((i < depth) && (i < 25));i++)
                   1088:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1089:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1090: 
                   1091: 
                   1092:     fprintf(output, "%s", shift);
                   1093: 
                   1094:     if (cur == NULL) {
                   1095:         fprintf(output, "Object is empty (NULL)\n");
                   1096:        return;
                   1097:     }
                   1098:     switch(cur->type) {
                   1099:         case XPATH_UNDEFINED:
                   1100:            fprintf(output, "Object is uninitialized\n");
                   1101:            break;
                   1102:         case XPATH_NODESET:
                   1103:            fprintf(output, "Object is a Node Set :\n");
                   1104:            xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
                   1105:            break;
                   1106:        case XPATH_XSLT_TREE:
                   1107:            fprintf(output, "Object is an XSLT value tree :\n");
                   1108:            xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
                   1109:            break;
                   1110:         case XPATH_BOOLEAN:
                   1111:            fprintf(output, "Object is a Boolean : ");
                   1112:            if (cur->boolval) fprintf(output, "true\n");
                   1113:            else fprintf(output, "false\n");
                   1114:            break;
                   1115:         case XPATH_NUMBER:
                   1116:            switch (xmlXPathIsInf(cur->floatval)) {
                   1117:            case 1:
                   1118:                fprintf(output, "Object is a number : Infinity\n");
                   1119:                break;
                   1120:            case -1:
                   1121:                fprintf(output, "Object is a number : -Infinity\n");
                   1122:                break;
                   1123:            default:
                   1124:                if (xmlXPathIsNaN(cur->floatval)) {
                   1125:                    fprintf(output, "Object is a number : NaN\n");
                   1126:                } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
                   1127:                    fprintf(output, "Object is a number : 0\n");
                   1128:                } else {
                   1129:                    fprintf(output, "Object is a number : %0g\n", cur->floatval);
                   1130:                }
                   1131:            }
                   1132:            break;
                   1133:         case XPATH_STRING:
                   1134:            fprintf(output, "Object is a string : ");
                   1135:            xmlDebugDumpString(output, cur->stringval);
                   1136:            fprintf(output, "\n");
                   1137:            break;
                   1138:        case XPATH_POINT:
                   1139:            fprintf(output, "Object is a point : index %d in node", cur->index);
                   1140:            xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
                   1141:            fprintf(output, "\n");
                   1142:            break;
                   1143:        case XPATH_RANGE:
                   1144:            if ((cur->user2 == NULL) ||
                   1145:                ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
                   1146:                fprintf(output, "Object is a collapsed range :\n");
                   1147:                fprintf(output, "%s", shift);
                   1148:                if (cur->index >= 0)
                   1149:                    fprintf(output, "index %d in ", cur->index);
                   1150:                fprintf(output, "node\n");
                   1151:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
                   1152:                                      depth + 1);
                   1153:            } else  {
                   1154:                fprintf(output, "Object is a range :\n");
                   1155:                fprintf(output, "%s", shift);
                   1156:                fprintf(output, "From ");
                   1157:                if (cur->index >= 0)
                   1158:                    fprintf(output, "index %d in ", cur->index);
                   1159:                fprintf(output, "node\n");
                   1160:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
                   1161:                                      depth + 1);
                   1162:                fprintf(output, "%s", shift);
                   1163:                fprintf(output, "To ");
                   1164:                if (cur->index2 >= 0)
                   1165:                    fprintf(output, "index %d in ", cur->index2);
                   1166:                fprintf(output, "node\n");
                   1167:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
                   1168:                                      depth + 1);
                   1169:                fprintf(output, "\n");
                   1170:            }
                   1171:            break;
                   1172:        case XPATH_LOCATIONSET:
                   1173: #if defined(LIBXML_XPTR_ENABLED)
                   1174:            fprintf(output, "Object is a Location Set:\n");
                   1175:            xmlXPathDebugDumpLocationSet(output,
                   1176:                    (xmlLocationSetPtr) cur->user, depth);
                   1177: #endif
                   1178:            break;
                   1179:        case XPATH_USERS:
                   1180:            fprintf(output, "Object is user defined\n");
                   1181:            break;
                   1182:     }
                   1183: }
                   1184: 
                   1185: static void
                   1186: xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
                   1187:                             xmlXPathStepOpPtr op, int depth) {
                   1188:     int i;
                   1189:     char shift[100];
                   1190: 
                   1191:     for (i = 0;((i < depth) && (i < 25));i++)
                   1192:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1193:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1194: 
                   1195:     fprintf(output, "%s", shift);
                   1196:     if (op == NULL) {
                   1197:        fprintf(output, "Step is NULL\n");
                   1198:        return;
                   1199:     }
                   1200:     switch (op->op) {
                   1201:         case XPATH_OP_END:
                   1202:            fprintf(output, "END"); break;
                   1203:         case XPATH_OP_AND:
                   1204:            fprintf(output, "AND"); break;
                   1205:         case XPATH_OP_OR:
                   1206:            fprintf(output, "OR"); break;
                   1207:         case XPATH_OP_EQUAL:
                   1208:             if (op->value)
                   1209:                 fprintf(output, "EQUAL =");
                   1210:             else
                   1211:                 fprintf(output, "EQUAL !=");
                   1212:             break;
                   1213:         case XPATH_OP_CMP:
                   1214:             if (op->value)
                   1215:                 fprintf(output, "CMP <");
                   1216:             else
                   1217:                 fprintf(output, "CMP >");
                   1218:             if (!op->value2)
                   1219:                 fprintf(output, "=");
                   1220:             break;
                   1221:         case XPATH_OP_PLUS:
                   1222:             if (op->value == 0)
                   1223:                 fprintf(output, "PLUS -");
                   1224:             else if (op->value == 1)
                   1225:                 fprintf(output, "PLUS +");
                   1226:             else if (op->value == 2)
                   1227:                 fprintf(output, "PLUS unary -");
                   1228:             else if (op->value == 3)
                   1229:                 fprintf(output, "PLUS unary - -");
                   1230:             break;
                   1231:         case XPATH_OP_MULT:
                   1232:             if (op->value == 0)
                   1233:                 fprintf(output, "MULT *");
                   1234:             else if (op->value == 1)
                   1235:                 fprintf(output, "MULT div");
                   1236:             else
                   1237:                 fprintf(output, "MULT mod");
                   1238:             break;
                   1239:         case XPATH_OP_UNION:
                   1240:             fprintf(output, "UNION"); break;
                   1241:         case XPATH_OP_ROOT:
                   1242:             fprintf(output, "ROOT"); break;
                   1243:         case XPATH_OP_NODE:
                   1244:             fprintf(output, "NODE"); break;
                   1245:         case XPATH_OP_RESET:
                   1246:             fprintf(output, "RESET"); break;
                   1247:         case XPATH_OP_SORT:
                   1248:             fprintf(output, "SORT"); break;
                   1249:         case XPATH_OP_COLLECT: {
                   1250:            xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
                   1251:            xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
                   1252:            xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
                   1253:            const xmlChar *prefix = op->value4;
                   1254:            const xmlChar *name = op->value5;
                   1255: 
                   1256:            fprintf(output, "COLLECT ");
                   1257:            switch (axis) {
                   1258:                case AXIS_ANCESTOR:
                   1259:                    fprintf(output, " 'ancestors' "); break;
                   1260:                case AXIS_ANCESTOR_OR_SELF:
                   1261:                    fprintf(output, " 'ancestors-or-self' "); break;
                   1262:                case AXIS_ATTRIBUTE:
                   1263:                    fprintf(output, " 'attributes' "); break;
                   1264:                case AXIS_CHILD:
                   1265:                    fprintf(output, " 'child' "); break;
                   1266:                case AXIS_DESCENDANT:
                   1267:                    fprintf(output, " 'descendant' "); break;
                   1268:                case AXIS_DESCENDANT_OR_SELF:
                   1269:                    fprintf(output, " 'descendant-or-self' "); break;
                   1270:                case AXIS_FOLLOWING:
                   1271:                    fprintf(output, " 'following' "); break;
                   1272:                case AXIS_FOLLOWING_SIBLING:
                   1273:                    fprintf(output, " 'following-siblings' "); break;
                   1274:                case AXIS_NAMESPACE:
                   1275:                    fprintf(output, " 'namespace' "); break;
                   1276:                case AXIS_PARENT:
                   1277:                    fprintf(output, " 'parent' "); break;
                   1278:                case AXIS_PRECEDING:
                   1279:                    fprintf(output, " 'preceding' "); break;
                   1280:                case AXIS_PRECEDING_SIBLING:
                   1281:                    fprintf(output, " 'preceding-sibling' "); break;
                   1282:                case AXIS_SELF:
                   1283:                    fprintf(output, " 'self' "); break;
                   1284:            }
                   1285:            switch (test) {
                   1286:                 case NODE_TEST_NONE:
                   1287:                    fprintf(output, "'none' "); break;
                   1288:                 case NODE_TEST_TYPE:
                   1289:                    fprintf(output, "'type' "); break;
                   1290:                 case NODE_TEST_PI:
                   1291:                    fprintf(output, "'PI' "); break;
                   1292:                 case NODE_TEST_ALL:
                   1293:                    fprintf(output, "'all' "); break;
                   1294:                 case NODE_TEST_NS:
                   1295:                    fprintf(output, "'namespace' "); break;
                   1296:                 case NODE_TEST_NAME:
                   1297:                    fprintf(output, "'name' "); break;
                   1298:            }
                   1299:            switch (type) {
                   1300:                 case NODE_TYPE_NODE:
                   1301:                    fprintf(output, "'node' "); break;
                   1302:                 case NODE_TYPE_COMMENT:
                   1303:                    fprintf(output, "'comment' "); break;
                   1304:                 case NODE_TYPE_TEXT:
                   1305:                    fprintf(output, "'text' "); break;
                   1306:                 case NODE_TYPE_PI:
                   1307:                    fprintf(output, "'PI' "); break;
                   1308:            }
                   1309:            if (prefix != NULL)
                   1310:                fprintf(output, "%s:", prefix);
                   1311:            if (name != NULL)
                   1312:                fprintf(output, "%s", (const char *) name);
                   1313:            break;
                   1314: 
                   1315:         }
                   1316:        case XPATH_OP_VALUE: {
                   1317:            xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
                   1318: 
                   1319:            fprintf(output, "ELEM ");
                   1320:            xmlXPathDebugDumpObject(output, object, 0);
                   1321:            goto finish;
                   1322:        }
                   1323:        case XPATH_OP_VARIABLE: {
                   1324:            const xmlChar *prefix = op->value5;
                   1325:            const xmlChar *name = op->value4;
                   1326: 
                   1327:            if (prefix != NULL)
                   1328:                fprintf(output, "VARIABLE %s:%s", prefix, name);
                   1329:            else
                   1330:                fprintf(output, "VARIABLE %s", name);
                   1331:            break;
                   1332:        }
                   1333:        case XPATH_OP_FUNCTION: {
                   1334:            int nbargs = op->value;
                   1335:            const xmlChar *prefix = op->value5;
                   1336:            const xmlChar *name = op->value4;
                   1337: 
                   1338:            if (prefix != NULL)
                   1339:                fprintf(output, "FUNCTION %s:%s(%d args)",
                   1340:                        prefix, name, nbargs);
                   1341:            else
                   1342:                fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
                   1343:            break;
                   1344:        }
                   1345:         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
                   1346:         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
                   1347:         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
                   1348: #ifdef LIBXML_XPTR_ENABLED
                   1349:         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
                   1350: #endif
                   1351:        default:
                   1352:         fprintf(output, "UNKNOWN %d\n", op->op); return;
                   1353:     }
                   1354:     fprintf(output, "\n");
                   1355: finish:
                   1356:     if (op->ch1 >= 0)
                   1357:        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
                   1358:     if (op->ch2 >= 0)
                   1359:        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
                   1360: }
                   1361: 
                   1362: /**
                   1363:  * xmlXPathDebugDumpCompExpr:
                   1364:  * @output:  the FILE * for the output
                   1365:  * @comp:  the precompiled XPath expression
                   1366:  * @depth:  the indentation level.
                   1367:  *
                   1368:  * Dumps the tree of the compiled XPath expression.
                   1369:  */
                   1370: void
                   1371: xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
                   1372:                          int depth) {
                   1373:     int i;
                   1374:     char shift[100];
                   1375: 
                   1376:     if ((output == NULL) || (comp == NULL)) return;
                   1377: 
                   1378:     for (i = 0;((i < depth) && (i < 25));i++)
                   1379:         shift[2 * i] = shift[2 * i + 1] = ' ';
                   1380:     shift[2 * i] = shift[2 * i + 1] = 0;
                   1381: 
                   1382:     fprintf(output, "%s", shift);
                   1383: 
                   1384:     fprintf(output, "Compiled Expression : %d elements\n",
                   1385:            comp->nbStep);
                   1386:     i = comp->last;
                   1387:     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
                   1388: }
                   1389: 
                   1390: #ifdef XP_DEBUG_OBJ_USAGE
                   1391: 
                   1392: /*
                   1393: * XPath object usage related debugging variables.
                   1394: */
                   1395: static int xmlXPathDebugObjCounterUndefined = 0;
                   1396: static int xmlXPathDebugObjCounterNodeset = 0;
                   1397: static int xmlXPathDebugObjCounterBool = 0;
                   1398: static int xmlXPathDebugObjCounterNumber = 0;
                   1399: static int xmlXPathDebugObjCounterString = 0;
                   1400: static int xmlXPathDebugObjCounterPoint = 0;
                   1401: static int xmlXPathDebugObjCounterRange = 0;
                   1402: static int xmlXPathDebugObjCounterLocset = 0;
                   1403: static int xmlXPathDebugObjCounterUsers = 0;
                   1404: static int xmlXPathDebugObjCounterXSLTTree = 0;
                   1405: static int xmlXPathDebugObjCounterAll = 0;
                   1406: 
                   1407: static int xmlXPathDebugObjTotalUndefined = 0;
                   1408: static int xmlXPathDebugObjTotalNodeset = 0;
                   1409: static int xmlXPathDebugObjTotalBool = 0;
                   1410: static int xmlXPathDebugObjTotalNumber = 0;
                   1411: static int xmlXPathDebugObjTotalString = 0;
                   1412: static int xmlXPathDebugObjTotalPoint = 0;
                   1413: static int xmlXPathDebugObjTotalRange = 0;
                   1414: static int xmlXPathDebugObjTotalLocset = 0;
                   1415: static int xmlXPathDebugObjTotalUsers = 0;
                   1416: static int xmlXPathDebugObjTotalXSLTTree = 0;
                   1417: static int xmlXPathDebugObjTotalAll = 0;
                   1418: 
                   1419: static int xmlXPathDebugObjMaxUndefined = 0;
                   1420: static int xmlXPathDebugObjMaxNodeset = 0;
                   1421: static int xmlXPathDebugObjMaxBool = 0;
                   1422: static int xmlXPathDebugObjMaxNumber = 0;
                   1423: static int xmlXPathDebugObjMaxString = 0;
                   1424: static int xmlXPathDebugObjMaxPoint = 0;
                   1425: static int xmlXPathDebugObjMaxRange = 0;
                   1426: static int xmlXPathDebugObjMaxLocset = 0;
                   1427: static int xmlXPathDebugObjMaxUsers = 0;
                   1428: static int xmlXPathDebugObjMaxXSLTTree = 0;
                   1429: static int xmlXPathDebugObjMaxAll = 0;
                   1430: 
                   1431: /* REVISIT TODO: Make this static when committing */
                   1432: static void
                   1433: xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
                   1434: {
                   1435:     if (ctxt != NULL) {
                   1436:        if (ctxt->cache != NULL) {
                   1437:            xmlXPathContextCachePtr cache =
                   1438:                (xmlXPathContextCachePtr) ctxt->cache;
                   1439: 
                   1440:            cache->dbgCachedAll = 0;
                   1441:            cache->dbgCachedNodeset = 0;
                   1442:            cache->dbgCachedString = 0;
                   1443:            cache->dbgCachedBool = 0;
                   1444:            cache->dbgCachedNumber = 0;
                   1445:            cache->dbgCachedPoint = 0;
                   1446:            cache->dbgCachedRange = 0;
                   1447:            cache->dbgCachedLocset = 0;
                   1448:            cache->dbgCachedUsers = 0;
                   1449:            cache->dbgCachedXSLTTree = 0;
                   1450:            cache->dbgCachedUndefined = 0;
                   1451: 
                   1452:            cache->dbgReusedAll = 0;
                   1453:            cache->dbgReusedNodeset = 0;
                   1454:            cache->dbgReusedString = 0;
                   1455:            cache->dbgReusedBool = 0;
                   1456:            cache->dbgReusedNumber = 0;
                   1457:            cache->dbgReusedPoint = 0;
                   1458:            cache->dbgReusedRange = 0;
                   1459:            cache->dbgReusedLocset = 0;
                   1460:            cache->dbgReusedUsers = 0;
                   1461:            cache->dbgReusedXSLTTree = 0;
                   1462:            cache->dbgReusedUndefined = 0;
                   1463:        }
                   1464:     }
                   1465: 
                   1466:     xmlXPathDebugObjCounterUndefined = 0;
                   1467:     xmlXPathDebugObjCounterNodeset = 0;
                   1468:     xmlXPathDebugObjCounterBool = 0;
                   1469:     xmlXPathDebugObjCounterNumber = 0;
                   1470:     xmlXPathDebugObjCounterString = 0;
                   1471:     xmlXPathDebugObjCounterPoint = 0;
                   1472:     xmlXPathDebugObjCounterRange = 0;
                   1473:     xmlXPathDebugObjCounterLocset = 0;
                   1474:     xmlXPathDebugObjCounterUsers = 0;
                   1475:     xmlXPathDebugObjCounterXSLTTree = 0;
                   1476:     xmlXPathDebugObjCounterAll = 0;
                   1477: 
                   1478:     xmlXPathDebugObjTotalUndefined = 0;
                   1479:     xmlXPathDebugObjTotalNodeset = 0;
                   1480:     xmlXPathDebugObjTotalBool = 0;
                   1481:     xmlXPathDebugObjTotalNumber = 0;
                   1482:     xmlXPathDebugObjTotalString = 0;
                   1483:     xmlXPathDebugObjTotalPoint = 0;
                   1484:     xmlXPathDebugObjTotalRange = 0;
                   1485:     xmlXPathDebugObjTotalLocset = 0;
                   1486:     xmlXPathDebugObjTotalUsers = 0;
                   1487:     xmlXPathDebugObjTotalXSLTTree = 0;
                   1488:     xmlXPathDebugObjTotalAll = 0;
                   1489: 
                   1490:     xmlXPathDebugObjMaxUndefined = 0;
                   1491:     xmlXPathDebugObjMaxNodeset = 0;
                   1492:     xmlXPathDebugObjMaxBool = 0;
                   1493:     xmlXPathDebugObjMaxNumber = 0;
                   1494:     xmlXPathDebugObjMaxString = 0;
                   1495:     xmlXPathDebugObjMaxPoint = 0;
                   1496:     xmlXPathDebugObjMaxRange = 0;
                   1497:     xmlXPathDebugObjMaxLocset = 0;
                   1498:     xmlXPathDebugObjMaxUsers = 0;
                   1499:     xmlXPathDebugObjMaxXSLTTree = 0;
                   1500:     xmlXPathDebugObjMaxAll = 0;
                   1501: 
                   1502: }
                   1503: 
                   1504: static void
                   1505: xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
                   1506:                              xmlXPathObjectType objType)
                   1507: {
                   1508:     int isCached = 0;
                   1509: 
                   1510:     if (ctxt != NULL) {
                   1511:        if (ctxt->cache != NULL) {
                   1512:            xmlXPathContextCachePtr cache =
                   1513:                (xmlXPathContextCachePtr) ctxt->cache;
                   1514: 
                   1515:            isCached = 1;
                   1516: 
                   1517:            cache->dbgReusedAll++;
                   1518:            switch (objType) {
                   1519:                case XPATH_UNDEFINED:
                   1520:                    cache->dbgReusedUndefined++;
                   1521:                    break;
                   1522:                case XPATH_NODESET:
                   1523:                    cache->dbgReusedNodeset++;
                   1524:                    break;
                   1525:                case XPATH_BOOLEAN:
                   1526:                    cache->dbgReusedBool++;
                   1527:                    break;
                   1528:                case XPATH_NUMBER:
                   1529:                    cache->dbgReusedNumber++;
                   1530:                    break;
                   1531:                case XPATH_STRING:
                   1532:                    cache->dbgReusedString++;
                   1533:                    break;
                   1534:                case XPATH_POINT:
                   1535:                    cache->dbgReusedPoint++;
                   1536:                    break;
                   1537:                case XPATH_RANGE:
                   1538:                    cache->dbgReusedRange++;
                   1539:                    break;
                   1540:                case XPATH_LOCATIONSET:
                   1541:                    cache->dbgReusedLocset++;
                   1542:                    break;
                   1543:                case XPATH_USERS:
                   1544:                    cache->dbgReusedUsers++;
                   1545:                    break;
                   1546:                case XPATH_XSLT_TREE:
                   1547:                    cache->dbgReusedXSLTTree++;
                   1548:                    break;
                   1549:                default:
                   1550:                    break;
                   1551:            }
                   1552:        }
                   1553:     }
                   1554: 
                   1555:     switch (objType) {
                   1556:        case XPATH_UNDEFINED:
                   1557:            if (! isCached)
                   1558:                xmlXPathDebugObjTotalUndefined++;
                   1559:            xmlXPathDebugObjCounterUndefined++;
                   1560:            if (xmlXPathDebugObjCounterUndefined >
                   1561:                xmlXPathDebugObjMaxUndefined)
                   1562:                xmlXPathDebugObjMaxUndefined =
                   1563:                    xmlXPathDebugObjCounterUndefined;
                   1564:            break;
                   1565:        case XPATH_NODESET:
                   1566:            if (! isCached)
                   1567:                xmlXPathDebugObjTotalNodeset++;
                   1568:            xmlXPathDebugObjCounterNodeset++;
                   1569:            if (xmlXPathDebugObjCounterNodeset >
                   1570:                xmlXPathDebugObjMaxNodeset)
                   1571:                xmlXPathDebugObjMaxNodeset =
                   1572:                    xmlXPathDebugObjCounterNodeset;
                   1573:            break;
                   1574:        case XPATH_BOOLEAN:
                   1575:            if (! isCached)
                   1576:                xmlXPathDebugObjTotalBool++;
                   1577:            xmlXPathDebugObjCounterBool++;
                   1578:            if (xmlXPathDebugObjCounterBool >
                   1579:                xmlXPathDebugObjMaxBool)
                   1580:                xmlXPathDebugObjMaxBool =
                   1581:                    xmlXPathDebugObjCounterBool;
                   1582:            break;
                   1583:        case XPATH_NUMBER:
                   1584:            if (! isCached)
                   1585:                xmlXPathDebugObjTotalNumber++;
                   1586:            xmlXPathDebugObjCounterNumber++;
                   1587:            if (xmlXPathDebugObjCounterNumber >
                   1588:                xmlXPathDebugObjMaxNumber)
                   1589:                xmlXPathDebugObjMaxNumber =
                   1590:                    xmlXPathDebugObjCounterNumber;
                   1591:            break;
                   1592:        case XPATH_STRING:
                   1593:            if (! isCached)
                   1594:                xmlXPathDebugObjTotalString++;
                   1595:            xmlXPathDebugObjCounterString++;
                   1596:            if (xmlXPathDebugObjCounterString >
                   1597:                xmlXPathDebugObjMaxString)
                   1598:                xmlXPathDebugObjMaxString =
                   1599:                    xmlXPathDebugObjCounterString;
                   1600:            break;
                   1601:        case XPATH_POINT:
                   1602:            if (! isCached)
                   1603:                xmlXPathDebugObjTotalPoint++;
                   1604:            xmlXPathDebugObjCounterPoint++;
                   1605:            if (xmlXPathDebugObjCounterPoint >
                   1606:                xmlXPathDebugObjMaxPoint)
                   1607:                xmlXPathDebugObjMaxPoint =
                   1608:                    xmlXPathDebugObjCounterPoint;
                   1609:            break;
                   1610:        case XPATH_RANGE:
                   1611:            if (! isCached)
                   1612:                xmlXPathDebugObjTotalRange++;
                   1613:            xmlXPathDebugObjCounterRange++;
                   1614:            if (xmlXPathDebugObjCounterRange >
                   1615:                xmlXPathDebugObjMaxRange)
                   1616:                xmlXPathDebugObjMaxRange =
                   1617:                    xmlXPathDebugObjCounterRange;
                   1618:            break;
                   1619:        case XPATH_LOCATIONSET:
                   1620:            if (! isCached)
                   1621:                xmlXPathDebugObjTotalLocset++;
                   1622:            xmlXPathDebugObjCounterLocset++;
                   1623:            if (xmlXPathDebugObjCounterLocset >
                   1624:                xmlXPathDebugObjMaxLocset)
                   1625:                xmlXPathDebugObjMaxLocset =
                   1626:                    xmlXPathDebugObjCounterLocset;
                   1627:            break;
                   1628:        case XPATH_USERS:
                   1629:            if (! isCached)
                   1630:                xmlXPathDebugObjTotalUsers++;
                   1631:            xmlXPathDebugObjCounterUsers++;
                   1632:            if (xmlXPathDebugObjCounterUsers >
                   1633:                xmlXPathDebugObjMaxUsers)
                   1634:                xmlXPathDebugObjMaxUsers =
                   1635:                    xmlXPathDebugObjCounterUsers;
                   1636:            break;
                   1637:        case XPATH_XSLT_TREE:
                   1638:            if (! isCached)
                   1639:                xmlXPathDebugObjTotalXSLTTree++;
                   1640:            xmlXPathDebugObjCounterXSLTTree++;
                   1641:            if (xmlXPathDebugObjCounterXSLTTree >
                   1642:                xmlXPathDebugObjMaxXSLTTree)
                   1643:                xmlXPathDebugObjMaxXSLTTree =
                   1644:                    xmlXPathDebugObjCounterXSLTTree;
                   1645:            break;
                   1646:        default:
                   1647:            break;
                   1648:     }
                   1649:     if (! isCached)
                   1650:        xmlXPathDebugObjTotalAll++;
                   1651:     xmlXPathDebugObjCounterAll++;
                   1652:     if (xmlXPathDebugObjCounterAll >
                   1653:        xmlXPathDebugObjMaxAll)
                   1654:        xmlXPathDebugObjMaxAll =
                   1655:            xmlXPathDebugObjCounterAll;
                   1656: }
                   1657: 
                   1658: static void
                   1659: xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
                   1660:                              xmlXPathObjectType objType)
                   1661: {
                   1662:     int isCached = 0;
                   1663: 
                   1664:     if (ctxt != NULL) {
                   1665:        if (ctxt->cache != NULL) {
                   1666:            xmlXPathContextCachePtr cache =
                   1667:                (xmlXPathContextCachePtr) ctxt->cache;
                   1668: 
                   1669:            isCached = 1;
                   1670: 
                   1671:            cache->dbgCachedAll++;
                   1672:            switch (objType) {
                   1673:                case XPATH_UNDEFINED:
                   1674:                    cache->dbgCachedUndefined++;
                   1675:                    break;
                   1676:                case XPATH_NODESET:
                   1677:                    cache->dbgCachedNodeset++;
                   1678:                    break;
                   1679:                case XPATH_BOOLEAN:
                   1680:                    cache->dbgCachedBool++;
                   1681:                    break;
                   1682:                case XPATH_NUMBER:
                   1683:                    cache->dbgCachedNumber++;
                   1684:                    break;
                   1685:                case XPATH_STRING:
                   1686:                    cache->dbgCachedString++;
                   1687:                    break;
                   1688:                case XPATH_POINT:
                   1689:                    cache->dbgCachedPoint++;
                   1690:                    break;
                   1691:                case XPATH_RANGE:
                   1692:                    cache->dbgCachedRange++;
                   1693:                    break;
                   1694:                case XPATH_LOCATIONSET:
                   1695:                    cache->dbgCachedLocset++;
                   1696:                    break;
                   1697:                case XPATH_USERS:
                   1698:                    cache->dbgCachedUsers++;
                   1699:                    break;
                   1700:                case XPATH_XSLT_TREE:
                   1701:                    cache->dbgCachedXSLTTree++;
                   1702:                    break;
                   1703:                default:
                   1704:                    break;
                   1705:            }
                   1706: 
                   1707:        }
                   1708:     }
                   1709:     switch (objType) {
                   1710:        case XPATH_UNDEFINED:
                   1711:            xmlXPathDebugObjCounterUndefined--;
                   1712:            break;
                   1713:        case XPATH_NODESET:
                   1714:            xmlXPathDebugObjCounterNodeset--;
                   1715:            break;
                   1716:        case XPATH_BOOLEAN:
                   1717:            xmlXPathDebugObjCounterBool--;
                   1718:            break;
                   1719:        case XPATH_NUMBER:
                   1720:            xmlXPathDebugObjCounterNumber--;
                   1721:            break;
                   1722:        case XPATH_STRING:
                   1723:            xmlXPathDebugObjCounterString--;
                   1724:            break;
                   1725:        case XPATH_POINT:
                   1726:            xmlXPathDebugObjCounterPoint--;
                   1727:            break;
                   1728:        case XPATH_RANGE:
                   1729:            xmlXPathDebugObjCounterRange--;
                   1730:            break;
                   1731:        case XPATH_LOCATIONSET:
                   1732:            xmlXPathDebugObjCounterLocset--;
                   1733:            break;
                   1734:        case XPATH_USERS:
                   1735:            xmlXPathDebugObjCounterUsers--;
                   1736:            break;
                   1737:        case XPATH_XSLT_TREE:
                   1738:            xmlXPathDebugObjCounterXSLTTree--;
                   1739:            break;
                   1740:        default:
                   1741:            break;
                   1742:     }
                   1743:     xmlXPathDebugObjCounterAll--;
                   1744: }
                   1745: 
                   1746: /* REVISIT TODO: Make this static when committing */
                   1747: static void
                   1748: xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
                   1749: {
                   1750:     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
                   1751:        reqXSLTTree, reqUndefined;
                   1752:     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
                   1753:        caNumber = 0, caXSLTTree = 0, caUndefined = 0;
                   1754:     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
                   1755:        reNumber = 0, reXSLTTree = 0, reUndefined = 0;
                   1756:     int leftObjs = xmlXPathDebugObjCounterAll;
                   1757: 
                   1758:     reqAll = xmlXPathDebugObjTotalAll;
                   1759:     reqNodeset = xmlXPathDebugObjTotalNodeset;
                   1760:     reqString = xmlXPathDebugObjTotalString;
                   1761:     reqBool = xmlXPathDebugObjTotalBool;
                   1762:     reqNumber = xmlXPathDebugObjTotalNumber;
                   1763:     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
                   1764:     reqUndefined = xmlXPathDebugObjTotalUndefined;
                   1765: 
                   1766:     printf("# XPath object usage:\n");
                   1767: 
                   1768:     if (ctxt != NULL) {
                   1769:        if (ctxt->cache != NULL) {
                   1770:            xmlXPathContextCachePtr cache =
                   1771:                (xmlXPathContextCachePtr) ctxt->cache;
                   1772: 
                   1773:            reAll = cache->dbgReusedAll;
                   1774:            reqAll += reAll;
                   1775:            reNodeset = cache->dbgReusedNodeset;
                   1776:            reqNodeset += reNodeset;
                   1777:            reString = cache->dbgReusedString;
                   1778:            reqString += reString;
                   1779:            reBool = cache->dbgReusedBool;
                   1780:            reqBool += reBool;
                   1781:            reNumber = cache->dbgReusedNumber;
                   1782:            reqNumber += reNumber;
                   1783:            reXSLTTree = cache->dbgReusedXSLTTree;
                   1784:            reqXSLTTree += reXSLTTree;
                   1785:            reUndefined = cache->dbgReusedUndefined;
                   1786:            reqUndefined += reUndefined;
                   1787: 
                   1788:            caAll = cache->dbgCachedAll;
                   1789:            caBool = cache->dbgCachedBool;
                   1790:            caNodeset = cache->dbgCachedNodeset;
                   1791:            caString = cache->dbgCachedString;
                   1792:            caNumber = cache->dbgCachedNumber;
                   1793:            caXSLTTree = cache->dbgCachedXSLTTree;
                   1794:            caUndefined = cache->dbgCachedUndefined;
                   1795: 
                   1796:            if (cache->nodesetObjs)
                   1797:                leftObjs -= cache->nodesetObjs->number;
                   1798:            if (cache->stringObjs)
                   1799:                leftObjs -= cache->stringObjs->number;
                   1800:            if (cache->booleanObjs)
                   1801:                leftObjs -= cache->booleanObjs->number;
                   1802:            if (cache->numberObjs)
                   1803:                leftObjs -= cache->numberObjs->number;
                   1804:            if (cache->miscObjs)
                   1805:                leftObjs -= cache->miscObjs->number;
                   1806:        }
                   1807:     }
                   1808: 
                   1809:     printf("# all\n");
                   1810:     printf("#   total  : %d\n", reqAll);
                   1811:     printf("#   left  : %d\n", leftObjs);
                   1812:     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
                   1813:     printf("#   reused : %d\n", reAll);
                   1814:     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
                   1815: 
                   1816:     printf("# node-sets\n");
                   1817:     printf("#   total  : %d\n", reqNodeset);
                   1818:     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
                   1819:     printf("#   reused : %d\n", reNodeset);
                   1820:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
                   1821: 
                   1822:     printf("# strings\n");
                   1823:     printf("#   total  : %d\n", reqString);
                   1824:     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
                   1825:     printf("#   reused : %d\n", reString);
                   1826:     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
                   1827: 
                   1828:     printf("# booleans\n");
                   1829:     printf("#   total  : %d\n", reqBool);
                   1830:     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
                   1831:     printf("#   reused : %d\n", reBool);
                   1832:     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
                   1833: 
                   1834:     printf("# numbers\n");
                   1835:     printf("#   total  : %d\n", reqNumber);
                   1836:     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
                   1837:     printf("#   reused : %d\n", reNumber);
                   1838:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
                   1839: 
                   1840:     printf("# XSLT result tree fragments\n");
                   1841:     printf("#   total  : %d\n", reqXSLTTree);
                   1842:     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
                   1843:     printf("#   reused : %d\n", reXSLTTree);
                   1844:     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
                   1845: 
                   1846:     printf("# undefined\n");
                   1847:     printf("#   total  : %d\n", reqUndefined);
                   1848:     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
                   1849:     printf("#   reused : %d\n", reUndefined);
                   1850:     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
                   1851: 
                   1852: }
                   1853: 
                   1854: #endif /* XP_DEBUG_OBJ_USAGE */
                   1855: 
                   1856: #endif /* LIBXML_DEBUG_ENABLED */
                   1857: 
                   1858: /************************************************************************
                   1859:  *                                                                     *
                   1860:  *                     XPath object caching                            *
                   1861:  *                                                                     *
                   1862:  ************************************************************************/
                   1863: 
                   1864: /**
                   1865:  * xmlXPathNewCache:
                   1866:  *
                   1867:  * Create a new object cache
                   1868:  *
                   1869:  * Returns the xmlXPathCache just allocated.
                   1870:  */
                   1871: static xmlXPathContextCachePtr
                   1872: xmlXPathNewCache(void)
                   1873: {
                   1874:     xmlXPathContextCachePtr ret;
                   1875: 
                   1876:     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
                   1877:     if (ret == NULL) {
                   1878:         xmlXPathErrMemory(NULL, "creating object cache\n");
                   1879:        return(NULL);
                   1880:     }
                   1881:     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
                   1882:     ret->maxNodeset = 100;
                   1883:     ret->maxString = 100;
                   1884:     ret->maxBoolean = 100;
                   1885:     ret->maxNumber = 100;
                   1886:     ret->maxMisc = 100;
                   1887:     return(ret);
                   1888: }
                   1889: 
                   1890: static void
                   1891: xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
                   1892: {
                   1893:     int i;
                   1894:     xmlXPathObjectPtr obj;
                   1895: 
                   1896:     if (list == NULL)
                   1897:        return;
                   1898: 
                   1899:     for (i = 0; i < list->number; i++) {
                   1900:        obj = list->items[i];
                   1901:        /*
                   1902:        * Note that it is already assured that we don't need to
                   1903:        * look out for namespace nodes in the node-set.
                   1904:        */
                   1905:        if (obj->nodesetval != NULL) {
                   1906:            if (obj->nodesetval->nodeTab != NULL)
                   1907:                xmlFree(obj->nodesetval->nodeTab);
                   1908:            xmlFree(obj->nodesetval);
                   1909:        }
                   1910:        xmlFree(obj);
                   1911: #ifdef XP_DEBUG_OBJ_USAGE
                   1912:        xmlXPathDebugObjCounterAll--;
                   1913: #endif
                   1914:     }
                   1915:     xmlPointerListFree(list);
                   1916: }
                   1917: 
                   1918: static void
                   1919: xmlXPathFreeCache(xmlXPathContextCachePtr cache)
                   1920: {
                   1921:     if (cache == NULL)
                   1922:        return;
                   1923:     if (cache->nodesetObjs)
                   1924:        xmlXPathCacheFreeObjectList(cache->nodesetObjs);
                   1925:     if (cache->stringObjs)
                   1926:        xmlXPathCacheFreeObjectList(cache->stringObjs);
                   1927:     if (cache->booleanObjs)
                   1928:        xmlXPathCacheFreeObjectList(cache->booleanObjs);
                   1929:     if (cache->numberObjs)
                   1930:        xmlXPathCacheFreeObjectList(cache->numberObjs);
                   1931:     if (cache->miscObjs)
                   1932:        xmlXPathCacheFreeObjectList(cache->miscObjs);
                   1933:     xmlFree(cache);
                   1934: }
                   1935: 
                   1936: /**
                   1937:  * xmlXPathContextSetCache:
                   1938:  *
                   1939:  * @ctxt:  the XPath context
                   1940:  * @active: enables/disables (creates/frees) the cache
                   1941:  * @value: a value with semantics dependant on @options
                   1942:  * @options: options (currently only the value 0 is used)
                   1943:  *
                   1944:  * Creates/frees an object cache on the XPath context.
                   1945:  * If activates XPath objects (xmlXPathObject) will be cached internally
                   1946:  * to be reused.
                   1947:  * @options:
                   1948:  *   0: This will set the XPath object caching:
                   1949:  *      @value:
                   1950:  *        This will set the maximum number of XPath objects
                   1951:  *        to be cached per slot
                   1952:  *        There are 5 slots for: node-set, string, number, boolean, and
                   1953:  *        misc objects. Use <0 for the default number (100).
                   1954:  *   Other values for @options have currently no effect.
                   1955:  *
                   1956:  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
                   1957:  */
                   1958: int
                   1959: xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
                   1960:                        int active,
                   1961:                        int value,
                   1962:                        int options)
                   1963: {
                   1964:     if (ctxt == NULL)
                   1965:        return(-1);
                   1966:     if (active) {
                   1967:        xmlXPathContextCachePtr cache;
                   1968: 
                   1969:        if (ctxt->cache == NULL) {
                   1970:            ctxt->cache = xmlXPathNewCache();
                   1971:            if (ctxt->cache == NULL)
                   1972:                return(-1);
                   1973:        }
                   1974:        cache = (xmlXPathContextCachePtr) ctxt->cache;
                   1975:        if (options == 0) {
                   1976:            if (value < 0)
                   1977:                value = 100;
                   1978:            cache->maxNodeset = value;
                   1979:            cache->maxString = value;
                   1980:            cache->maxNumber = value;
                   1981:            cache->maxBoolean = value;
                   1982:            cache->maxMisc = value;
                   1983:        }
                   1984:     } else if (ctxt->cache != NULL) {
                   1985:        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
                   1986:        ctxt->cache = NULL;
                   1987:     }
                   1988:     return(0);
                   1989: }
                   1990: 
                   1991: /**
                   1992:  * xmlXPathCacheWrapNodeSet:
                   1993:  * @ctxt: the XPath context
                   1994:  * @val:  the NodePtr value
                   1995:  *
                   1996:  * This is the cached version of xmlXPathWrapNodeSet().
                   1997:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
                   1998:  *
                   1999:  * Returns the created or reused object.
                   2000:  */
                   2001: static xmlXPathObjectPtr
                   2002: xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
                   2003: {
                   2004:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
                   2005:        xmlXPathContextCachePtr cache =
                   2006:            (xmlXPathContextCachePtr) ctxt->cache;
                   2007: 
                   2008:        if ((cache->miscObjs != NULL) &&
                   2009:            (cache->miscObjs->number != 0))
                   2010:        {
                   2011:            xmlXPathObjectPtr ret;
                   2012: 
                   2013:            ret = (xmlXPathObjectPtr)
                   2014:                cache->miscObjs->items[--cache->miscObjs->number];
                   2015:            ret->type = XPATH_NODESET;
                   2016:            ret->nodesetval = val;
                   2017: #ifdef XP_DEBUG_OBJ_USAGE
                   2018:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
                   2019: #endif
                   2020:            return(ret);
                   2021:        }
                   2022:     }
                   2023: 
                   2024:     return(xmlXPathWrapNodeSet(val));
                   2025: 
                   2026: }
                   2027: 
                   2028: /**
                   2029:  * xmlXPathCacheWrapString:
                   2030:  * @ctxt: the XPath context
                   2031:  * @val:  the xmlChar * value
                   2032:  *
                   2033:  * This is the cached version of xmlXPathWrapString().
                   2034:  * Wraps the @val string into an XPath object.
                   2035:  *
                   2036:  * Returns the created or reused object.
                   2037:  */
                   2038: static xmlXPathObjectPtr
                   2039: xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
                   2040: {
                   2041:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
                   2042:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2043: 
                   2044:        if ((cache->stringObjs != NULL) &&
                   2045:            (cache->stringObjs->number != 0))
                   2046:        {
                   2047: 
                   2048:            xmlXPathObjectPtr ret;
                   2049: 
                   2050:            ret = (xmlXPathObjectPtr)
                   2051:                cache->stringObjs->items[--cache->stringObjs->number];
                   2052:            ret->type = XPATH_STRING;
                   2053:            ret->stringval = val;
                   2054: #ifdef XP_DEBUG_OBJ_USAGE
                   2055:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2056: #endif
                   2057:            return(ret);
                   2058:        } else if ((cache->miscObjs != NULL) &&
                   2059:            (cache->miscObjs->number != 0))
                   2060:        {
                   2061:            xmlXPathObjectPtr ret;
                   2062:            /*
                   2063:            * Fallback to misc-cache.
                   2064:            */
                   2065:            ret = (xmlXPathObjectPtr)
                   2066:                cache->miscObjs->items[--cache->miscObjs->number];
                   2067: 
                   2068:            ret->type = XPATH_STRING;
                   2069:            ret->stringval = val;
                   2070: #ifdef XP_DEBUG_OBJ_USAGE
                   2071:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2072: #endif
                   2073:            return(ret);
                   2074:        }
                   2075:     }
                   2076:     return(xmlXPathWrapString(val));
                   2077: }
                   2078: 
                   2079: /**
                   2080:  * xmlXPathCacheNewNodeSet:
                   2081:  * @ctxt: the XPath context
                   2082:  * @val:  the NodePtr value
                   2083:  *
                   2084:  * This is the cached version of xmlXPathNewNodeSet().
                   2085:  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
                   2086:  * it with the single Node @val
                   2087:  *
                   2088:  * Returns the created or reused object.
                   2089:  */
                   2090: static xmlXPathObjectPtr
                   2091: xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
                   2092: {
                   2093:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2094:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2095: 
                   2096:        if ((cache->nodesetObjs != NULL) &&
                   2097:            (cache->nodesetObjs->number != 0))
                   2098:        {
                   2099:            xmlXPathObjectPtr ret;
                   2100:            /*
                   2101:            * Use the nodset-cache.
                   2102:            */
                   2103:            ret = (xmlXPathObjectPtr)
                   2104:                cache->nodesetObjs->items[--cache->nodesetObjs->number];
                   2105:            ret->type = XPATH_NODESET;
                   2106:            ret->boolval = 0;
                   2107:            if (val) {
                   2108:                if ((ret->nodesetval->nodeMax == 0) ||
                   2109:                    (val->type == XML_NAMESPACE_DECL))
                   2110:                {
                   2111:                    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
                   2112:                } else {
                   2113:                    ret->nodesetval->nodeTab[0] = val;
                   2114:                    ret->nodesetval->nodeNr = 1;
                   2115:                }
                   2116:            }
                   2117: #ifdef XP_DEBUG_OBJ_USAGE
                   2118:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
                   2119: #endif
                   2120:            return(ret);
                   2121:        } else if ((cache->miscObjs != NULL) &&
                   2122:            (cache->miscObjs->number != 0))
                   2123:        {
                   2124:            xmlXPathObjectPtr ret;
                   2125:            /*
                   2126:            * Fallback to misc-cache.
                   2127:            */
                   2128: 
                   2129:            ret = (xmlXPathObjectPtr)
                   2130:                cache->miscObjs->items[--cache->miscObjs->number];
                   2131: 
                   2132:            ret->type = XPATH_NODESET;
                   2133:            ret->boolval = 0;
                   2134:            ret->nodesetval = xmlXPathNodeSetCreate(val);
1.1.1.3 ! misho    2135:            if (ret->nodesetval == NULL) {
        !          2136:                ctxt->lastError.domain = XML_FROM_XPATH;
        !          2137:                ctxt->lastError.code = XML_ERR_NO_MEMORY;
        !          2138:                return(NULL);
        !          2139:            }
1.1       misho    2140: #ifdef XP_DEBUG_OBJ_USAGE
                   2141:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
                   2142: #endif
                   2143:            return(ret);
                   2144:        }
                   2145:     }
                   2146:     return(xmlXPathNewNodeSet(val));
                   2147: }
                   2148: 
                   2149: /**
                   2150:  * xmlXPathCacheNewCString:
                   2151:  * @ctxt: the XPath context
                   2152:  * @val:  the char * value
                   2153:  *
                   2154:  * This is the cached version of xmlXPathNewCString().
                   2155:  * Acquire an xmlXPathObjectPtr of type string and of value @val
                   2156:  *
                   2157:  * Returns the created or reused object.
                   2158:  */
                   2159: static xmlXPathObjectPtr
                   2160: xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
                   2161: {
                   2162:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2163:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2164: 
                   2165:        if ((cache->stringObjs != NULL) &&
                   2166:            (cache->stringObjs->number != 0))
                   2167:        {
                   2168:            xmlXPathObjectPtr ret;
                   2169: 
                   2170:            ret = (xmlXPathObjectPtr)
                   2171:                cache->stringObjs->items[--cache->stringObjs->number];
                   2172: 
                   2173:            ret->type = XPATH_STRING;
                   2174:            ret->stringval = xmlStrdup(BAD_CAST val);
                   2175: #ifdef XP_DEBUG_OBJ_USAGE
                   2176:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2177: #endif
                   2178:            return(ret);
                   2179:        } else if ((cache->miscObjs != NULL) &&
                   2180:            (cache->miscObjs->number != 0))
                   2181:        {
                   2182:            xmlXPathObjectPtr ret;
                   2183: 
                   2184:            ret = (xmlXPathObjectPtr)
                   2185:                cache->miscObjs->items[--cache->miscObjs->number];
                   2186: 
                   2187:            ret->type = XPATH_STRING;
                   2188:            ret->stringval = xmlStrdup(BAD_CAST val);
                   2189: #ifdef XP_DEBUG_OBJ_USAGE
                   2190:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2191: #endif
                   2192:            return(ret);
                   2193:        }
                   2194:     }
                   2195:     return(xmlXPathNewCString(val));
                   2196: }
                   2197: 
                   2198: /**
                   2199:  * xmlXPathCacheNewString:
                   2200:  * @ctxt: the XPath context
                   2201:  * @val:  the xmlChar * value
                   2202:  *
                   2203:  * This is the cached version of xmlXPathNewString().
                   2204:  * Acquire an xmlXPathObjectPtr of type string and of value @val
                   2205:  *
                   2206:  * Returns the created or reused object.
                   2207:  */
                   2208: static xmlXPathObjectPtr
                   2209: xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
                   2210: {
                   2211:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2212:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2213: 
                   2214:        if ((cache->stringObjs != NULL) &&
                   2215:            (cache->stringObjs->number != 0))
                   2216:        {
                   2217:            xmlXPathObjectPtr ret;
                   2218: 
                   2219:            ret = (xmlXPathObjectPtr)
                   2220:                cache->stringObjs->items[--cache->stringObjs->number];
                   2221:            ret->type = XPATH_STRING;
                   2222:            if (val != NULL)
                   2223:                ret->stringval = xmlStrdup(val);
                   2224:            else
                   2225:                ret->stringval = xmlStrdup((const xmlChar *)"");
                   2226: #ifdef XP_DEBUG_OBJ_USAGE
                   2227:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2228: #endif
                   2229:            return(ret);
                   2230:        } else if ((cache->miscObjs != NULL) &&
                   2231:            (cache->miscObjs->number != 0))
                   2232:        {
                   2233:            xmlXPathObjectPtr ret;
                   2234: 
                   2235:            ret = (xmlXPathObjectPtr)
                   2236:                cache->miscObjs->items[--cache->miscObjs->number];
                   2237: 
                   2238:            ret->type = XPATH_STRING;
                   2239:            if (val != NULL)
                   2240:                ret->stringval = xmlStrdup(val);
                   2241:            else
                   2242:                ret->stringval = xmlStrdup((const xmlChar *)"");
                   2243: #ifdef XP_DEBUG_OBJ_USAGE
                   2244:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
                   2245: #endif
                   2246:            return(ret);
                   2247:        }
                   2248:     }
                   2249:     return(xmlXPathNewString(val));
                   2250: }
                   2251: 
                   2252: /**
                   2253:  * xmlXPathCacheNewBoolean:
                   2254:  * @ctxt: the XPath context
                   2255:  * @val:  the boolean value
                   2256:  *
                   2257:  * This is the cached version of xmlXPathNewBoolean().
                   2258:  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
                   2259:  *
                   2260:  * Returns the created or reused object.
                   2261:  */
                   2262: static xmlXPathObjectPtr
                   2263: xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
                   2264: {
                   2265:     if ((ctxt != NULL) && (ctxt->cache)) {
                   2266:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2267: 
                   2268:        if ((cache->booleanObjs != NULL) &&
                   2269:            (cache->booleanObjs->number != 0))
                   2270:        {
                   2271:            xmlXPathObjectPtr ret;
                   2272: 
                   2273:            ret = (xmlXPathObjectPtr)
                   2274:                cache->booleanObjs->items[--cache->booleanObjs->number];
                   2275:            ret->type = XPATH_BOOLEAN;
                   2276:            ret->boolval = (val != 0);
                   2277: #ifdef XP_DEBUG_OBJ_USAGE
                   2278:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
                   2279: #endif
                   2280:            return(ret);
                   2281:        } else if ((cache->miscObjs != NULL) &&
                   2282:            (cache->miscObjs->number != 0))
                   2283:        {
                   2284:            xmlXPathObjectPtr ret;
                   2285: 
                   2286:            ret = (xmlXPathObjectPtr)
                   2287:                cache->miscObjs->items[--cache->miscObjs->number];
                   2288: 
                   2289:            ret->type = XPATH_BOOLEAN;
                   2290:            ret->boolval = (val != 0);
                   2291: #ifdef XP_DEBUG_OBJ_USAGE
                   2292:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
                   2293: #endif
                   2294:            return(ret);
                   2295:        }
                   2296:     }
                   2297:     return(xmlXPathNewBoolean(val));
                   2298: }
                   2299: 
                   2300: /**
                   2301:  * xmlXPathCacheNewFloat:
                   2302:  * @ctxt: the XPath context
                   2303:  * @val:  the double value
                   2304:  *
                   2305:  * This is the cached version of xmlXPathNewFloat().
                   2306:  * Acquires an xmlXPathObjectPtr of type double and of value @val
                   2307:  *
                   2308:  * Returns the created or reused object.
                   2309:  */
                   2310: static xmlXPathObjectPtr
                   2311: xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
                   2312: {
                   2313:      if ((ctxt != NULL) && (ctxt->cache)) {
                   2314:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
                   2315: 
                   2316:        if ((cache->numberObjs != NULL) &&
                   2317:            (cache->numberObjs->number != 0))
                   2318:        {
                   2319:            xmlXPathObjectPtr ret;
                   2320: 
                   2321:            ret = (xmlXPathObjectPtr)
                   2322:                cache->numberObjs->items[--cache->numberObjs->number];
                   2323:            ret->type = XPATH_NUMBER;
                   2324:            ret->floatval = val;
                   2325: #ifdef XP_DEBUG_OBJ_USAGE
                   2326:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
                   2327: #endif
                   2328:            return(ret);
                   2329:        } else if ((cache->miscObjs != NULL) &&
                   2330:            (cache->miscObjs->number != 0))
                   2331:        {
                   2332:            xmlXPathObjectPtr ret;
                   2333: 
                   2334:            ret = (xmlXPathObjectPtr)
                   2335:                cache->miscObjs->items[--cache->miscObjs->number];
                   2336: 
                   2337:            ret->type = XPATH_NUMBER;
                   2338:            ret->floatval = val;
                   2339: #ifdef XP_DEBUG_OBJ_USAGE
                   2340:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
                   2341: #endif
                   2342:            return(ret);
                   2343:        }
                   2344:     }
                   2345:     return(xmlXPathNewFloat(val));
                   2346: }
                   2347: 
                   2348: /**
                   2349:  * xmlXPathCacheConvertString:
                   2350:  * @ctxt: the XPath context
                   2351:  * @val:  an XPath object
                   2352:  *
                   2353:  * This is the cached version of xmlXPathConvertString().
                   2354:  * Converts an existing object to its string() equivalent
                   2355:  *
                   2356:  * Returns a created or reused object, the old one is freed (cached)
                   2357:  *         (or the operation is done directly on @val)
                   2358:  */
                   2359: 
                   2360: static xmlXPathObjectPtr
                   2361: xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
                   2362:     xmlChar *res = NULL;
                   2363: 
                   2364:     if (val == NULL)
                   2365:        return(xmlXPathCacheNewCString(ctxt, ""));
                   2366: 
                   2367:     switch (val->type) {
                   2368:     case XPATH_UNDEFINED:
                   2369: #ifdef DEBUG_EXPR
                   2370:        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
                   2371: #endif
                   2372:        break;
                   2373:     case XPATH_NODESET:
                   2374:     case XPATH_XSLT_TREE:
                   2375:        res = xmlXPathCastNodeSetToString(val->nodesetval);
                   2376:        break;
                   2377:     case XPATH_STRING:
                   2378:        return(val);
                   2379:     case XPATH_BOOLEAN:
                   2380:        res = xmlXPathCastBooleanToString(val->boolval);
                   2381:        break;
                   2382:     case XPATH_NUMBER:
                   2383:        res = xmlXPathCastNumberToString(val->floatval);
                   2384:        break;
                   2385:     case XPATH_USERS:
                   2386:     case XPATH_POINT:
                   2387:     case XPATH_RANGE:
                   2388:     case XPATH_LOCATIONSET:
                   2389:        TODO;
                   2390:        break;
                   2391:     }
                   2392:     xmlXPathReleaseObject(ctxt, val);
                   2393:     if (res == NULL)
                   2394:        return(xmlXPathCacheNewCString(ctxt, ""));
                   2395:     return(xmlXPathCacheWrapString(ctxt, res));
                   2396: }
                   2397: 
                   2398: /**
                   2399:  * xmlXPathCacheObjectCopy:
                   2400:  * @ctxt: the XPath context
                   2401:  * @val:  the original object
                   2402:  *
                   2403:  * This is the cached version of xmlXPathObjectCopy().
                   2404:  * Acquire a copy of a given object
                   2405:  *
                   2406:  * Returns a created or reused created object.
                   2407:  */
                   2408: static xmlXPathObjectPtr
                   2409: xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
                   2410: {
                   2411:     if (val == NULL)
                   2412:        return(NULL);
                   2413: 
                   2414:     if (XP_HAS_CACHE(ctxt)) {
                   2415:        switch (val->type) {
                   2416:            case XPATH_NODESET:
                   2417:                return(xmlXPathCacheWrapNodeSet(ctxt,
                   2418:                    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
                   2419:            case XPATH_STRING:
                   2420:                return(xmlXPathCacheNewString(ctxt, val->stringval));
                   2421:            case XPATH_BOOLEAN:
                   2422:                return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
                   2423:            case XPATH_NUMBER:
                   2424:                return(xmlXPathCacheNewFloat(ctxt, val->floatval));
                   2425:            default:
                   2426:                break;
                   2427:        }
                   2428:     }
                   2429:     return(xmlXPathObjectCopy(val));
                   2430: }
                   2431: 
                   2432: /**
                   2433:  * xmlXPathCacheConvertBoolean:
                   2434:  * @ctxt: the XPath context
                   2435:  * @val:  an XPath object
                   2436:  *
                   2437:  * This is the cached version of xmlXPathConvertBoolean().
                   2438:  * Converts an existing object to its boolean() equivalent
                   2439:  *
                   2440:  * Returns a created or reused object, the old one is freed (or the operation
                   2441:  *         is done directly on @val)
                   2442:  */
                   2443: static xmlXPathObjectPtr
                   2444: xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
                   2445:     xmlXPathObjectPtr ret;
                   2446: 
                   2447:     if (val == NULL)
                   2448:        return(xmlXPathCacheNewBoolean(ctxt, 0));
                   2449:     if (val->type == XPATH_BOOLEAN)
                   2450:        return(val);
                   2451:     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
                   2452:     xmlXPathReleaseObject(ctxt, val);
                   2453:     return(ret);
                   2454: }
                   2455: 
                   2456: /**
                   2457:  * xmlXPathCacheConvertNumber:
                   2458:  * @ctxt: the XPath context
                   2459:  * @val:  an XPath object
                   2460:  *
                   2461:  * This is the cached version of xmlXPathConvertNumber().
                   2462:  * Converts an existing object to its number() equivalent
                   2463:  *
                   2464:  * Returns a created or reused object, the old one is freed (or the operation
                   2465:  *         is done directly on @val)
                   2466:  */
                   2467: static xmlXPathObjectPtr
                   2468: xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
                   2469:     xmlXPathObjectPtr ret;
                   2470: 
                   2471:     if (val == NULL)
                   2472:        return(xmlXPathCacheNewFloat(ctxt, 0.0));
                   2473:     if (val->type == XPATH_NUMBER)
                   2474:        return(val);
                   2475:     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
                   2476:     xmlXPathReleaseObject(ctxt, val);
                   2477:     return(ret);
                   2478: }
                   2479: 
                   2480: /************************************************************************
                   2481:  *                                                                     *
                   2482:  *             Parser stacks related functions and macros              *
                   2483:  *                                                                     *
                   2484:  ************************************************************************/
                   2485: 
                   2486: /**
1.1.1.2   misho    2487:  * xmlXPathSetFrame:
                   2488:  * @ctxt: an XPath parser context
                   2489:  *
                   2490:  * Set the callee evaluation frame
                   2491:  *
                   2492:  * Returns the previous frame value to be restored once done
                   2493:  */
                   2494: static int
                   2495: xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
                   2496:     int ret;
                   2497: 
                   2498:     if (ctxt == NULL)
                   2499:         return(0);
                   2500:     ret = ctxt->valueFrame;
                   2501:     ctxt->valueFrame = ctxt->valueNr;
                   2502:     return(ret);
                   2503: }
                   2504: 
                   2505: /**
                   2506:  * xmlXPathPopFrame:
                   2507:  * @ctxt: an XPath parser context
                   2508:  * @frame: the previous frame value
                   2509:  *
                   2510:  * Remove the callee evaluation frame
                   2511:  */
                   2512: static void
                   2513: xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
                   2514:     if (ctxt == NULL)
                   2515:         return;
                   2516:     if (ctxt->valueNr < ctxt->valueFrame) {
                   2517:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
                   2518:     }
                   2519:     ctxt->valueFrame = frame;
                   2520: }
                   2521: 
                   2522: /**
1.1       misho    2523:  * valuePop:
                   2524:  * @ctxt: an XPath evaluation context
                   2525:  *
                   2526:  * Pops the top XPath object from the value stack
                   2527:  *
                   2528:  * Returns the XPath object just removed
                   2529:  */
                   2530: xmlXPathObjectPtr
                   2531: valuePop(xmlXPathParserContextPtr ctxt)
                   2532: {
                   2533:     xmlXPathObjectPtr ret;
                   2534: 
                   2535:     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
                   2536:         return (NULL);
1.1.1.2   misho    2537: 
                   2538:     if (ctxt->valueNr <= ctxt->valueFrame) {
                   2539:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
                   2540:         return (NULL);
                   2541:     }
                   2542: 
1.1       misho    2543:     ctxt->valueNr--;
                   2544:     if (ctxt->valueNr > 0)
                   2545:         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
                   2546:     else
                   2547:         ctxt->value = NULL;
                   2548:     ret = ctxt->valueTab[ctxt->valueNr];
                   2549:     ctxt->valueTab[ctxt->valueNr] = NULL;
                   2550:     return (ret);
                   2551: }
                   2552: /**
                   2553:  * valuePush:
                   2554:  * @ctxt:  an XPath evaluation context
                   2555:  * @value:  the XPath object
                   2556:  *
                   2557:  * Pushes a new XPath object on top of the value stack
                   2558:  *
                   2559:  * returns the number of items on the value stack
                   2560:  */
                   2561: int
                   2562: valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
                   2563: {
                   2564:     if ((ctxt == NULL) || (value == NULL)) return(-1);
                   2565:     if (ctxt->valueNr >= ctxt->valueMax) {
                   2566:         xmlXPathObjectPtr *tmp;
                   2567: 
1.1.1.3 ! misho    2568:         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
        !          2569:             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
        !          2570:             ctxt->error = XPATH_MEMORY_ERROR;
        !          2571:             return (0);
        !          2572:         }
1.1       misho    2573:         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
                   2574:                                              2 * ctxt->valueMax *
                   2575:                                              sizeof(ctxt->valueTab[0]));
                   2576:         if (tmp == NULL) {
1.1.1.3 ! misho    2577:             xmlXPathErrMemory(NULL, "pushing value\n");
1.1.1.2   misho    2578:             ctxt->error = XPATH_MEMORY_ERROR;
1.1       misho    2579:             return (0);
                   2580:         }
                   2581:         ctxt->valueMax *= 2;
                   2582:        ctxt->valueTab = tmp;
                   2583:     }
                   2584:     ctxt->valueTab[ctxt->valueNr] = value;
                   2585:     ctxt->value = value;
                   2586:     return (ctxt->valueNr++);
                   2587: }
                   2588: 
                   2589: /**
                   2590:  * xmlXPathPopBoolean:
                   2591:  * @ctxt:  an XPath parser context
                   2592:  *
                   2593:  * Pops a boolean from the stack, handling conversion if needed.
                   2594:  * Check error with #xmlXPathCheckError.
                   2595:  *
                   2596:  * Returns the boolean
                   2597:  */
                   2598: int
                   2599: xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
                   2600:     xmlXPathObjectPtr obj;
                   2601:     int ret;
                   2602: 
                   2603:     obj = valuePop(ctxt);
                   2604:     if (obj == NULL) {
                   2605:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2606:        return(0);
                   2607:     }
                   2608:     if (obj->type != XPATH_BOOLEAN)
                   2609:        ret = xmlXPathCastToBoolean(obj);
                   2610:     else
                   2611:         ret = obj->boolval;
                   2612:     xmlXPathReleaseObject(ctxt->context, obj);
                   2613:     return(ret);
                   2614: }
                   2615: 
                   2616: /**
                   2617:  * xmlXPathPopNumber:
                   2618:  * @ctxt:  an XPath parser context
                   2619:  *
                   2620:  * Pops a number from the stack, handling conversion if needed.
                   2621:  * Check error with #xmlXPathCheckError.
                   2622:  *
                   2623:  * Returns the number
                   2624:  */
                   2625: double
                   2626: xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
                   2627:     xmlXPathObjectPtr obj;
                   2628:     double ret;
                   2629: 
                   2630:     obj = valuePop(ctxt);
                   2631:     if (obj == NULL) {
                   2632:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2633:        return(0);
                   2634:     }
                   2635:     if (obj->type != XPATH_NUMBER)
                   2636:        ret = xmlXPathCastToNumber(obj);
                   2637:     else
                   2638:         ret = obj->floatval;
                   2639:     xmlXPathReleaseObject(ctxt->context, obj);
                   2640:     return(ret);
                   2641: }
                   2642: 
                   2643: /**
                   2644:  * xmlXPathPopString:
                   2645:  * @ctxt:  an XPath parser context
                   2646:  *
                   2647:  * Pops a string from the stack, handling conversion if needed.
                   2648:  * Check error with #xmlXPathCheckError.
                   2649:  *
                   2650:  * Returns the string
                   2651:  */
                   2652: xmlChar *
                   2653: xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
                   2654:     xmlXPathObjectPtr obj;
                   2655:     xmlChar * ret;
                   2656: 
                   2657:     obj = valuePop(ctxt);
                   2658:     if (obj == NULL) {
                   2659:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2660:        return(NULL);
                   2661:     }
                   2662:     ret = xmlXPathCastToString(obj);   /* this does required strdup */
                   2663:     /* TODO: needs refactoring somewhere else */
                   2664:     if (obj->stringval == ret)
                   2665:        obj->stringval = NULL;
                   2666:     xmlXPathReleaseObject(ctxt->context, obj);
                   2667:     return(ret);
                   2668: }
                   2669: 
                   2670: /**
                   2671:  * xmlXPathPopNodeSet:
                   2672:  * @ctxt:  an XPath parser context
                   2673:  *
                   2674:  * Pops a node-set from the stack, handling conversion if needed.
                   2675:  * Check error with #xmlXPathCheckError.
                   2676:  *
                   2677:  * Returns the node-set
                   2678:  */
                   2679: xmlNodeSetPtr
                   2680: xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
                   2681:     xmlXPathObjectPtr obj;
                   2682:     xmlNodeSetPtr ret;
                   2683: 
                   2684:     if (ctxt == NULL) return(NULL);
                   2685:     if (ctxt->value == NULL) {
                   2686:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2687:        return(NULL);
                   2688:     }
                   2689:     if (!xmlXPathStackIsNodeSet(ctxt)) {
                   2690:        xmlXPathSetTypeError(ctxt);
                   2691:        return(NULL);
                   2692:     }
                   2693:     obj = valuePop(ctxt);
                   2694:     ret = obj->nodesetval;
                   2695: #if 0
                   2696:     /* to fix memory leak of not clearing obj->user */
                   2697:     if (obj->boolval && obj->user != NULL)
                   2698:         xmlFreeNodeList((xmlNodePtr) obj->user);
                   2699: #endif
                   2700:     obj->nodesetval = NULL;
                   2701:     xmlXPathReleaseObject(ctxt->context, obj);
                   2702:     return(ret);
                   2703: }
                   2704: 
                   2705: /**
                   2706:  * xmlXPathPopExternal:
                   2707:  * @ctxt:  an XPath parser context
                   2708:  *
                   2709:  * Pops an external object from the stack, handling conversion if needed.
                   2710:  * Check error with #xmlXPathCheckError.
                   2711:  *
                   2712:  * Returns the object
                   2713:  */
                   2714: void *
                   2715: xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
                   2716:     xmlXPathObjectPtr obj;
                   2717:     void * ret;
                   2718: 
                   2719:     if ((ctxt == NULL) || (ctxt->value == NULL)) {
                   2720:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
                   2721:        return(NULL);
                   2722:     }
                   2723:     if (ctxt->value->type != XPATH_USERS) {
                   2724:        xmlXPathSetTypeError(ctxt);
                   2725:        return(NULL);
                   2726:     }
                   2727:     obj = valuePop(ctxt);
                   2728:     ret = obj->user;
                   2729:     obj->user = NULL;
                   2730:     xmlXPathReleaseObject(ctxt->context, obj);
                   2731:     return(ret);
                   2732: }
                   2733: 
                   2734: /*
                   2735:  * Macros for accessing the content. Those should be used only by the parser,
                   2736:  * and not exported.
                   2737:  *
                   2738:  * Dirty macros, i.e. one need to make assumption on the context to use them
                   2739:  *
                   2740:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
                   2741:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
                   2742:  *           in ISO-Latin or UTF-8.
                   2743:  *           This should be used internally by the parser
                   2744:  *           only to compare to ASCII values otherwise it would break when
                   2745:  *           running with UTF-8 encoding.
                   2746:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
                   2747:  *           to compare on ASCII based substring.
                   2748:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
                   2749:  *           strings within the parser.
                   2750:  *   CURRENT Returns the current char value, with the full decoding of
                   2751:  *           UTF-8 if we are using this mode. It returns an int.
                   2752:  *   NEXT    Skip to the next character, this does the proper decoding
                   2753:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
                   2754:  *           It returns the pointer to the current xmlChar.
                   2755:  */
                   2756: 
                   2757: #define CUR (*ctxt->cur)
                   2758: #define SKIP(val) ctxt->cur += (val)
                   2759: #define NXT(val) ctxt->cur[(val)]
                   2760: #define CUR_PTR ctxt->cur
                   2761: #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
                   2762: 
                   2763: #define COPY_BUF(l,b,i,v)                                              \
                   2764:     if (l == 1) b[i++] = (xmlChar) v;                                  \
                   2765:     else i += xmlCopyChar(l,&b[i],v)
                   2766: 
                   2767: #define NEXTL(l)  ctxt->cur += l
                   2768: 
                   2769: #define SKIP_BLANKS                                                    \
                   2770:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
                   2771: 
                   2772: #define CURRENT (*ctxt->cur)
                   2773: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
                   2774: 
                   2775: 
                   2776: #ifndef DBL_DIG
                   2777: #define DBL_DIG 16
                   2778: #endif
                   2779: #ifndef DBL_EPSILON
                   2780: #define DBL_EPSILON 1E-9
                   2781: #endif
                   2782: 
                   2783: #define UPPER_DOUBLE 1E9
                   2784: #define LOWER_DOUBLE 1E-5
                   2785: #define        LOWER_DOUBLE_EXP 5
                   2786: 
                   2787: #define INTEGER_DIGITS DBL_DIG
                   2788: #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
                   2789: #define EXPONENT_DIGITS (3 + 2)
                   2790: 
                   2791: /**
                   2792:  * xmlXPathFormatNumber:
                   2793:  * @number:     number to format
                   2794:  * @buffer:     output buffer
                   2795:  * @buffersize: size of output buffer
                   2796:  *
                   2797:  * Convert the number into a string representation.
                   2798:  */
                   2799: static void
                   2800: xmlXPathFormatNumber(double number, char buffer[], int buffersize)
                   2801: {
                   2802:     switch (xmlXPathIsInf(number)) {
                   2803:     case 1:
                   2804:        if (buffersize > (int)sizeof("Infinity"))
                   2805:            snprintf(buffer, buffersize, "Infinity");
                   2806:        break;
                   2807:     case -1:
                   2808:        if (buffersize > (int)sizeof("-Infinity"))
                   2809:            snprintf(buffer, buffersize, "-Infinity");
                   2810:        break;
                   2811:     default:
                   2812:        if (xmlXPathIsNaN(number)) {
                   2813:            if (buffersize > (int)sizeof("NaN"))
                   2814:                snprintf(buffer, buffersize, "NaN");
                   2815:        } else if (number == 0 && xmlXPathGetSign(number) != 0) {
                   2816:            snprintf(buffer, buffersize, "0");
                   2817:        } else if (number == ((int) number)) {
                   2818:            char work[30];
                   2819:            char *ptr, *cur;
                   2820:            int value = (int) number;
                   2821: 
                   2822:             ptr = &buffer[0];
                   2823:            if (value == 0) {
                   2824:                *ptr++ = '0';
                   2825:            } else {
                   2826:                snprintf(work, 29, "%d", value);
                   2827:                cur = &work[0];
                   2828:                while ((*cur) && (ptr - buffer < buffersize)) {
                   2829:                    *ptr++ = *cur++;
                   2830:                }
                   2831:            }
                   2832:            if (ptr - buffer < buffersize) {
                   2833:                *ptr = 0;
                   2834:            } else if (buffersize > 0) {
                   2835:                ptr--;
                   2836:                *ptr = 0;
                   2837:            }
                   2838:        } else {
                   2839:            /*
                   2840:              For the dimension of work,
                   2841:                  DBL_DIG is number of significant digits
                   2842:                  EXPONENT is only needed for "scientific notation"
                   2843:                  3 is sign, decimal point, and terminating zero
                   2844:                  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
                   2845:              Note that this dimension is slightly (a few characters)
                   2846:              larger than actually necessary.
                   2847:            */
                   2848:            char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
                   2849:            int integer_place, fraction_place;
                   2850:            char *ptr;
                   2851:            char *after_fraction;
                   2852:            double absolute_value;
                   2853:            int size;
                   2854: 
                   2855:            absolute_value = fabs(number);
                   2856: 
                   2857:            /*
                   2858:             * First choose format - scientific or regular floating point.
                   2859:             * In either case, result is in work, and after_fraction points
                   2860:             * just past the fractional part.
                   2861:            */
                   2862:            if ( ((absolute_value > UPPER_DOUBLE) ||
                   2863:                  (absolute_value < LOWER_DOUBLE)) &&
                   2864:                 (absolute_value != 0.0) ) {
                   2865:                /* Use scientific notation */
                   2866:                integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
                   2867:                fraction_place = DBL_DIG - 1;
                   2868:                size = snprintf(work, sizeof(work),"%*.*e",
                   2869:                         integer_place, fraction_place, number);
                   2870:                while ((size > 0) && (work[size] != 'e')) size--;
                   2871: 
                   2872:            }
                   2873:            else {
                   2874:                /* Use regular notation */
                   2875:                if (absolute_value > 0.0) {
                   2876:                    integer_place = (int)log10(absolute_value);
                   2877:                    if (integer_place > 0)
                   2878:                        fraction_place = DBL_DIG - integer_place - 1;
                   2879:                    else
                   2880:                        fraction_place = DBL_DIG - integer_place;
                   2881:                } else {
                   2882:                    fraction_place = 1;
                   2883:                }
                   2884:                size = snprintf(work, sizeof(work), "%0.*f",
                   2885:                                fraction_place, number);
                   2886:            }
                   2887: 
                   2888:            /* Remove fractional trailing zeroes */
                   2889:            after_fraction = work + size;
                   2890:            ptr = after_fraction;
                   2891:            while (*(--ptr) == '0')
                   2892:                ;
                   2893:            if (*ptr != '.')
                   2894:                ptr++;
                   2895:            while ((*ptr++ = *after_fraction++) != 0);
                   2896: 
                   2897:            /* Finally copy result back to caller */
                   2898:            size = strlen(work) + 1;
                   2899:            if (size > buffersize) {
                   2900:                work[buffersize - 1] = 0;
                   2901:                size = buffersize;
                   2902:            }
                   2903:            memmove(buffer, work, size);
                   2904:        }
                   2905:        break;
                   2906:     }
                   2907: }
                   2908: 
                   2909: 
                   2910: /************************************************************************
                   2911:  *                                                                     *
                   2912:  *                     Routines to handle NodeSets                     *
                   2913:  *                                                                     *
                   2914:  ************************************************************************/
                   2915: 
                   2916: /**
                   2917:  * xmlXPathOrderDocElems:
                   2918:  * @doc:  an input document
                   2919:  *
                   2920:  * Call this routine to speed up XPath computation on static documents.
                   2921:  * This stamps all the element nodes with the document order
                   2922:  * Like for line information, the order is kept in the element->content
                   2923:  * field, the value stored is actually - the node number (starting at -1)
                   2924:  * to be able to differentiate from line numbers.
                   2925:  *
                   2926:  * Returns the number of elements found in the document or -1 in case
                   2927:  *    of error.
                   2928:  */
                   2929: long
                   2930: xmlXPathOrderDocElems(xmlDocPtr doc) {
                   2931:     long count = 0;
                   2932:     xmlNodePtr cur;
                   2933: 
                   2934:     if (doc == NULL)
                   2935:        return(-1);
                   2936:     cur = doc->children;
                   2937:     while (cur != NULL) {
                   2938:        if (cur->type == XML_ELEMENT_NODE) {
                   2939:            cur->content = (void *) (-(++count));
                   2940:            if (cur->children != NULL) {
                   2941:                cur = cur->children;
                   2942:                continue;
                   2943:            }
                   2944:        }
                   2945:        if (cur->next != NULL) {
                   2946:            cur = cur->next;
                   2947:            continue;
                   2948:        }
                   2949:        do {
                   2950:            cur = cur->parent;
                   2951:            if (cur == NULL)
                   2952:                break;
                   2953:            if (cur == (xmlNodePtr) doc) {
                   2954:                cur = NULL;
                   2955:                break;
                   2956:            }
                   2957:            if (cur->next != NULL) {
                   2958:                cur = cur->next;
                   2959:                break;
                   2960:            }
                   2961:        } while (cur != NULL);
                   2962:     }
                   2963:     return(count);
                   2964: }
                   2965: 
                   2966: /**
                   2967:  * xmlXPathCmpNodes:
                   2968:  * @node1:  the first node
                   2969:  * @node2:  the second node
                   2970:  *
                   2971:  * Compare two nodes w.r.t document order
                   2972:  *
                   2973:  * Returns -2 in case of error 1 if first point < second point, 0 if
                   2974:  *         it's the same node, -1 otherwise
                   2975:  */
                   2976: int
                   2977: xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
                   2978:     int depth1, depth2;
                   2979:     int attr1 = 0, attr2 = 0;
                   2980:     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
                   2981:     xmlNodePtr cur, root;
                   2982: 
                   2983:     if ((node1 == NULL) || (node2 == NULL))
                   2984:        return(-2);
                   2985:     /*
                   2986:      * a couple of optimizations which will avoid computations in most cases
                   2987:      */
                   2988:     if (node1 == node2)                /* trivial case */
                   2989:        return(0);
                   2990:     if (node1->type == XML_ATTRIBUTE_NODE) {
                   2991:        attr1 = 1;
                   2992:        attrNode1 = node1;
                   2993:        node1 = node1->parent;
                   2994:     }
                   2995:     if (node2->type == XML_ATTRIBUTE_NODE) {
                   2996:        attr2 = 1;
                   2997:        attrNode2 = node2;
                   2998:        node2 = node2->parent;
                   2999:     }
                   3000:     if (node1 == node2) {
                   3001:        if (attr1 == attr2) {
                   3002:            /* not required, but we keep attributes in order */
                   3003:            if (attr1 != 0) {
                   3004:                cur = attrNode2->prev;
                   3005:                while (cur != NULL) {
                   3006:                    if (cur == attrNode1)
                   3007:                        return (1);
                   3008:                    cur = cur->prev;
                   3009:                }
                   3010:                return (-1);
                   3011:            }
                   3012:            return(0);
                   3013:        }
                   3014:        if (attr2 == 1)
                   3015:            return(1);
                   3016:        return(-1);
                   3017:     }
                   3018:     if ((node1->type == XML_NAMESPACE_DECL) ||
                   3019:         (node2->type == XML_NAMESPACE_DECL))
                   3020:        return(1);
                   3021:     if (node1 == node2->prev)
                   3022:        return(1);
                   3023:     if (node1 == node2->next)
                   3024:        return(-1);
                   3025: 
                   3026:     /*
                   3027:      * Speedup using document order if availble.
                   3028:      */
                   3029:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3030:        (node2->type == XML_ELEMENT_NODE) &&
                   3031:        (0 > (long) node1->content) &&
                   3032:        (0 > (long) node2->content) &&
                   3033:        (node1->doc == node2->doc)) {
                   3034:        long l1, l2;
                   3035: 
                   3036:        l1 = -((long) node1->content);
                   3037:        l2 = -((long) node2->content);
                   3038:        if (l1 < l2)
                   3039:            return(1);
                   3040:        if (l1 > l2)
                   3041:            return(-1);
                   3042:     }
                   3043: 
                   3044:     /*
                   3045:      * compute depth to root
                   3046:      */
                   3047:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
                   3048:        if (cur == node1)
                   3049:            return(1);
                   3050:        depth2++;
                   3051:     }
                   3052:     root = cur;
                   3053:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
                   3054:        if (cur == node2)
                   3055:            return(-1);
                   3056:        depth1++;
                   3057:     }
                   3058:     /*
                   3059:      * Distinct document (or distinct entities :-( ) case.
                   3060:      */
                   3061:     if (root != cur) {
                   3062:        return(-2);
                   3063:     }
                   3064:     /*
                   3065:      * get the nearest common ancestor.
                   3066:      */
                   3067:     while (depth1 > depth2) {
                   3068:        depth1--;
                   3069:        node1 = node1->parent;
                   3070:     }
                   3071:     while (depth2 > depth1) {
                   3072:        depth2--;
                   3073:        node2 = node2->parent;
                   3074:     }
                   3075:     while (node1->parent != node2->parent) {
                   3076:        node1 = node1->parent;
                   3077:        node2 = node2->parent;
                   3078:        /* should not happen but just in case ... */
                   3079:        if ((node1 == NULL) || (node2 == NULL))
                   3080:            return(-2);
                   3081:     }
                   3082:     /*
                   3083:      * Find who's first.
                   3084:      */
                   3085:     if (node1 == node2->prev)
                   3086:        return(1);
                   3087:     if (node1 == node2->next)
                   3088:        return(-1);
                   3089:     /*
                   3090:      * Speedup using document order if availble.
                   3091:      */
                   3092:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3093:        (node2->type == XML_ELEMENT_NODE) &&
                   3094:        (0 > (long) node1->content) &&
                   3095:        (0 > (long) node2->content) &&
                   3096:        (node1->doc == node2->doc)) {
                   3097:        long l1, l2;
                   3098: 
                   3099:        l1 = -((long) node1->content);
                   3100:        l2 = -((long) node2->content);
                   3101:        if (l1 < l2)
                   3102:            return(1);
                   3103:        if (l1 > l2)
                   3104:            return(-1);
                   3105:     }
                   3106: 
                   3107:     for (cur = node1->next;cur != NULL;cur = cur->next)
                   3108:        if (cur == node2)
                   3109:            return(1);
                   3110:     return(-1); /* assume there is no sibling list corruption */
                   3111: }
                   3112: 
                   3113: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   3114: /**
                   3115:  * xmlXPathCmpNodesExt:
                   3116:  * @node1:  the first node
                   3117:  * @node2:  the second node
                   3118:  *
                   3119:  * Compare two nodes w.r.t document order.
                   3120:  * This one is optimized for handling of non-element nodes.
                   3121:  *
                   3122:  * Returns -2 in case of error 1 if first point < second point, 0 if
                   3123:  *         it's the same node, -1 otherwise
                   3124:  */
                   3125: static int
                   3126: xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
                   3127:     int depth1, depth2;
                   3128:     int misc = 0, precedence1 = 0, precedence2 = 0;
                   3129:     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
                   3130:     xmlNodePtr cur, root;
                   3131:     long l1, l2;
                   3132: 
                   3133:     if ((node1 == NULL) || (node2 == NULL))
                   3134:        return(-2);
                   3135: 
                   3136:     if (node1 == node2)
                   3137:        return(0);
                   3138: 
                   3139:     /*
                   3140:      * a couple of optimizations which will avoid computations in most cases
                   3141:      */
                   3142:     switch (node1->type) {
                   3143:        case XML_ELEMENT_NODE:
                   3144:            if (node2->type == XML_ELEMENT_NODE) {
                   3145:                if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
                   3146:                    (0 > (long) node2->content) &&
                   3147:                    (node1->doc == node2->doc))
                   3148:                {
                   3149:                    l1 = -((long) node1->content);
                   3150:                    l2 = -((long) node2->content);
                   3151:                    if (l1 < l2)
                   3152:                        return(1);
                   3153:                    if (l1 > l2)
                   3154:                        return(-1);
                   3155:                } else
                   3156:                    goto turtle_comparison;
                   3157:            }
                   3158:            break;
                   3159:        case XML_ATTRIBUTE_NODE:
                   3160:            precedence1 = 1; /* element is owner */
                   3161:            miscNode1 = node1;
                   3162:            node1 = node1->parent;
                   3163:            misc = 1;
                   3164:            break;
                   3165:        case XML_TEXT_NODE:
                   3166:        case XML_CDATA_SECTION_NODE:
                   3167:        case XML_COMMENT_NODE:
                   3168:        case XML_PI_NODE: {
                   3169:            miscNode1 = node1;
                   3170:            /*
                   3171:            * Find nearest element node.
                   3172:            */
                   3173:            if (node1->prev != NULL) {
                   3174:                do {
                   3175:                    node1 = node1->prev;
                   3176:                    if (node1->type == XML_ELEMENT_NODE) {
                   3177:                        precedence1 = 3; /* element in prev-sibl axis */
                   3178:                        break;
                   3179:                    }
                   3180:                    if (node1->prev == NULL) {
                   3181:                        precedence1 = 2; /* element is parent */
                   3182:                        /*
                   3183:                        * URGENT TODO: Are there any cases, where the
                   3184:                        * parent of such a node is not an element node?
                   3185:                        */
                   3186:                        node1 = node1->parent;
                   3187:                        break;
                   3188:                    }
                   3189:                } while (1);
                   3190:            } else {
                   3191:                precedence1 = 2; /* element is parent */
                   3192:                node1 = node1->parent;
                   3193:            }
                   3194:            if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
                   3195:                (0 <= (long) node1->content)) {
                   3196:                /*
                   3197:                * Fallback for whatever case.
                   3198:                */
                   3199:                node1 = miscNode1;
                   3200:                precedence1 = 0;
                   3201:            } else
                   3202:                misc = 1;
                   3203:        }
                   3204:            break;
                   3205:        case XML_NAMESPACE_DECL:
                   3206:            /*
                   3207:            * TODO: why do we return 1 for namespace nodes?
                   3208:            */
                   3209:            return(1);
                   3210:        default:
                   3211:            break;
                   3212:     }
                   3213:     switch (node2->type) {
                   3214:        case XML_ELEMENT_NODE:
                   3215:            break;
                   3216:        case XML_ATTRIBUTE_NODE:
                   3217:            precedence2 = 1; /* element is owner */
                   3218:            miscNode2 = node2;
                   3219:            node2 = node2->parent;
                   3220:            misc = 1;
                   3221:            break;
                   3222:        case XML_TEXT_NODE:
                   3223:        case XML_CDATA_SECTION_NODE:
                   3224:        case XML_COMMENT_NODE:
                   3225:        case XML_PI_NODE: {
                   3226:            miscNode2 = node2;
                   3227:            if (node2->prev != NULL) {
                   3228:                do {
                   3229:                    node2 = node2->prev;
                   3230:                    if (node2->type == XML_ELEMENT_NODE) {
                   3231:                        precedence2 = 3; /* element in prev-sibl axis */
                   3232:                        break;
                   3233:                    }
                   3234:                    if (node2->prev == NULL) {
                   3235:                        precedence2 = 2; /* element is parent */
                   3236:                        node2 = node2->parent;
                   3237:                        break;
                   3238:                    }
                   3239:                } while (1);
                   3240:            } else {
                   3241:                precedence2 = 2; /* element is parent */
                   3242:                node2 = node2->parent;
                   3243:            }
                   3244:            if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
                   3245:                (0 <= (long) node1->content))
                   3246:            {
                   3247:                node2 = miscNode2;
                   3248:                precedence2 = 0;
                   3249:            } else
                   3250:                misc = 1;
                   3251:        }
                   3252:            break;
                   3253:        case XML_NAMESPACE_DECL:
                   3254:            return(1);
                   3255:        default:
                   3256:            break;
                   3257:     }
                   3258:     if (misc) {
                   3259:        if (node1 == node2) {
                   3260:            if (precedence1 == precedence2) {
                   3261:                /*
                   3262:                * The ugly case; but normally there aren't many
                   3263:                * adjacent non-element nodes around.
                   3264:                */
                   3265:                cur = miscNode2->prev;
                   3266:                while (cur != NULL) {
                   3267:                    if (cur == miscNode1)
                   3268:                        return(1);
                   3269:                    if (cur->type == XML_ELEMENT_NODE)
                   3270:                        return(-1);
                   3271:                    cur = cur->prev;
                   3272:                }
                   3273:                return (-1);
                   3274:            } else {
                   3275:                /*
                   3276:                * Evaluate based on higher precedence wrt to the element.
                   3277:                * TODO: This assumes attributes are sorted before content.
                   3278:                *   Is this 100% correct?
                   3279:                */
                   3280:                if (precedence1 < precedence2)
                   3281:                    return(1);
                   3282:                else
                   3283:                    return(-1);
                   3284:            }
                   3285:        }
                   3286:        /*
                   3287:        * Special case: One of the helper-elements is contained by the other.
                   3288:        * <foo>
                   3289:        *   <node2>
                   3290:        *     <node1>Text-1(precedence1 == 2)</node1>
                   3291:        *   </node2>
                   3292:        *   Text-6(precedence2 == 3)
                   3293:        * </foo>
                   3294:        */
                   3295:        if ((precedence2 == 3) && (precedence1 > 1)) {
                   3296:            cur = node1->parent;
                   3297:            while (cur) {
                   3298:                if (cur == node2)
                   3299:                    return(1);
                   3300:                cur = cur->parent;
                   3301:            }
                   3302:        }
                   3303:        if ((precedence1 == 3) && (precedence2 > 1)) {
                   3304:            cur = node2->parent;
                   3305:            while (cur) {
                   3306:                if (cur == node1)
                   3307:                    return(-1);
                   3308:                cur = cur->parent;
                   3309:            }
                   3310:        }
                   3311:     }
                   3312: 
                   3313:     /*
                   3314:      * Speedup using document order if availble.
                   3315:      */
                   3316:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3317:        (node2->type == XML_ELEMENT_NODE) &&
                   3318:        (0 > (long) node1->content) &&
                   3319:        (0 > (long) node2->content) &&
                   3320:        (node1->doc == node2->doc)) {
                   3321: 
                   3322:        l1 = -((long) node1->content);
                   3323:        l2 = -((long) node2->content);
                   3324:        if (l1 < l2)
                   3325:            return(1);
                   3326:        if (l1 > l2)
                   3327:            return(-1);
                   3328:     }
                   3329: 
                   3330: turtle_comparison:
                   3331: 
                   3332:     if (node1 == node2->prev)
                   3333:        return(1);
                   3334:     if (node1 == node2->next)
                   3335:        return(-1);
                   3336:     /*
                   3337:      * compute depth to root
                   3338:      */
                   3339:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
                   3340:        if (cur == node1)
                   3341:            return(1);
                   3342:        depth2++;
                   3343:     }
                   3344:     root = cur;
                   3345:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
                   3346:        if (cur == node2)
                   3347:            return(-1);
                   3348:        depth1++;
                   3349:     }
                   3350:     /*
                   3351:      * Distinct document (or distinct entities :-( ) case.
                   3352:      */
                   3353:     if (root != cur) {
                   3354:        return(-2);
                   3355:     }
                   3356:     /*
                   3357:      * get the nearest common ancestor.
                   3358:      */
                   3359:     while (depth1 > depth2) {
                   3360:        depth1--;
                   3361:        node1 = node1->parent;
                   3362:     }
                   3363:     while (depth2 > depth1) {
                   3364:        depth2--;
                   3365:        node2 = node2->parent;
                   3366:     }
                   3367:     while (node1->parent != node2->parent) {
                   3368:        node1 = node1->parent;
                   3369:        node2 = node2->parent;
                   3370:        /* should not happen but just in case ... */
                   3371:        if ((node1 == NULL) || (node2 == NULL))
                   3372:            return(-2);
                   3373:     }
                   3374:     /*
                   3375:      * Find who's first.
                   3376:      */
                   3377:     if (node1 == node2->prev)
                   3378:        return(1);
                   3379:     if (node1 == node2->next)
                   3380:        return(-1);
                   3381:     /*
                   3382:      * Speedup using document order if availble.
                   3383:      */
                   3384:     if ((node1->type == XML_ELEMENT_NODE) &&
                   3385:        (node2->type == XML_ELEMENT_NODE) &&
                   3386:        (0 > (long) node1->content) &&
                   3387:        (0 > (long) node2->content) &&
                   3388:        (node1->doc == node2->doc)) {
                   3389: 
                   3390:        l1 = -((long) node1->content);
                   3391:        l2 = -((long) node2->content);
                   3392:        if (l1 < l2)
                   3393:            return(1);
                   3394:        if (l1 > l2)
                   3395:            return(-1);
                   3396:     }
                   3397: 
                   3398:     for (cur = node1->next;cur != NULL;cur = cur->next)
                   3399:        if (cur == node2)
                   3400:            return(1);
                   3401:     return(-1); /* assume there is no sibling list corruption */
                   3402: }
                   3403: #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
                   3404: 
                   3405: /**
                   3406:  * xmlXPathNodeSetSort:
                   3407:  * @set:  the node set
                   3408:  *
                   3409:  * Sort the node set in document order
                   3410:  */
                   3411: void
                   3412: xmlXPathNodeSetSort(xmlNodeSetPtr set) {
1.1.1.3 ! misho    3413: #ifndef WITH_TIM_SORT
1.1       misho    3414:     int i, j, incr, len;
                   3415:     xmlNodePtr tmp;
1.1.1.3 ! misho    3416: #endif
1.1       misho    3417: 
                   3418:     if (set == NULL)
                   3419:        return;
                   3420: 
1.1.1.3 ! misho    3421: #ifndef WITH_TIM_SORT
        !          3422:     /*
        !          3423:      * Use the old Shell's sort implementation to sort the node-set
        !          3424:      * Timsort ought to be quite faster
        !          3425:      */
1.1       misho    3426:     len = set->nodeNr;
                   3427:     for (incr = len / 2; incr > 0; incr /= 2) {
                   3428:        for (i = incr; i < len; i++) {
                   3429:            j = i - incr;
                   3430:            while (j >= 0) {
                   3431: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   3432:                if (xmlXPathCmpNodesExt(set->nodeTab[j],
                   3433:                        set->nodeTab[j + incr]) == -1)
                   3434: #else
                   3435:                if (xmlXPathCmpNodes(set->nodeTab[j],
                   3436:                        set->nodeTab[j + incr]) == -1)
                   3437: #endif
                   3438:                {
                   3439:                    tmp = set->nodeTab[j];
                   3440:                    set->nodeTab[j] = set->nodeTab[j + incr];
                   3441:                    set->nodeTab[j + incr] = tmp;
                   3442:                    j -= incr;
                   3443:                } else
                   3444:                    break;
                   3445:            }
                   3446:        }
                   3447:     }
1.1.1.3 ! misho    3448: #else /* WITH_TIM_SORT */
        !          3449:     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
        !          3450: #endif /* WITH_TIM_SORT */
1.1       misho    3451: }
                   3452: 
                   3453: #define XML_NODESET_DEFAULT    10
                   3454: /**
                   3455:  * xmlXPathNodeSetDupNs:
                   3456:  * @node:  the parent node of the namespace XPath node
                   3457:  * @ns:  the libxml namespace declaration node.
                   3458:  *
                   3459:  * Namespace node in libxml don't match the XPath semantic. In a node set
                   3460:  * the namespace nodes are duplicated and the next pointer is set to the
                   3461:  * parent node in the XPath semantic.
                   3462:  *
                   3463:  * Returns the newly created object.
                   3464:  */
                   3465: static xmlNodePtr
                   3466: xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
                   3467:     xmlNsPtr cur;
                   3468: 
                   3469:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
                   3470:        return(NULL);
                   3471:     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
                   3472:        return((xmlNodePtr) ns);
                   3473: 
                   3474:     /*
                   3475:      * Allocate a new Namespace and fill the fields.
                   3476:      */
                   3477:     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
                   3478:     if (cur == NULL) {
                   3479:         xmlXPathErrMemory(NULL, "duplicating namespace\n");
                   3480:        return(NULL);
                   3481:     }
                   3482:     memset(cur, 0, sizeof(xmlNs));
                   3483:     cur->type = XML_NAMESPACE_DECL;
                   3484:     if (ns->href != NULL)
                   3485:        cur->href = xmlStrdup(ns->href);
                   3486:     if (ns->prefix != NULL)
                   3487:        cur->prefix = xmlStrdup(ns->prefix);
                   3488:     cur->next = (xmlNsPtr) node;
                   3489:     return((xmlNodePtr) cur);
                   3490: }
                   3491: 
                   3492: /**
                   3493:  * xmlXPathNodeSetFreeNs:
                   3494:  * @ns:  the XPath namespace node found in a nodeset.
                   3495:  *
                   3496:  * Namespace nodes in libxml don't match the XPath semantic. In a node set
                   3497:  * the namespace nodes are duplicated and the next pointer is set to the
                   3498:  * parent node in the XPath semantic. Check if such a node needs to be freed
                   3499:  */
                   3500: void
                   3501: xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
                   3502:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
                   3503:        return;
                   3504: 
                   3505:     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
                   3506:        if (ns->href != NULL)
                   3507:            xmlFree((xmlChar *)ns->href);
                   3508:        if (ns->prefix != NULL)
                   3509:            xmlFree((xmlChar *)ns->prefix);
                   3510:        xmlFree(ns);
                   3511:     }
                   3512: }
                   3513: 
                   3514: /**
                   3515:  * xmlXPathNodeSetCreate:
                   3516:  * @val:  an initial xmlNodePtr, or NULL
                   3517:  *
                   3518:  * Create a new xmlNodeSetPtr of type double and of value @val
                   3519:  *
                   3520:  * Returns the newly created object.
                   3521:  */
                   3522: xmlNodeSetPtr
                   3523: xmlXPathNodeSetCreate(xmlNodePtr val) {
                   3524:     xmlNodeSetPtr ret;
                   3525: 
                   3526:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
                   3527:     if (ret == NULL) {
                   3528:         xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3529:        return(NULL);
                   3530:     }
                   3531:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
                   3532:     if (val != NULL) {
                   3533:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3534:                                             sizeof(xmlNodePtr));
                   3535:        if (ret->nodeTab == NULL) {
                   3536:            xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3537:            xmlFree(ret);
                   3538:            return(NULL);
                   3539:        }
                   3540:        memset(ret->nodeTab, 0 ,
                   3541:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3542:         ret->nodeMax = XML_NODESET_DEFAULT;
                   3543:        if (val->type == XML_NAMESPACE_DECL) {
                   3544:            xmlNsPtr ns = (xmlNsPtr) val;
                   3545: 
                   3546:            ret->nodeTab[ret->nodeNr++] =
                   3547:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3548:        } else
                   3549:            ret->nodeTab[ret->nodeNr++] = val;
                   3550:     }
                   3551:     return(ret);
                   3552: }
                   3553: 
                   3554: /**
                   3555:  * xmlXPathNodeSetCreateSize:
                   3556:  * @size:  the initial size of the set
                   3557:  *
                   3558:  * Create a new xmlNodeSetPtr of type double and of value @val
                   3559:  *
                   3560:  * Returns the newly created object.
                   3561:  */
                   3562: static xmlNodeSetPtr
                   3563: xmlXPathNodeSetCreateSize(int size) {
                   3564:     xmlNodeSetPtr ret;
                   3565: 
                   3566:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
                   3567:     if (ret == NULL) {
                   3568:         xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3569:        return(NULL);
                   3570:     }
                   3571:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
                   3572:     if (size < XML_NODESET_DEFAULT)
                   3573:        size = XML_NODESET_DEFAULT;
                   3574:     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
                   3575:     if (ret->nodeTab == NULL) {
                   3576:        xmlXPathErrMemory(NULL, "creating nodeset\n");
                   3577:        xmlFree(ret);
                   3578:        return(NULL);
                   3579:     }
                   3580:     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
                   3581:     ret->nodeMax = size;
                   3582:     return(ret);
                   3583: }
                   3584: 
                   3585: /**
                   3586:  * xmlXPathNodeSetContains:
                   3587:  * @cur:  the node-set
                   3588:  * @val:  the node
                   3589:  *
                   3590:  * checks whether @cur contains @val
                   3591:  *
                   3592:  * Returns true (1) if @cur contains @val, false (0) otherwise
                   3593:  */
                   3594: int
                   3595: xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
                   3596:     int i;
                   3597: 
                   3598:     if ((cur == NULL) || (val == NULL)) return(0);
                   3599:     if (val->type == XML_NAMESPACE_DECL) {
                   3600:        for (i = 0; i < cur->nodeNr; i++) {
                   3601:            if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
                   3602:                xmlNsPtr ns1, ns2;
                   3603: 
                   3604:                ns1 = (xmlNsPtr) val;
                   3605:                ns2 = (xmlNsPtr) cur->nodeTab[i];
                   3606:                if (ns1 == ns2)
                   3607:                    return(1);
                   3608:                if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
                   3609:                    (xmlStrEqual(ns1->prefix, ns2->prefix)))
                   3610:                    return(1);
                   3611:            }
                   3612:        }
                   3613:     } else {
                   3614:        for (i = 0; i < cur->nodeNr; i++) {
                   3615:            if (cur->nodeTab[i] == val)
                   3616:                return(1);
                   3617:        }
                   3618:     }
                   3619:     return(0);
                   3620: }
                   3621: 
                   3622: /**
                   3623:  * xmlXPathNodeSetAddNs:
                   3624:  * @cur:  the initial node set
                   3625:  * @node:  the hosting node
                   3626:  * @ns:  a the namespace node
                   3627:  *
                   3628:  * add a new namespace node to an existing NodeSet
1.1.1.3 ! misho    3629:  *
        !          3630:  * Returns 0 in case of success and -1 in case of error
1.1       misho    3631:  */
1.1.1.3 ! misho    3632: int
1.1       misho    3633: xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
                   3634:     int i;
                   3635: 
                   3636: 
                   3637:     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
                   3638:         (ns->type != XML_NAMESPACE_DECL) ||
                   3639:        (node->type != XML_ELEMENT_NODE))
1.1.1.3 ! misho    3640:        return(-1);
1.1       misho    3641: 
                   3642:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3643:     /*
                   3644:      * prevent duplicates
                   3645:      */
                   3646:     for (i = 0;i < cur->nodeNr;i++) {
                   3647:         if ((cur->nodeTab[i] != NULL) &&
                   3648:            (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
                   3649:            (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
                   3650:            (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1.1.1.3 ! misho    3651:            return(0);
1.1       misho    3652:     }
                   3653: 
                   3654:     /*
                   3655:      * grow the nodeTab if needed
                   3656:      */
                   3657:     if (cur->nodeMax == 0) {
                   3658:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3659:                                             sizeof(xmlNodePtr));
                   3660:        if (cur->nodeTab == NULL) {
                   3661:            xmlXPathErrMemory(NULL, "growing nodeset\n");
1.1.1.3 ! misho    3662:            return(-1);
1.1       misho    3663:        }
                   3664:        memset(cur->nodeTab, 0 ,
                   3665:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3666:         cur->nodeMax = XML_NODESET_DEFAULT;
                   3667:     } else if (cur->nodeNr == cur->nodeMax) {
                   3668:         xmlNodePtr *temp;
                   3669: 
1.1.1.3 ! misho    3670:         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
        !          3671:             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
        !          3672:             return(-1);
        !          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");
1.1.1.3 ! misho    3678:            return(-1);
1.1       misho    3679:        }
1.1.1.2   misho    3680:         cur->nodeMax *= 2;
1.1       misho    3681:        cur->nodeTab = temp;
                   3682:     }
                   3683:     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1.1.1.3 ! misho    3684:     return(0);
1.1       misho    3685: }
                   3686: 
                   3687: /**
                   3688:  * xmlXPathNodeSetAdd:
                   3689:  * @cur:  the initial node set
                   3690:  * @val:  a new xmlNodePtr
                   3691:  *
                   3692:  * add a new xmlNodePtr to an existing NodeSet
1.1.1.3 ! misho    3693:  *
        !          3694:  * Returns 0 in case of success, and -1 in case of error
1.1       misho    3695:  */
1.1.1.3 ! misho    3696: int
1.1       misho    3697: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
                   3698:     int i;
                   3699: 
1.1.1.3 ! misho    3700:     if ((cur == NULL) || (val == NULL)) return(-1);
1.1       misho    3701: 
                   3702:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3703:     /*
                   3704:      * prevent duplcates
                   3705:      */
                   3706:     for (i = 0;i < cur->nodeNr;i++)
1.1.1.3 ! misho    3707:         if (cur->nodeTab[i] == val) return(0);
1.1       misho    3708: 
                   3709:     /*
                   3710:      * grow the nodeTab if needed
                   3711:      */
                   3712:     if (cur->nodeMax == 0) {
                   3713:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3714:                                             sizeof(xmlNodePtr));
                   3715:        if (cur->nodeTab == NULL) {
                   3716:            xmlXPathErrMemory(NULL, "growing nodeset\n");
1.1.1.3 ! misho    3717:            return(-1);
1.1       misho    3718:        }
                   3719:        memset(cur->nodeTab, 0 ,
                   3720:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3721:         cur->nodeMax = XML_NODESET_DEFAULT;
                   3722:     } else if (cur->nodeNr == cur->nodeMax) {
                   3723:         xmlNodePtr *temp;
                   3724: 
1.1.1.3 ! misho    3725:         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
        !          3726:             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
        !          3727:             return(-1);
        !          3728:         }
1.1.1.2   misho    3729:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1       misho    3730:                                      sizeof(xmlNodePtr));
                   3731:        if (temp == NULL) {
                   3732:            xmlXPathErrMemory(NULL, "growing nodeset\n");
1.1.1.3 ! misho    3733:            return(-1);
1.1       misho    3734:        }
1.1.1.2   misho    3735:         cur->nodeMax *= 2;
1.1       misho    3736:        cur->nodeTab = temp;
                   3737:     }
                   3738:     if (val->type == XML_NAMESPACE_DECL) {
                   3739:        xmlNsPtr ns = (xmlNsPtr) val;
                   3740: 
                   3741:        cur->nodeTab[cur->nodeNr++] =
                   3742:            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3743:     } else
                   3744:        cur->nodeTab[cur->nodeNr++] = val;
1.1.1.3 ! misho    3745:     return(0);
1.1       misho    3746: }
                   3747: 
                   3748: /**
                   3749:  * xmlXPathNodeSetAddUnique:
                   3750:  * @cur:  the initial node set
                   3751:  * @val:  a new xmlNodePtr
                   3752:  *
                   3753:  * add a new xmlNodePtr to an existing NodeSet, optimized version
                   3754:  * when we are sure the node is not already in the set.
1.1.1.3 ! misho    3755:  *
        !          3756:  * Returns 0 in case of success and -1 in case of failure
1.1       misho    3757:  */
1.1.1.3 ! misho    3758: int
1.1       misho    3759: xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1.1.1.3 ! misho    3760:     if ((cur == NULL) || (val == NULL)) return(-1);
1.1       misho    3761: 
                   3762:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3763:     /*
                   3764:      * grow the nodeTab if needed
                   3765:      */
                   3766:     if (cur->nodeMax == 0) {
                   3767:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3768:                                             sizeof(xmlNodePtr));
                   3769:        if (cur->nodeTab == NULL) {
                   3770:            xmlXPathErrMemory(NULL, "growing nodeset\n");
1.1.1.3 ! misho    3771:            return(-1);
1.1       misho    3772:        }
                   3773:        memset(cur->nodeTab, 0 ,
                   3774:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3775:         cur->nodeMax = XML_NODESET_DEFAULT;
                   3776:     } else if (cur->nodeNr == cur->nodeMax) {
                   3777:         xmlNodePtr *temp;
                   3778: 
1.1.1.3 ! misho    3779:         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
        !          3780:             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
        !          3781:             return(-1);
        !          3782:         }
1.1.1.2   misho    3783:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1       misho    3784:                                      sizeof(xmlNodePtr));
                   3785:        if (temp == NULL) {
                   3786:            xmlXPathErrMemory(NULL, "growing nodeset\n");
1.1.1.3 ! misho    3787:            return(-1);
1.1       misho    3788:        }
                   3789:        cur->nodeTab = temp;
1.1.1.2   misho    3790:         cur->nodeMax *= 2;
1.1       misho    3791:     }
                   3792:     if (val->type == XML_NAMESPACE_DECL) {
                   3793:        xmlNsPtr ns = (xmlNsPtr) val;
                   3794: 
                   3795:        cur->nodeTab[cur->nodeNr++] =
                   3796:            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3797:     } else
                   3798:        cur->nodeTab[cur->nodeNr++] = val;
1.1.1.3 ! misho    3799:     return(0);
1.1       misho    3800: }
                   3801: 
                   3802: /**
                   3803:  * xmlXPathNodeSetMerge:
                   3804:  * @val1:  the first NodeSet or NULL
                   3805:  * @val2:  the second NodeSet
                   3806:  *
                   3807:  * Merges two nodesets, all nodes from @val2 are added to @val1
                   3808:  * if @val1 is NULL, a new set is created and copied from @val2
                   3809:  *
                   3810:  * Returns @val1 once extended or NULL in case of error.
                   3811:  */
                   3812: xmlNodeSetPtr
                   3813: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
                   3814:     int i, j, initNr, skip;
                   3815:     xmlNodePtr n1, n2;
                   3816: 
                   3817:     if (val2 == NULL) return(val1);
                   3818:     if (val1 == NULL) {
                   3819:        val1 = xmlXPathNodeSetCreate(NULL);
                   3820:     if (val1 == NULL)
                   3821:         return (NULL);
                   3822: #if 0
                   3823:        /*
                   3824:        * TODO: The optimization won't work in every case, since
                   3825:        *  those nasty namespace nodes need to be added with
                   3826:        *  xmlXPathNodeSetDupNs() to the set; thus a pure
                   3827:        *  memcpy is not possible.
                   3828:        *  If there was a flag on the nodesetval, indicating that
                   3829:        *  some temporary nodes are in, that would be helpfull.
                   3830:        */
                   3831:        /*
                   3832:        * Optimization: Create an equally sized node-set
                   3833:        * and memcpy the content.
                   3834:        */
                   3835:        val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
                   3836:        if (val1 == NULL)
                   3837:            return(NULL);
                   3838:        if (val2->nodeNr != 0) {
                   3839:            if (val2->nodeNr == 1)
                   3840:                *(val1->nodeTab) = *(val2->nodeTab);
                   3841:            else {
                   3842:                memcpy(val1->nodeTab, val2->nodeTab,
                   3843:                    val2->nodeNr * sizeof(xmlNodePtr));
                   3844:            }
                   3845:            val1->nodeNr = val2->nodeNr;
                   3846:        }
                   3847:        return(val1);
                   3848: #endif
                   3849:     }
                   3850: 
                   3851:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   3852:     initNr = val1->nodeNr;
                   3853: 
                   3854:     for (i = 0;i < val2->nodeNr;i++) {
                   3855:        n2 = val2->nodeTab[i];
                   3856:        /*
                   3857:         * check against duplicates
                   3858:         */
                   3859:        skip = 0;
                   3860:        for (j = 0; j < initNr; j++) {
                   3861:            n1 = val1->nodeTab[j];
                   3862:            if (n1 == n2) {
                   3863:                skip = 1;
                   3864:                break;
                   3865:            } else if ((n1->type == XML_NAMESPACE_DECL) &&
                   3866:                       (n2->type == XML_NAMESPACE_DECL)) {
                   3867:                if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
                   3868:                    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
                   3869:                        ((xmlNsPtr) n2)->prefix)))
                   3870:                {
                   3871:                    skip = 1;
                   3872:                    break;
                   3873:                }
                   3874:            }
                   3875:        }
                   3876:        if (skip)
                   3877:            continue;
                   3878: 
                   3879:        /*
                   3880:         * grow the nodeTab if needed
                   3881:         */
                   3882:        if (val1->nodeMax == 0) {
                   3883:            val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
                   3884:                                                    sizeof(xmlNodePtr));
                   3885:            if (val1->nodeTab == NULL) {
                   3886:                xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3887:                return(NULL);
                   3888:            }
                   3889:            memset(val1->nodeTab, 0 ,
                   3890:                   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   3891:            val1->nodeMax = XML_NODESET_DEFAULT;
                   3892:        } else if (val1->nodeNr == val1->nodeMax) {
                   3893:            xmlNodePtr *temp;
                   3894: 
1.1.1.3 ! misho    3895:             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
        !          3896:                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
        !          3897:                 return(NULL);
        !          3898:             }
1.1.1.2   misho    3899:            temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
1.1       misho    3900:                                             sizeof(xmlNodePtr));
                   3901:            if (temp == NULL) {
                   3902:                xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3903:                return(NULL);
                   3904:            }
                   3905:            val1->nodeTab = temp;
1.1.1.2   misho    3906:            val1->nodeMax *= 2;
1.1       misho    3907:        }
                   3908:        if (n2->type == XML_NAMESPACE_DECL) {
                   3909:            xmlNsPtr ns = (xmlNsPtr) n2;
                   3910: 
                   3911:            val1->nodeTab[val1->nodeNr++] =
                   3912:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   3913:        } else
                   3914:            val1->nodeTab[val1->nodeNr++] = n2;
                   3915:     }
                   3916: 
                   3917:     return(val1);
                   3918: }
                   3919: 
                   3920: 
                   3921: /**
                   3922:  * xmlXPathNodeSetMergeAndClear:
                   3923:  * @set1:  the first NodeSet or NULL
                   3924:  * @set2:  the second NodeSet
                   3925:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
                   3926:  *
                   3927:  * Merges two nodesets, all nodes from @set2 are added to @set1
                   3928:  * if @set1 is NULL, a new set is created and copied from @set2.
                   3929:  * Checks for duplicate nodes. Clears set2.
                   3930:  *
                   3931:  * Returns @set1 once extended or NULL in case of error.
                   3932:  */
                   3933: static xmlNodeSetPtr
                   3934: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
                   3935:                             int hasNullEntries)
                   3936: {
                   3937:     if ((set1 == NULL) && (hasNullEntries == 0)) {
                   3938:        /*
                   3939:        * Note that doing a memcpy of the list, namespace nodes are
                   3940:        * just assigned to set1, since set2 is cleared anyway.
                   3941:        */
                   3942:        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
                   3943:        if (set1 == NULL)
                   3944:            return(NULL);
                   3945:        if (set2->nodeNr != 0) {
                   3946:            memcpy(set1->nodeTab, set2->nodeTab,
                   3947:                set2->nodeNr * sizeof(xmlNodePtr));
                   3948:            set1->nodeNr = set2->nodeNr;
                   3949:        }
                   3950:     } else {
                   3951:        int i, j, initNbSet1;
                   3952:        xmlNodePtr n1, n2;
                   3953: 
                   3954:        if (set1 == NULL)
                   3955:             set1 = xmlXPathNodeSetCreate(NULL);
                   3956:         if (set1 == NULL)
                   3957:             return (NULL);
                   3958: 
                   3959:        initNbSet1 = set1->nodeNr;
                   3960:        for (i = 0;i < set2->nodeNr;i++) {
                   3961:            n2 = set2->nodeTab[i];
                   3962:            /*
                   3963:            * Skip NULLed entries.
                   3964:            */
                   3965:            if (n2 == NULL)
                   3966:                continue;
                   3967:            /*
                   3968:            * Skip duplicates.
                   3969:            */
                   3970:            for (j = 0; j < initNbSet1; j++) {
                   3971:                n1 = set1->nodeTab[j];
                   3972:                if (n1 == n2) {
                   3973:                    goto skip_node;
                   3974:                } else if ((n1->type == XML_NAMESPACE_DECL) &&
                   3975:                    (n2->type == XML_NAMESPACE_DECL))
                   3976:                {
                   3977:                    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
                   3978:                        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
                   3979:                        ((xmlNsPtr) n2)->prefix)))
                   3980:                    {
                   3981:                        /*
                   3982:                        * Free the namespace node.
                   3983:                        */
                   3984:                        set2->nodeTab[i] = NULL;
                   3985:                        xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
                   3986:                        goto skip_node;
                   3987:                    }
                   3988:                }
                   3989:            }
                   3990:            /*
                   3991:            * grow the nodeTab if needed
                   3992:            */
                   3993:            if (set1->nodeMax == 0) {
                   3994:                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
                   3995:                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
                   3996:                if (set1->nodeTab == NULL) {
                   3997:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   3998:                    return(NULL);
                   3999:                }
                   4000:                memset(set1->nodeTab, 0,
                   4001:                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   4002:                set1->nodeMax = XML_NODESET_DEFAULT;
                   4003:            } else if (set1->nodeNr >= set1->nodeMax) {
                   4004:                xmlNodePtr *temp;
                   4005: 
1.1.1.3 ! misho    4006:                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
        !          4007:                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
        !          4008:                     return(NULL);
        !          4009:                 }
1.1       misho    4010:                temp = (xmlNodePtr *) xmlRealloc(
1.1.1.2   misho    4011:                    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
1.1       misho    4012:                if (temp == NULL) {
                   4013:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   4014:                    return(NULL);
                   4015:                }
                   4016:                set1->nodeTab = temp;
1.1.1.2   misho    4017:                set1->nodeMax *= 2;
1.1       misho    4018:            }
                   4019:            if (n2->type == XML_NAMESPACE_DECL) {
                   4020:                xmlNsPtr ns = (xmlNsPtr) n2;
                   4021: 
                   4022:                set1->nodeTab[set1->nodeNr++] =
                   4023:                    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
                   4024:            } else
                   4025:                set1->nodeTab[set1->nodeNr++] = n2;
                   4026: skip_node:
                   4027:            {}
                   4028:        }
                   4029:     }
                   4030:     set2->nodeNr = 0;
                   4031:     return(set1);
                   4032: }
                   4033: 
                   4034: /**
                   4035:  * xmlXPathNodeSetMergeAndClearNoDupls:
                   4036:  * @set1:  the first NodeSet or NULL
                   4037:  * @set2:  the second NodeSet
                   4038:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
                   4039:  *
                   4040:  * Merges two nodesets, all nodes from @set2 are added to @set1
                   4041:  * if @set1 is NULL, a new set is created and copied from @set2.
                   4042:  * Doesn't chack for duplicate nodes. Clears set2.
                   4043:  *
                   4044:  * Returns @set1 once extended or NULL in case of error.
                   4045:  */
                   4046: static xmlNodeSetPtr
                   4047: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
                   4048:                                    int hasNullEntries)
                   4049: {
                   4050:     if (set2 == NULL)
                   4051:        return(set1);
                   4052:     if ((set1 == NULL) && (hasNullEntries == 0)) {
                   4053:        /*
                   4054:        * Note that doing a memcpy of the list, namespace nodes are
                   4055:        * just assigned to set1, since set2 is cleared anyway.
                   4056:        */
                   4057:        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
                   4058:        if (set1 == NULL)
                   4059:            return(NULL);
                   4060:        if (set2->nodeNr != 0) {
                   4061:            memcpy(set1->nodeTab, set2->nodeTab,
                   4062:                set2->nodeNr * sizeof(xmlNodePtr));
                   4063:            set1->nodeNr = set2->nodeNr;
                   4064:        }
                   4065:     } else {
                   4066:        int i;
                   4067:        xmlNodePtr n2;
                   4068: 
                   4069:        if (set1 == NULL)
                   4070:            set1 = xmlXPathNodeSetCreate(NULL);
                   4071:         if (set1 == NULL)
                   4072:             return (NULL);
                   4073: 
                   4074:        for (i = 0;i < set2->nodeNr;i++) {
                   4075:            n2 = set2->nodeTab[i];
                   4076:            /*
                   4077:            * Skip NULLed entries.
                   4078:            */
                   4079:            if (n2 == NULL)
                   4080:                continue;
                   4081:            if (set1->nodeMax == 0) {
                   4082:                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
                   4083:                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
                   4084:                if (set1->nodeTab == NULL) {
                   4085:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   4086:                    return(NULL);
                   4087:                }
                   4088:                memset(set1->nodeTab, 0,
                   4089:                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
                   4090:                set1->nodeMax = XML_NODESET_DEFAULT;
                   4091:            } else if (set1->nodeNr >= set1->nodeMax) {
                   4092:                xmlNodePtr *temp;
                   4093: 
1.1.1.3 ! misho    4094:                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
        !          4095:                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
        !          4096:                     return(NULL);
        !          4097:                 }
1.1       misho    4098:                temp = (xmlNodePtr *) xmlRealloc(
1.1.1.2   misho    4099:                    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
1.1       misho    4100:                if (temp == NULL) {
                   4101:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
                   4102:                    return(NULL);
                   4103:                }
                   4104:                set1->nodeTab = temp;
1.1.1.2   misho    4105:                set1->nodeMax *= 2;
1.1       misho    4106:            }
                   4107:            set1->nodeTab[set1->nodeNr++] = n2;
                   4108:        }
                   4109:     }
                   4110:     set2->nodeNr = 0;
                   4111:     return(set1);
                   4112: }
                   4113: 
                   4114: /**
                   4115:  * xmlXPathNodeSetDel:
                   4116:  * @cur:  the initial node set
                   4117:  * @val:  an xmlNodePtr
                   4118:  *
                   4119:  * Removes an xmlNodePtr from an existing NodeSet
                   4120:  */
                   4121: void
                   4122: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
                   4123:     int i;
                   4124: 
                   4125:     if (cur == NULL) return;
                   4126:     if (val == NULL) return;
                   4127: 
                   4128:     /*
                   4129:      * find node in nodeTab
                   4130:      */
                   4131:     for (i = 0;i < cur->nodeNr;i++)
                   4132:         if (cur->nodeTab[i] == val) break;
                   4133: 
                   4134:     if (i >= cur->nodeNr) {    /* not found */
                   4135: #ifdef DEBUG
                   4136:         xmlGenericError(xmlGenericErrorContext,
                   4137:                "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
                   4138:                val->name);
                   4139: #endif
                   4140:         return;
                   4141:     }
                   4142:     if ((cur->nodeTab[i] != NULL) &&
                   4143:        (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
                   4144:        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
                   4145:     cur->nodeNr--;
                   4146:     for (;i < cur->nodeNr;i++)
                   4147:         cur->nodeTab[i] = cur->nodeTab[i + 1];
                   4148:     cur->nodeTab[cur->nodeNr] = NULL;
                   4149: }
                   4150: 
                   4151: /**
                   4152:  * xmlXPathNodeSetRemove:
                   4153:  * @cur:  the initial node set
                   4154:  * @val:  the index to remove
                   4155:  *
                   4156:  * Removes an entry from an existing NodeSet list.
                   4157:  */
                   4158: void
                   4159: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
                   4160:     if (cur == NULL) return;
                   4161:     if (val >= cur->nodeNr) return;
                   4162:     if ((cur->nodeTab[val] != NULL) &&
                   4163:        (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
                   4164:        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
                   4165:     cur->nodeNr--;
                   4166:     for (;val < cur->nodeNr;val++)
                   4167:         cur->nodeTab[val] = cur->nodeTab[val + 1];
                   4168:     cur->nodeTab[cur->nodeNr] = NULL;
                   4169: }
                   4170: 
                   4171: /**
                   4172:  * xmlXPathFreeNodeSet:
                   4173:  * @obj:  the xmlNodeSetPtr to free
                   4174:  *
                   4175:  * Free the NodeSet compound (not the actual nodes !).
                   4176:  */
                   4177: void
                   4178: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
                   4179:     if (obj == NULL) return;
                   4180:     if (obj->nodeTab != NULL) {
                   4181:        int i;
                   4182: 
                   4183:        /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   4184:        for (i = 0;i < obj->nodeNr;i++)
                   4185:            if ((obj->nodeTab[i] != NULL) &&
                   4186:                (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
                   4187:                xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
                   4188:        xmlFree(obj->nodeTab);
                   4189:     }
                   4190:     xmlFree(obj);
                   4191: }
                   4192: 
                   4193: /**
                   4194:  * xmlXPathNodeSetClear:
                   4195:  * @set:  the node set to clear
                   4196:  *
                   4197:  * Clears the list from all temporary XPath objects (e.g. namespace nodes
                   4198:  * are feed), but does *not* free the list itself. Sets the length of the
                   4199:  * list to 0.
                   4200:  */
                   4201: static void
                   4202: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
                   4203: {
                   4204:     if ((set == NULL) || (set->nodeNr <= 0))
                   4205:        return;
                   4206:     else if (hasNsNodes) {
                   4207:        int i;
                   4208:        xmlNodePtr node;
                   4209: 
                   4210:        for (i = 0; i < set->nodeNr; i++) {
                   4211:            node = set->nodeTab[i];
                   4212:            if ((node != NULL) &&
                   4213:                (node->type == XML_NAMESPACE_DECL))
                   4214:                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
                   4215:        }
                   4216:     }
                   4217:     set->nodeNr = 0;
                   4218: }
                   4219: 
                   4220: /**
                   4221:  * xmlXPathNodeSetClearFromPos:
                   4222:  * @set: the node set to be cleared
                   4223:  * @pos: the start position to clear from
                   4224:  *
                   4225:  * Clears the list from temporary XPath objects (e.g. namespace nodes
                   4226:  * are feed) starting with the entry at @pos, but does *not* free the list
                   4227:  * itself. Sets the length of the list to @pos.
                   4228:  */
                   4229: static void
                   4230: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
                   4231: {
                   4232:     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
                   4233:        return;
                   4234:     else if ((hasNsNodes)) {
                   4235:        int i;
                   4236:        xmlNodePtr node;
                   4237: 
                   4238:        for (i = pos; i < set->nodeNr; i++) {
                   4239:            node = set->nodeTab[i];
                   4240:            if ((node != NULL) &&
                   4241:                (node->type == XML_NAMESPACE_DECL))
                   4242:                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
                   4243:        }
                   4244:     }
                   4245:     set->nodeNr = pos;
                   4246: }
                   4247: 
                   4248: /**
                   4249:  * xmlXPathFreeValueTree:
                   4250:  * @obj:  the xmlNodeSetPtr to free
                   4251:  *
                   4252:  * Free the NodeSet compound and the actual tree, this is different
                   4253:  * from xmlXPathFreeNodeSet()
                   4254:  */
                   4255: static void
                   4256: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
                   4257:     int i;
                   4258: 
                   4259:     if (obj == NULL) return;
                   4260: 
                   4261:     if (obj->nodeTab != NULL) {
                   4262:        for (i = 0;i < obj->nodeNr;i++) {
                   4263:            if (obj->nodeTab[i] != NULL) {
                   4264:                if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
                   4265:                    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
                   4266:                } else {
                   4267:                    xmlFreeNodeList(obj->nodeTab[i]);
                   4268:                }
                   4269:            }
                   4270:        }
                   4271:        xmlFree(obj->nodeTab);
                   4272:     }
                   4273:     xmlFree(obj);
                   4274: }
                   4275: 
                   4276: #if defined(DEBUG) || defined(DEBUG_STEP)
                   4277: /**
                   4278:  * xmlGenericErrorContextNodeSet:
                   4279:  * @output:  a FILE * for the output
                   4280:  * @obj:  the xmlNodeSetPtr to display
                   4281:  *
                   4282:  * Quick display of a NodeSet
                   4283:  */
                   4284: void
                   4285: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
                   4286:     int i;
                   4287: 
                   4288:     if (output == NULL) output = xmlGenericErrorContext;
                   4289:     if (obj == NULL)  {
                   4290:         fprintf(output, "NodeSet == NULL !\n");
                   4291:        return;
                   4292:     }
                   4293:     if (obj->nodeNr == 0) {
                   4294:         fprintf(output, "NodeSet is empty\n");
                   4295:        return;
                   4296:     }
                   4297:     if (obj->nodeTab == NULL) {
                   4298:        fprintf(output, " nodeTab == NULL !\n");
                   4299:        return;
                   4300:     }
                   4301:     for (i = 0; i < obj->nodeNr; i++) {
                   4302:         if (obj->nodeTab[i] == NULL) {
                   4303:            fprintf(output, " NULL !\n");
                   4304:            return;
                   4305:         }
                   4306:        if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
                   4307:            (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
                   4308:            fprintf(output, " /");
                   4309:        else if (obj->nodeTab[i]->name == NULL)
                   4310:            fprintf(output, " noname!");
                   4311:        else fprintf(output, " %s", obj->nodeTab[i]->name);
                   4312:     }
                   4313:     fprintf(output, "\n");
                   4314: }
                   4315: #endif
                   4316: 
                   4317: /**
                   4318:  * xmlXPathNewNodeSet:
                   4319:  * @val:  the NodePtr value
                   4320:  *
                   4321:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
                   4322:  * it with the single Node @val
                   4323:  *
                   4324:  * Returns the newly created object.
                   4325:  */
                   4326: xmlXPathObjectPtr
                   4327: xmlXPathNewNodeSet(xmlNodePtr val) {
                   4328:     xmlXPathObjectPtr ret;
                   4329: 
                   4330:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   4331:     if (ret == NULL) {
                   4332:         xmlXPathErrMemory(NULL, "creating nodeset\n");
                   4333:        return(NULL);
                   4334:     }
                   4335:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   4336:     ret->type = XPATH_NODESET;
                   4337:     ret->boolval = 0;
                   4338:     ret->nodesetval = xmlXPathNodeSetCreate(val);
                   4339:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
                   4340: #ifdef XP_DEBUG_OBJ_USAGE
                   4341:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
                   4342: #endif
                   4343:     return(ret);
                   4344: }
                   4345: 
                   4346: /**
                   4347:  * xmlXPathNewValueTree:
                   4348:  * @val:  the NodePtr value
                   4349:  *
                   4350:  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
                   4351:  * it with the tree root @val
                   4352:  *
                   4353:  * Returns the newly created object.
                   4354:  */
                   4355: xmlXPathObjectPtr
                   4356: xmlXPathNewValueTree(xmlNodePtr val) {
                   4357:     xmlXPathObjectPtr ret;
                   4358: 
                   4359:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   4360:     if (ret == NULL) {
                   4361:         xmlXPathErrMemory(NULL, "creating result value tree\n");
                   4362:        return(NULL);
                   4363:     }
                   4364:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   4365:     ret->type = XPATH_XSLT_TREE;
                   4366:     ret->boolval = 1;
                   4367:     ret->user = (void *) val;
                   4368:     ret->nodesetval = xmlXPathNodeSetCreate(val);
                   4369: #ifdef XP_DEBUG_OBJ_USAGE
                   4370:     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
                   4371: #endif
                   4372:     return(ret);
                   4373: }
                   4374: 
                   4375: /**
                   4376:  * xmlXPathNewNodeSetList:
                   4377:  * @val:  an existing NodeSet
                   4378:  *
                   4379:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
                   4380:  * it with the Nodeset @val
                   4381:  *
                   4382:  * Returns the newly created object.
                   4383:  */
                   4384: xmlXPathObjectPtr
                   4385: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
                   4386: {
                   4387:     xmlXPathObjectPtr ret;
                   4388:     int i;
                   4389: 
                   4390:     if (val == NULL)
                   4391:         ret = NULL;
                   4392:     else if (val->nodeTab == NULL)
                   4393:         ret = xmlXPathNewNodeSet(NULL);
                   4394:     else {
                   4395:         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1.1.1.3 ! misho    4396:         if (ret) {
        !          4397:             for (i = 1; i < val->nodeNr; ++i) {
        !          4398:                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
        !          4399:                    < 0) break;
        !          4400:            }
        !          4401:        }
1.1       misho    4402:     }
                   4403: 
                   4404:     return (ret);
                   4405: }
                   4406: 
                   4407: /**
                   4408:  * xmlXPathWrapNodeSet:
                   4409:  * @val:  the NodePtr value
                   4410:  *
                   4411:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
                   4412:  *
                   4413:  * Returns the newly created object.
                   4414:  */
                   4415: xmlXPathObjectPtr
                   4416: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
                   4417:     xmlXPathObjectPtr ret;
                   4418: 
                   4419:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   4420:     if (ret == NULL) {
                   4421:         xmlXPathErrMemory(NULL, "creating node set object\n");
                   4422:        return(NULL);
                   4423:     }
                   4424:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   4425:     ret->type = XPATH_NODESET;
                   4426:     ret->nodesetval = val;
                   4427: #ifdef XP_DEBUG_OBJ_USAGE
                   4428:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
                   4429: #endif
                   4430:     return(ret);
                   4431: }
                   4432: 
                   4433: /**
                   4434:  * xmlXPathFreeNodeSetList:
                   4435:  * @obj:  an existing NodeSetList object
                   4436:  *
                   4437:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
                   4438:  * the list contrary to xmlXPathFreeObject().
                   4439:  */
                   4440: void
                   4441: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
                   4442:     if (obj == NULL) return;
                   4443: #ifdef XP_DEBUG_OBJ_USAGE
                   4444:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
                   4445: #endif
                   4446:     xmlFree(obj);
                   4447: }
                   4448: 
                   4449: /**
                   4450:  * xmlXPathDifference:
                   4451:  * @nodes1:  a node-set
                   4452:  * @nodes2:  a node-set
                   4453:  *
                   4454:  * Implements the EXSLT - Sets difference() function:
                   4455:  *    node-set set:difference (node-set, node-set)
                   4456:  *
                   4457:  * Returns the difference between the two node sets, or nodes1 if
                   4458:  *         nodes2 is empty
                   4459:  */
                   4460: xmlNodeSetPtr
                   4461: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4462:     xmlNodeSetPtr ret;
                   4463:     int i, l1;
                   4464:     xmlNodePtr cur;
                   4465: 
                   4466:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4467:        return(nodes1);
                   4468: 
                   4469:     ret = xmlXPathNodeSetCreate(NULL);
                   4470:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4471:        return(ret);
                   4472: 
                   4473:     l1 = xmlXPathNodeSetGetLength(nodes1);
                   4474: 
                   4475:     for (i = 0; i < l1; i++) {
                   4476:        cur = xmlXPathNodeSetItem(nodes1, i);
1.1.1.3 ! misho    4477:        if (!xmlXPathNodeSetContains(nodes2, cur)) {
        !          4478:            if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
        !          4479:                break;
        !          4480:        }
1.1       misho    4481:     }
                   4482:     return(ret);
                   4483: }
                   4484: 
                   4485: /**
                   4486:  * xmlXPathIntersection:
                   4487:  * @nodes1:  a node-set
                   4488:  * @nodes2:  a node-set
                   4489:  *
                   4490:  * Implements the EXSLT - Sets intersection() function:
                   4491:  *    node-set set:intersection (node-set, node-set)
                   4492:  *
                   4493:  * Returns a node set comprising the nodes that are within both the
                   4494:  *         node sets passed as arguments
                   4495:  */
                   4496: xmlNodeSetPtr
                   4497: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4498:     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
                   4499:     int i, l1;
                   4500:     xmlNodePtr cur;
                   4501: 
                   4502:     if (ret == NULL)
                   4503:         return(ret);
                   4504:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4505:        return(ret);
                   4506:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4507:        return(ret);
                   4508: 
                   4509:     l1 = xmlXPathNodeSetGetLength(nodes1);
                   4510: 
                   4511:     for (i = 0; i < l1; i++) {
                   4512:        cur = xmlXPathNodeSetItem(nodes1, i);
1.1.1.3 ! misho    4513:        if (xmlXPathNodeSetContains(nodes2, cur)) {
        !          4514:            if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
        !          4515:                break;
        !          4516:        }
1.1       misho    4517:     }
                   4518:     return(ret);
                   4519: }
                   4520: 
                   4521: /**
                   4522:  * xmlXPathDistinctSorted:
                   4523:  * @nodes:  a node-set, sorted by document order
                   4524:  *
                   4525:  * Implements the EXSLT - Sets distinct() function:
                   4526:  *    node-set set:distinct (node-set)
                   4527:  *
                   4528:  * Returns a subset of the nodes contained in @nodes, or @nodes if
                   4529:  *         it is empty
                   4530:  */
                   4531: xmlNodeSetPtr
                   4532: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
                   4533:     xmlNodeSetPtr ret;
                   4534:     xmlHashTablePtr hash;
                   4535:     int i, l;
                   4536:     xmlChar * strval;
                   4537:     xmlNodePtr cur;
                   4538: 
                   4539:     if (xmlXPathNodeSetIsEmpty(nodes))
                   4540:        return(nodes);
                   4541: 
                   4542:     ret = xmlXPathNodeSetCreate(NULL);
                   4543:     if (ret == NULL)
                   4544:         return(ret);
                   4545:     l = xmlXPathNodeSetGetLength(nodes);
                   4546:     hash = xmlHashCreate (l);
                   4547:     for (i = 0; i < l; i++) {
                   4548:        cur = xmlXPathNodeSetItem(nodes, i);
                   4549:        strval = xmlXPathCastNodeToString(cur);
                   4550:        if (xmlHashLookup(hash, strval) == NULL) {
                   4551:            xmlHashAddEntry(hash, strval, strval);
1.1.1.3 ! misho    4552:            if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
        !          4553:                break;
1.1       misho    4554:        } else {
                   4555:            xmlFree(strval);
                   4556:        }
                   4557:     }
                   4558:     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
                   4559:     return(ret);
                   4560: }
                   4561: 
                   4562: /**
                   4563:  * xmlXPathDistinct:
                   4564:  * @nodes:  a node-set
                   4565:  *
                   4566:  * Implements the EXSLT - Sets distinct() function:
                   4567:  *    node-set set:distinct (node-set)
                   4568:  * @nodes is sorted by document order, then #exslSetsDistinctSorted
                   4569:  * is called with the sorted node-set
                   4570:  *
                   4571:  * Returns a subset of the nodes contained in @nodes, or @nodes if
                   4572:  *         it is empty
                   4573:  */
                   4574: xmlNodeSetPtr
                   4575: xmlXPathDistinct (xmlNodeSetPtr nodes) {
                   4576:     if (xmlXPathNodeSetIsEmpty(nodes))
                   4577:        return(nodes);
                   4578: 
                   4579:     xmlXPathNodeSetSort(nodes);
                   4580:     return(xmlXPathDistinctSorted(nodes));
                   4581: }
                   4582: 
                   4583: /**
                   4584:  * xmlXPathHasSameNodes:
                   4585:  * @nodes1:  a node-set
                   4586:  * @nodes2:  a node-set
                   4587:  *
                   4588:  * Implements the EXSLT - Sets has-same-nodes function:
                   4589:  *    boolean set:has-same-node(node-set, node-set)
                   4590:  *
                   4591:  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
                   4592:  *         otherwise
                   4593:  */
                   4594: int
                   4595: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4596:     int i, l;
                   4597:     xmlNodePtr cur;
                   4598: 
                   4599:     if (xmlXPathNodeSetIsEmpty(nodes1) ||
                   4600:        xmlXPathNodeSetIsEmpty(nodes2))
                   4601:        return(0);
                   4602: 
                   4603:     l = xmlXPathNodeSetGetLength(nodes1);
                   4604:     for (i = 0; i < l; i++) {
                   4605:        cur = xmlXPathNodeSetItem(nodes1, i);
                   4606:        if (xmlXPathNodeSetContains(nodes2, cur))
                   4607:            return(1);
                   4608:     }
                   4609:     return(0);
                   4610: }
                   4611: 
                   4612: /**
                   4613:  * xmlXPathNodeLeadingSorted:
                   4614:  * @nodes: a node-set, sorted by document order
                   4615:  * @node: a node
                   4616:  *
                   4617:  * Implements the EXSLT - Sets leading() function:
                   4618:  *    node-set set:leading (node-set, node-set)
                   4619:  *
                   4620:  * Returns the nodes in @nodes that precede @node in document order,
                   4621:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4622:  *         doesn't contain @node
                   4623:  */
                   4624: xmlNodeSetPtr
                   4625: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4626:     int i, l;
                   4627:     xmlNodePtr cur;
                   4628:     xmlNodeSetPtr ret;
                   4629: 
                   4630:     if (node == NULL)
                   4631:        return(nodes);
                   4632: 
                   4633:     ret = xmlXPathNodeSetCreate(NULL);
                   4634:     if (ret == NULL)
                   4635:         return(ret);
                   4636:     if (xmlXPathNodeSetIsEmpty(nodes) ||
                   4637:        (!xmlXPathNodeSetContains(nodes, node)))
                   4638:        return(ret);
                   4639: 
                   4640:     l = xmlXPathNodeSetGetLength(nodes);
                   4641:     for (i = 0; i < l; i++) {
                   4642:        cur = xmlXPathNodeSetItem(nodes, i);
                   4643:        if (cur == node)
                   4644:            break;
1.1.1.3 ! misho    4645:        if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
        !          4646:            break;
1.1       misho    4647:     }
                   4648:     return(ret);
                   4649: }
                   4650: 
                   4651: /**
                   4652:  * xmlXPathNodeLeading:
                   4653:  * @nodes:  a node-set
                   4654:  * @node:  a node
                   4655:  *
                   4656:  * Implements the EXSLT - Sets leading() function:
                   4657:  *    node-set set:leading (node-set, node-set)
                   4658:  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
                   4659:  * is called.
                   4660:  *
                   4661:  * Returns the nodes in @nodes that precede @node in document order,
                   4662:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4663:  *         doesn't contain @node
                   4664:  */
                   4665: xmlNodeSetPtr
                   4666: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4667:     xmlXPathNodeSetSort(nodes);
                   4668:     return(xmlXPathNodeLeadingSorted(nodes, node));
                   4669: }
                   4670: 
                   4671: /**
                   4672:  * xmlXPathLeadingSorted:
                   4673:  * @nodes1:  a node-set, sorted by document order
                   4674:  * @nodes2:  a node-set, sorted by document order
                   4675:  *
                   4676:  * Implements the EXSLT - Sets leading() function:
                   4677:  *    node-set set:leading (node-set, node-set)
                   4678:  *
                   4679:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
                   4680:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4681:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4682:  */
                   4683: xmlNodeSetPtr
                   4684: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4685:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4686:        return(nodes1);
                   4687:     return(xmlXPathNodeLeadingSorted(nodes1,
                   4688:                                     xmlXPathNodeSetItem(nodes2, 1)));
                   4689: }
                   4690: 
                   4691: /**
                   4692:  * xmlXPathLeading:
                   4693:  * @nodes1:  a node-set
                   4694:  * @nodes2:  a node-set
                   4695:  *
                   4696:  * Implements the EXSLT - Sets leading() function:
                   4697:  *    node-set set:leading (node-set, node-set)
                   4698:  * @nodes1 and @nodes2 are sorted by document order, then
                   4699:  * #exslSetsLeadingSorted is called.
                   4700:  *
                   4701:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
                   4702:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4703:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4704:  */
                   4705: xmlNodeSetPtr
                   4706: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4707:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4708:        return(nodes1);
                   4709:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4710:        return(xmlXPathNodeSetCreate(NULL));
                   4711:     xmlXPathNodeSetSort(nodes1);
                   4712:     xmlXPathNodeSetSort(nodes2);
                   4713:     return(xmlXPathNodeLeadingSorted(nodes1,
                   4714:                                     xmlXPathNodeSetItem(nodes2, 1)));
                   4715: }
                   4716: 
                   4717: /**
                   4718:  * xmlXPathNodeTrailingSorted:
                   4719:  * @nodes: a node-set, sorted by document order
                   4720:  * @node: a node
                   4721:  *
                   4722:  * Implements the EXSLT - Sets trailing() function:
                   4723:  *    node-set set:trailing (node-set, node-set)
                   4724:  *
                   4725:  * Returns the nodes in @nodes that follow @node in document order,
                   4726:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4727:  *         doesn't contain @node
                   4728:  */
                   4729: xmlNodeSetPtr
                   4730: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4731:     int i, l;
                   4732:     xmlNodePtr cur;
                   4733:     xmlNodeSetPtr ret;
                   4734: 
                   4735:     if (node == NULL)
                   4736:        return(nodes);
                   4737: 
                   4738:     ret = xmlXPathNodeSetCreate(NULL);
                   4739:     if (ret == NULL)
                   4740:         return(ret);
                   4741:     if (xmlXPathNodeSetIsEmpty(nodes) ||
                   4742:        (!xmlXPathNodeSetContains(nodes, node)))
                   4743:        return(ret);
                   4744: 
                   4745:     l = xmlXPathNodeSetGetLength(nodes);
                   4746:     for (i = l - 1; i >= 0; i--) {
                   4747:        cur = xmlXPathNodeSetItem(nodes, i);
                   4748:        if (cur == node)
                   4749:            break;
1.1.1.3 ! misho    4750:        if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
        !          4751:            break;
1.1       misho    4752:     }
                   4753:     xmlXPathNodeSetSort(ret);  /* bug 413451 */
                   4754:     return(ret);
                   4755: }
                   4756: 
                   4757: /**
                   4758:  * xmlXPathNodeTrailing:
                   4759:  * @nodes:  a node-set
                   4760:  * @node:  a node
                   4761:  *
                   4762:  * Implements the EXSLT - Sets trailing() function:
                   4763:  *    node-set set:trailing (node-set, node-set)
                   4764:  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
                   4765:  * is called.
                   4766:  *
                   4767:  * Returns the nodes in @nodes that follow @node in document order,
                   4768:  *         @nodes if @node is NULL or an empty node-set if @nodes
                   4769:  *         doesn't contain @node
                   4770:  */
                   4771: xmlNodeSetPtr
                   4772: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
                   4773:     xmlXPathNodeSetSort(nodes);
                   4774:     return(xmlXPathNodeTrailingSorted(nodes, node));
                   4775: }
                   4776: 
                   4777: /**
                   4778:  * xmlXPathTrailingSorted:
                   4779:  * @nodes1:  a node-set, sorted by document order
                   4780:  * @nodes2:  a node-set, sorted by document order
                   4781:  *
                   4782:  * Implements the EXSLT - Sets trailing() function:
                   4783:  *    node-set set:trailing (node-set, node-set)
                   4784:  *
                   4785:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
                   4786:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4787:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4788:  */
                   4789: xmlNodeSetPtr
                   4790: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4791:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4792:        return(nodes1);
                   4793:     return(xmlXPathNodeTrailingSorted(nodes1,
                   4794:                                      xmlXPathNodeSetItem(nodes2, 0)));
                   4795: }
                   4796: 
                   4797: /**
                   4798:  * xmlXPathTrailing:
                   4799:  * @nodes1:  a node-set
                   4800:  * @nodes2:  a node-set
                   4801:  *
                   4802:  * Implements the EXSLT - Sets trailing() function:
                   4803:  *    node-set set:trailing (node-set, node-set)
                   4804:  * @nodes1 and @nodes2 are sorted by document order, then
                   4805:  * #xmlXPathTrailingSorted is called.
                   4806:  *
                   4807:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
                   4808:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
                   4809:  *         an empty node-set if @nodes1 doesn't contain @nodes2
                   4810:  */
                   4811: xmlNodeSetPtr
                   4812: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
                   4813:     if (xmlXPathNodeSetIsEmpty(nodes2))
                   4814:        return(nodes1);
                   4815:     if (xmlXPathNodeSetIsEmpty(nodes1))
                   4816:        return(xmlXPathNodeSetCreate(NULL));
                   4817:     xmlXPathNodeSetSort(nodes1);
                   4818:     xmlXPathNodeSetSort(nodes2);
                   4819:     return(xmlXPathNodeTrailingSorted(nodes1,
                   4820:                                      xmlXPathNodeSetItem(nodes2, 0)));
                   4821: }
                   4822: 
                   4823: /************************************************************************
                   4824:  *                                                                     *
                   4825:  *             Routines to handle extra functions                      *
                   4826:  *                                                                     *
                   4827:  ************************************************************************/
                   4828: 
                   4829: /**
                   4830:  * xmlXPathRegisterFunc:
                   4831:  * @ctxt:  the XPath context
                   4832:  * @name:  the function name
                   4833:  * @f:  the function implementation or NULL
                   4834:  *
                   4835:  * Register a new function. If @f is NULL it unregisters the function
                   4836:  *
                   4837:  * Returns 0 in case of success, -1 in case of error
                   4838:  */
                   4839: int
                   4840: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4841:                     xmlXPathFunction f) {
                   4842:     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
                   4843: }
                   4844: 
                   4845: /**
                   4846:  * xmlXPathRegisterFuncNS:
                   4847:  * @ctxt:  the XPath context
                   4848:  * @name:  the function name
                   4849:  * @ns_uri:  the function namespace URI
                   4850:  * @f:  the function implementation or NULL
                   4851:  *
                   4852:  * Register a new function. If @f is NULL it unregisters the function
                   4853:  *
                   4854:  * Returns 0 in case of success, -1 in case of error
                   4855:  */
                   4856: int
                   4857: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4858:                       const xmlChar *ns_uri, xmlXPathFunction f) {
                   4859:     if (ctxt == NULL)
                   4860:        return(-1);
                   4861:     if (name == NULL)
                   4862:        return(-1);
                   4863: 
                   4864:     if (ctxt->funcHash == NULL)
                   4865:        ctxt->funcHash = xmlHashCreate(0);
                   4866:     if (ctxt->funcHash == NULL)
                   4867:        return(-1);
                   4868:     if (f == NULL)
                   4869:         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
                   4870:     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
                   4871: }
                   4872: 
                   4873: /**
                   4874:  * xmlXPathRegisterFuncLookup:
                   4875:  * @ctxt:  the XPath context
                   4876:  * @f:  the lookup function
                   4877:  * @funcCtxt:  the lookup data
                   4878:  *
                   4879:  * Registers an external mechanism to do function lookup.
                   4880:  */
                   4881: void
                   4882: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
                   4883:                            xmlXPathFuncLookupFunc f,
                   4884:                            void *funcCtxt) {
                   4885:     if (ctxt == NULL)
                   4886:        return;
                   4887:     ctxt->funcLookupFunc = f;
                   4888:     ctxt->funcLookupData = funcCtxt;
                   4889: }
                   4890: 
                   4891: /**
                   4892:  * xmlXPathFunctionLookup:
                   4893:  * @ctxt:  the XPath context
                   4894:  * @name:  the function name
                   4895:  *
                   4896:  * Search in the Function array of the context for the given
                   4897:  * function.
                   4898:  *
                   4899:  * Returns the xmlXPathFunction or NULL if not found
                   4900:  */
                   4901: xmlXPathFunction
                   4902: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
                   4903:     if (ctxt == NULL)
                   4904:        return (NULL);
                   4905: 
                   4906:     if (ctxt->funcLookupFunc != NULL) {
                   4907:        xmlXPathFunction ret;
                   4908:        xmlXPathFuncLookupFunc f;
                   4909: 
                   4910:        f = ctxt->funcLookupFunc;
                   4911:        ret = f(ctxt->funcLookupData, name, NULL);
                   4912:        if (ret != NULL)
                   4913:            return(ret);
                   4914:     }
                   4915:     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
                   4916: }
                   4917: 
                   4918: /**
                   4919:  * xmlXPathFunctionLookupNS:
                   4920:  * @ctxt:  the XPath context
                   4921:  * @name:  the function name
                   4922:  * @ns_uri:  the function namespace URI
                   4923:  *
                   4924:  * Search in the Function array of the context for the given
                   4925:  * function.
                   4926:  *
                   4927:  * Returns the xmlXPathFunction or NULL if not found
                   4928:  */
                   4929: xmlXPathFunction
                   4930: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4931:                         const xmlChar *ns_uri) {
                   4932:     xmlXPathFunction ret;
                   4933: 
                   4934:     if (ctxt == NULL)
                   4935:        return(NULL);
                   4936:     if (name == NULL)
                   4937:        return(NULL);
                   4938: 
                   4939:     if (ctxt->funcLookupFunc != NULL) {
                   4940:        xmlXPathFuncLookupFunc f;
                   4941: 
                   4942:        f = ctxt->funcLookupFunc;
                   4943:        ret = f(ctxt->funcLookupData, name, ns_uri);
                   4944:        if (ret != NULL)
                   4945:            return(ret);
                   4946:     }
                   4947: 
                   4948:     if (ctxt->funcHash == NULL)
                   4949:        return(NULL);
                   4950: 
                   4951:     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
                   4952:     return(ret);
                   4953: }
                   4954: 
                   4955: /**
                   4956:  * xmlXPathRegisteredFuncsCleanup:
                   4957:  * @ctxt:  the XPath context
                   4958:  *
                   4959:  * Cleanup the XPath context data associated to registered functions
                   4960:  */
                   4961: void
                   4962: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
                   4963:     if (ctxt == NULL)
                   4964:        return;
                   4965: 
                   4966:     xmlHashFree(ctxt->funcHash, NULL);
                   4967:     ctxt->funcHash = NULL;
                   4968: }
                   4969: 
                   4970: /************************************************************************
                   4971:  *                                                                     *
                   4972:  *                     Routines to handle Variables                    *
                   4973:  *                                                                     *
                   4974:  ************************************************************************/
                   4975: 
                   4976: /**
                   4977:  * xmlXPathRegisterVariable:
                   4978:  * @ctxt:  the XPath context
                   4979:  * @name:  the variable name
                   4980:  * @value:  the variable value or NULL
                   4981:  *
                   4982:  * Register a new variable value. If @value is NULL it unregisters
                   4983:  * the variable
                   4984:  *
                   4985:  * Returns 0 in case of success, -1 in case of error
                   4986:  */
                   4987: int
                   4988: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
                   4989:                         xmlXPathObjectPtr value) {
                   4990:     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
                   4991: }
                   4992: 
                   4993: /**
                   4994:  * xmlXPathRegisterVariableNS:
                   4995:  * @ctxt:  the XPath context
                   4996:  * @name:  the variable name
                   4997:  * @ns_uri:  the variable namespace URI
                   4998:  * @value:  the variable value or NULL
                   4999:  *
                   5000:  * Register a new variable value. If @value is NULL it unregisters
                   5001:  * the variable
                   5002:  *
                   5003:  * Returns 0 in case of success, -1 in case of error
                   5004:  */
                   5005: int
                   5006: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   5007:                           const xmlChar *ns_uri,
                   5008:                           xmlXPathObjectPtr value) {
                   5009:     if (ctxt == NULL)
                   5010:        return(-1);
                   5011:     if (name == NULL)
                   5012:        return(-1);
                   5013: 
                   5014:     if (ctxt->varHash == NULL)
                   5015:        ctxt->varHash = xmlHashCreate(0);
                   5016:     if (ctxt->varHash == NULL)
                   5017:        return(-1);
                   5018:     if (value == NULL)
                   5019:         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
                   5020:                                   (xmlHashDeallocator)xmlXPathFreeObject));
                   5021:     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
                   5022:                               (void *) value,
                   5023:                               (xmlHashDeallocator)xmlXPathFreeObject));
                   5024: }
                   5025: 
                   5026: /**
                   5027:  * xmlXPathRegisterVariableLookup:
                   5028:  * @ctxt:  the XPath context
                   5029:  * @f:  the lookup function
                   5030:  * @data:  the lookup data
                   5031:  *
                   5032:  * register an external mechanism to do variable lookup
                   5033:  */
                   5034: void
                   5035: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
                   5036:         xmlXPathVariableLookupFunc f, void *data) {
                   5037:     if (ctxt == NULL)
                   5038:        return;
                   5039:     ctxt->varLookupFunc = f;
                   5040:     ctxt->varLookupData = data;
                   5041: }
                   5042: 
                   5043: /**
                   5044:  * xmlXPathVariableLookup:
                   5045:  * @ctxt:  the XPath context
                   5046:  * @name:  the variable name
                   5047:  *
                   5048:  * Search in the Variable array of the context for the given
                   5049:  * variable value.
                   5050:  *
                   5051:  * Returns a copy of the value or NULL if not found
                   5052:  */
                   5053: xmlXPathObjectPtr
                   5054: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
                   5055:     if (ctxt == NULL)
                   5056:        return(NULL);
                   5057: 
                   5058:     if (ctxt->varLookupFunc != NULL) {
                   5059:        xmlXPathObjectPtr ret;
                   5060: 
                   5061:        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
                   5062:                (ctxt->varLookupData, name, NULL);
                   5063:        return(ret);
                   5064:     }
                   5065:     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
                   5066: }
                   5067: 
                   5068: /**
                   5069:  * xmlXPathVariableLookupNS:
                   5070:  * @ctxt:  the XPath context
                   5071:  * @name:  the variable name
                   5072:  * @ns_uri:  the variable namespace URI
                   5073:  *
                   5074:  * Search in the Variable array of the context for the given
                   5075:  * variable value.
                   5076:  *
                   5077:  * Returns the a copy of the value or NULL if not found
                   5078:  */
                   5079: xmlXPathObjectPtr
                   5080: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
                   5081:                         const xmlChar *ns_uri) {
                   5082:     if (ctxt == NULL)
                   5083:        return(NULL);
                   5084: 
                   5085:     if (ctxt->varLookupFunc != NULL) {
                   5086:        xmlXPathObjectPtr ret;
                   5087: 
                   5088:        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
                   5089:                (ctxt->varLookupData, name, ns_uri);
                   5090:        if (ret != NULL) return(ret);
                   5091:     }
                   5092: 
                   5093:     if (ctxt->varHash == NULL)
                   5094:        return(NULL);
                   5095:     if (name == NULL)
                   5096:        return(NULL);
                   5097: 
                   5098:     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
                   5099:                xmlHashLookup2(ctxt->varHash, name, ns_uri)));
                   5100: }
                   5101: 
                   5102: /**
                   5103:  * xmlXPathRegisteredVariablesCleanup:
                   5104:  * @ctxt:  the XPath context
                   5105:  *
                   5106:  * Cleanup the XPath context data associated to registered variables
                   5107:  */
                   5108: void
                   5109: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
                   5110:     if (ctxt == NULL)
                   5111:        return;
                   5112: 
                   5113:     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
                   5114:     ctxt->varHash = NULL;
                   5115: }
                   5116: 
                   5117: /**
                   5118:  * xmlXPathRegisterNs:
                   5119:  * @ctxt:  the XPath context
                   5120:  * @prefix:  the namespace prefix cannot be NULL or empty string
                   5121:  * @ns_uri:  the namespace name
                   5122:  *
                   5123:  * Register a new namespace. If @ns_uri is NULL it unregisters
                   5124:  * the namespace
                   5125:  *
                   5126:  * Returns 0 in case of success, -1 in case of error
                   5127:  */
                   5128: int
                   5129: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
                   5130:                           const xmlChar *ns_uri) {
                   5131:     if (ctxt == NULL)
                   5132:        return(-1);
                   5133:     if (prefix == NULL)
                   5134:        return(-1);
                   5135:     if (prefix[0] == 0)
                   5136:        return(-1);
                   5137: 
                   5138:     if (ctxt->nsHash == NULL)
                   5139:        ctxt->nsHash = xmlHashCreate(10);
                   5140:     if (ctxt->nsHash == NULL)
                   5141:        return(-1);
                   5142:     if (ns_uri == NULL)
                   5143:         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
                   5144:                                  (xmlHashDeallocator)xmlFree));
                   5145:     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
                   5146:                              (xmlHashDeallocator)xmlFree));
                   5147: }
                   5148: 
                   5149: /**
                   5150:  * xmlXPathNsLookup:
                   5151:  * @ctxt:  the XPath context
                   5152:  * @prefix:  the namespace prefix value
                   5153:  *
                   5154:  * Search in the namespace declaration array of the context for the given
                   5155:  * namespace name associated to the given prefix
                   5156:  *
                   5157:  * Returns the value or NULL if not found
                   5158:  */
                   5159: const xmlChar *
                   5160: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
                   5161:     if (ctxt == NULL)
                   5162:        return(NULL);
                   5163:     if (prefix == NULL)
                   5164:        return(NULL);
                   5165: 
                   5166: #ifdef XML_XML_NAMESPACE
                   5167:     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
                   5168:        return(XML_XML_NAMESPACE);
                   5169: #endif
                   5170: 
                   5171:     if (ctxt->namespaces != NULL) {
                   5172:        int i;
                   5173: 
                   5174:        for (i = 0;i < ctxt->nsNr;i++) {
                   5175:            if ((ctxt->namespaces[i] != NULL) &&
                   5176:                (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
                   5177:                return(ctxt->namespaces[i]->href);
                   5178:        }
                   5179:     }
                   5180: 
                   5181:     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
                   5182: }
                   5183: 
                   5184: /**
                   5185:  * xmlXPathRegisteredNsCleanup:
                   5186:  * @ctxt:  the XPath context
                   5187:  *
                   5188:  * Cleanup the XPath context data associated to registered variables
                   5189:  */
                   5190: void
                   5191: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
                   5192:     if (ctxt == NULL)
                   5193:        return;
                   5194: 
                   5195:     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
                   5196:     ctxt->nsHash = NULL;
                   5197: }
                   5198: 
                   5199: /************************************************************************
                   5200:  *                                                                     *
                   5201:  *                     Routines to handle Values                       *
                   5202:  *                                                                     *
                   5203:  ************************************************************************/
                   5204: 
                   5205: /* Allocations are terrible, one needs to optimize all this !!! */
                   5206: 
                   5207: /**
                   5208:  * xmlXPathNewFloat:
                   5209:  * @val:  the double value
                   5210:  *
                   5211:  * Create a new xmlXPathObjectPtr of type double and of value @val
                   5212:  *
                   5213:  * Returns the newly created object.
                   5214:  */
                   5215: xmlXPathObjectPtr
                   5216: xmlXPathNewFloat(double val) {
                   5217:     xmlXPathObjectPtr ret;
                   5218: 
                   5219:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5220:     if (ret == NULL) {
                   5221:         xmlXPathErrMemory(NULL, "creating float object\n");
                   5222:        return(NULL);
                   5223:     }
                   5224:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5225:     ret->type = XPATH_NUMBER;
                   5226:     ret->floatval = val;
                   5227: #ifdef XP_DEBUG_OBJ_USAGE
                   5228:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
                   5229: #endif
                   5230:     return(ret);
                   5231: }
                   5232: 
                   5233: /**
                   5234:  * xmlXPathNewBoolean:
                   5235:  * @val:  the boolean value
                   5236:  *
                   5237:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
                   5238:  *
                   5239:  * Returns the newly created object.
                   5240:  */
                   5241: xmlXPathObjectPtr
                   5242: xmlXPathNewBoolean(int val) {
                   5243:     xmlXPathObjectPtr ret;
                   5244: 
                   5245:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5246:     if (ret == NULL) {
                   5247:         xmlXPathErrMemory(NULL, "creating boolean object\n");
                   5248:        return(NULL);
                   5249:     }
                   5250:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5251:     ret->type = XPATH_BOOLEAN;
                   5252:     ret->boolval = (val != 0);
                   5253: #ifdef XP_DEBUG_OBJ_USAGE
                   5254:     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
                   5255: #endif
                   5256:     return(ret);
                   5257: }
                   5258: 
                   5259: /**
                   5260:  * xmlXPathNewString:
                   5261:  * @val:  the xmlChar * value
                   5262:  *
                   5263:  * Create a new xmlXPathObjectPtr of type string and of value @val
                   5264:  *
                   5265:  * Returns the newly created object.
                   5266:  */
                   5267: xmlXPathObjectPtr
                   5268: xmlXPathNewString(const xmlChar *val) {
                   5269:     xmlXPathObjectPtr ret;
                   5270: 
                   5271:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5272:     if (ret == NULL) {
                   5273:         xmlXPathErrMemory(NULL, "creating string object\n");
                   5274:        return(NULL);
                   5275:     }
                   5276:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5277:     ret->type = XPATH_STRING;
                   5278:     if (val != NULL)
                   5279:        ret->stringval = xmlStrdup(val);
                   5280:     else
                   5281:        ret->stringval = xmlStrdup((const xmlChar *)"");
                   5282: #ifdef XP_DEBUG_OBJ_USAGE
                   5283:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
                   5284: #endif
                   5285:     return(ret);
                   5286: }
                   5287: 
                   5288: /**
                   5289:  * xmlXPathWrapString:
                   5290:  * @val:  the xmlChar * value
                   5291:  *
                   5292:  * Wraps the @val string into an XPath object.
                   5293:  *
                   5294:  * Returns the newly created object.
                   5295:  */
                   5296: xmlXPathObjectPtr
                   5297: xmlXPathWrapString (xmlChar *val) {
                   5298:     xmlXPathObjectPtr ret;
                   5299: 
                   5300:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5301:     if (ret == NULL) {
                   5302:         xmlXPathErrMemory(NULL, "creating string object\n");
                   5303:        return(NULL);
                   5304:     }
                   5305:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5306:     ret->type = XPATH_STRING;
                   5307:     ret->stringval = val;
                   5308: #ifdef XP_DEBUG_OBJ_USAGE
                   5309:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
                   5310: #endif
                   5311:     return(ret);
                   5312: }
                   5313: 
                   5314: /**
                   5315:  * xmlXPathNewCString:
                   5316:  * @val:  the char * value
                   5317:  *
                   5318:  * Create a new xmlXPathObjectPtr of type string and of value @val
                   5319:  *
                   5320:  * Returns the newly created object.
                   5321:  */
                   5322: xmlXPathObjectPtr
                   5323: xmlXPathNewCString(const char *val) {
                   5324:     xmlXPathObjectPtr ret;
                   5325: 
                   5326:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5327:     if (ret == NULL) {
                   5328:         xmlXPathErrMemory(NULL, "creating string object\n");
                   5329:        return(NULL);
                   5330:     }
                   5331:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5332:     ret->type = XPATH_STRING;
                   5333:     ret->stringval = xmlStrdup(BAD_CAST val);
                   5334: #ifdef XP_DEBUG_OBJ_USAGE
                   5335:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
                   5336: #endif
                   5337:     return(ret);
                   5338: }
                   5339: 
                   5340: /**
                   5341:  * xmlXPathWrapCString:
                   5342:  * @val:  the char * value
                   5343:  *
                   5344:  * Wraps a string into an XPath object.
                   5345:  *
                   5346:  * Returns the newly created object.
                   5347:  */
                   5348: xmlXPathObjectPtr
                   5349: xmlXPathWrapCString (char * val) {
                   5350:     return(xmlXPathWrapString((xmlChar *)(val)));
                   5351: }
                   5352: 
                   5353: /**
                   5354:  * xmlXPathWrapExternal:
                   5355:  * @val:  the user data
                   5356:  *
                   5357:  * Wraps the @val data into an XPath object.
                   5358:  *
                   5359:  * Returns the newly created object.
                   5360:  */
                   5361: xmlXPathObjectPtr
                   5362: xmlXPathWrapExternal (void *val) {
                   5363:     xmlXPathObjectPtr ret;
                   5364: 
                   5365:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5366:     if (ret == NULL) {
                   5367:         xmlXPathErrMemory(NULL, "creating user object\n");
                   5368:        return(NULL);
                   5369:     }
                   5370:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                   5371:     ret->type = XPATH_USERS;
                   5372:     ret->user = val;
                   5373: #ifdef XP_DEBUG_OBJ_USAGE
                   5374:     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
                   5375: #endif
                   5376:     return(ret);
                   5377: }
                   5378: 
                   5379: /**
                   5380:  * xmlXPathObjectCopy:
                   5381:  * @val:  the original object
                   5382:  *
                   5383:  * allocate a new copy of a given object
                   5384:  *
                   5385:  * Returns the newly created object.
                   5386:  */
                   5387: xmlXPathObjectPtr
                   5388: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
                   5389:     xmlXPathObjectPtr ret;
                   5390: 
                   5391:     if (val == NULL)
                   5392:        return(NULL);
                   5393: 
                   5394:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   5395:     if (ret == NULL) {
                   5396:         xmlXPathErrMemory(NULL, "copying object\n");
                   5397:        return(NULL);
                   5398:     }
                   5399:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
                   5400: #ifdef XP_DEBUG_OBJ_USAGE
                   5401:     xmlXPathDebugObjUsageRequested(NULL, val->type);
                   5402: #endif
                   5403:     switch (val->type) {
                   5404:        case XPATH_BOOLEAN:
                   5405:        case XPATH_NUMBER:
                   5406:        case XPATH_POINT:
                   5407:        case XPATH_RANGE:
                   5408:            break;
                   5409:        case XPATH_STRING:
                   5410:            ret->stringval = xmlStrdup(val->stringval);
                   5411:            break;
                   5412:        case XPATH_XSLT_TREE:
                   5413: #if 0
                   5414: /*
                   5415:   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
                   5416:   this previous handling is no longer correct, and can cause some serious
                   5417:   problems (ref. bug 145547)
                   5418: */
                   5419:            if ((val->nodesetval != NULL) &&
                   5420:                (val->nodesetval->nodeTab != NULL)) {
                   5421:                xmlNodePtr cur, tmp;
                   5422:                xmlDocPtr top;
                   5423: 
                   5424:                ret->boolval = 1;
                   5425:                top =  xmlNewDoc(NULL);
                   5426:                top->name = (char *)
                   5427:                    xmlStrdup(val->nodesetval->nodeTab[0]->name);
                   5428:                ret->user = top;
                   5429:                if (top != NULL) {
                   5430:                    top->doc = top;
                   5431:                    cur = val->nodesetval->nodeTab[0]->children;
                   5432:                    while (cur != NULL) {
                   5433:                        tmp = xmlDocCopyNode(cur, top, 1);
                   5434:                        xmlAddChild((xmlNodePtr) top, tmp);
                   5435:                        cur = cur->next;
                   5436:                    }
                   5437:                }
                   5438: 
                   5439:                ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
                   5440:            } else
                   5441:                ret->nodesetval = xmlXPathNodeSetCreate(NULL);
                   5442:            /* Deallocate the copied tree value */
                   5443:            break;
                   5444: #endif
                   5445:        case XPATH_NODESET:
                   5446:            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
                   5447:            /* Do not deallocate the copied tree value */
                   5448:            ret->boolval = 0;
                   5449:            break;
                   5450:        case XPATH_LOCATIONSET:
                   5451: #ifdef LIBXML_XPTR_ENABLED
                   5452:        {
                   5453:            xmlLocationSetPtr loc = val->user;
                   5454:            ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
                   5455:            break;
                   5456:        }
                   5457: #endif
                   5458:         case XPATH_USERS:
                   5459:            ret->user = val->user;
                   5460:            break;
                   5461:         case XPATH_UNDEFINED:
                   5462:            xmlGenericError(xmlGenericErrorContext,
                   5463:                    "xmlXPathObjectCopy: unsupported type %d\n",
                   5464:                    val->type);
                   5465:            break;
                   5466:     }
                   5467:     return(ret);
                   5468: }
                   5469: 
                   5470: /**
                   5471:  * xmlXPathFreeObject:
                   5472:  * @obj:  the object to free
                   5473:  *
                   5474:  * Free up an xmlXPathObjectPtr object.
                   5475:  */
                   5476: void
                   5477: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
                   5478:     if (obj == NULL) return;
                   5479:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
                   5480:        if (obj->boolval) {
                   5481: #if 0
                   5482:            if (obj->user != NULL) {
                   5483:                 xmlXPathFreeNodeSet(obj->nodesetval);
                   5484:                xmlFreeNodeList((xmlNodePtr) obj->user);
                   5485:            } else
                   5486: #endif
                   5487:            obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
                   5488:            if (obj->nodesetval != NULL)
                   5489:                xmlXPathFreeValueTree(obj->nodesetval);
                   5490:        } else {
                   5491:            if (obj->nodesetval != NULL)
                   5492:                xmlXPathFreeNodeSet(obj->nodesetval);
                   5493:        }
                   5494: #ifdef LIBXML_XPTR_ENABLED
                   5495:     } else if (obj->type == XPATH_LOCATIONSET) {
                   5496:        if (obj->user != NULL)
                   5497:            xmlXPtrFreeLocationSet(obj->user);
                   5498: #endif
                   5499:     } else if (obj->type == XPATH_STRING) {
                   5500:        if (obj->stringval != NULL)
                   5501:            xmlFree(obj->stringval);
                   5502:     }
                   5503: #ifdef XP_DEBUG_OBJ_USAGE
                   5504:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
                   5505: #endif
                   5506:     xmlFree(obj);
                   5507: }
                   5508: 
                   5509: /**
                   5510:  * xmlXPathReleaseObject:
                   5511:  * @obj:  the xmlXPathObjectPtr to free or to cache
                   5512:  *
                   5513:  * Depending on the state of the cache this frees the given
                   5514:  * XPath object or stores it in the cache.
                   5515:  */
                   5516: static void
                   5517: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
                   5518: {
                   5519: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
                   5520:        sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
                   5521:     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
                   5522: 
                   5523: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
                   5524: 
                   5525:     if (obj == NULL)
                   5526:        return;
                   5527:     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
                   5528:         xmlXPathFreeObject(obj);
                   5529:     } else {
                   5530:        xmlXPathContextCachePtr cache =
                   5531:            (xmlXPathContextCachePtr) ctxt->cache;
                   5532: 
                   5533:        switch (obj->type) {
                   5534:            case XPATH_NODESET:
                   5535:            case XPATH_XSLT_TREE:
                   5536:                if (obj->nodesetval != NULL) {
                   5537:                    if (obj->boolval) {
                   5538:                        /*
                   5539:                        * It looks like the @boolval is used for
                   5540:                        * evaluation if this an XSLT Result Tree Fragment.
                   5541:                        * TODO: Check if this assumption is correct.
                   5542:                        */
                   5543:                        obj->type = XPATH_XSLT_TREE; /* just for debugging */
                   5544:                        xmlXPathFreeValueTree(obj->nodesetval);
                   5545:                        obj->nodesetval = NULL;
                   5546:                    } else if ((obj->nodesetval->nodeMax <= 40) &&
                   5547:                        (XP_CACHE_WANTS(cache->nodesetObjs,
                   5548:                                        cache->maxNodeset)))
                   5549:                    {
                   5550:                        XP_CACHE_ADD(cache->nodesetObjs, obj);
                   5551:                        goto obj_cached;
                   5552:                    } else {
                   5553:                        xmlXPathFreeNodeSet(obj->nodesetval);
                   5554:                        obj->nodesetval = NULL;
                   5555:                    }
                   5556:                }
                   5557:                break;
                   5558:            case XPATH_STRING:
                   5559:                if (obj->stringval != NULL)
                   5560:                    xmlFree(obj->stringval);
                   5561: 
                   5562:                if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
                   5563:                    XP_CACHE_ADD(cache->stringObjs, obj);
                   5564:                    goto obj_cached;
                   5565:                }
                   5566:                break;
                   5567:            case XPATH_BOOLEAN:
                   5568:                if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
                   5569:                    XP_CACHE_ADD(cache->booleanObjs, obj);
                   5570:                    goto obj_cached;
                   5571:                }
                   5572:                break;
                   5573:            case XPATH_NUMBER:
                   5574:                if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
                   5575:                    XP_CACHE_ADD(cache->numberObjs, obj);
                   5576:                    goto obj_cached;
                   5577:                }
                   5578:                break;
                   5579: #ifdef LIBXML_XPTR_ENABLED
                   5580:            case XPATH_LOCATIONSET:
                   5581:                if (obj->user != NULL) {
                   5582:                    xmlXPtrFreeLocationSet(obj->user);
                   5583:                }
                   5584:                goto free_obj;
                   5585: #endif
                   5586:            default:
                   5587:                goto free_obj;
                   5588:        }
                   5589: 
                   5590:        /*
                   5591:        * Fallback to adding to the misc-objects slot.
                   5592:        */
                   5593:        if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
                   5594:            XP_CACHE_ADD(cache->miscObjs, obj);
                   5595:        } else
                   5596:            goto free_obj;
                   5597: 
                   5598: obj_cached:
                   5599: 
                   5600: #ifdef XP_DEBUG_OBJ_USAGE
                   5601:        xmlXPathDebugObjUsageReleased(ctxt, obj->type);
                   5602: #endif
                   5603: 
                   5604:        if (obj->nodesetval != NULL) {
                   5605:            xmlNodeSetPtr tmpset = obj->nodesetval;
                   5606: 
                   5607:            /*
                   5608:            * TODO: Due to those nasty ns-nodes, we need to traverse
                   5609:            *  the list and free the ns-nodes.
                   5610:            * URGENT TODO: Check if it's actually slowing things down.
                   5611:            *  Maybe we shouldn't try to preserve the list.
                   5612:            */
                   5613:            if (tmpset->nodeNr > 1) {
                   5614:                int i;
                   5615:                xmlNodePtr node;
                   5616: 
                   5617:                for (i = 0; i < tmpset->nodeNr; i++) {
                   5618:                    node = tmpset->nodeTab[i];
                   5619:                    if ((node != NULL) &&
                   5620:                        (node->type == XML_NAMESPACE_DECL))
                   5621:                    {
                   5622:                        xmlXPathNodeSetFreeNs((xmlNsPtr) node);
                   5623:                    }
                   5624:                }
                   5625:            } else if (tmpset->nodeNr == 1) {
                   5626:                if ((tmpset->nodeTab[0] != NULL) &&
                   5627:                    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
                   5628:                    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
                   5629:            }
                   5630:            tmpset->nodeNr = 0;
                   5631:            memset(obj, 0, sizeof(xmlXPathObject));
                   5632:            obj->nodesetval = tmpset;
                   5633:        } else
                   5634:            memset(obj, 0, sizeof(xmlXPathObject));
                   5635: 
                   5636:        return;
                   5637: 
                   5638: free_obj:
                   5639:        /*
                   5640:        * Cache is full; free the object.
                   5641:        */
                   5642:        if (obj->nodesetval != NULL)
                   5643:            xmlXPathFreeNodeSet(obj->nodesetval);
                   5644: #ifdef XP_DEBUG_OBJ_USAGE
                   5645:        xmlXPathDebugObjUsageReleased(NULL, obj->type);
                   5646: #endif
                   5647:        xmlFree(obj);
                   5648:     }
                   5649:     return;
                   5650: }
                   5651: 
                   5652: 
                   5653: /************************************************************************
                   5654:  *                                                                     *
                   5655:  *                     Type Casting Routines                           *
                   5656:  *                                                                     *
                   5657:  ************************************************************************/
                   5658: 
                   5659: /**
                   5660:  * xmlXPathCastBooleanToString:
                   5661:  * @val:  a boolean
                   5662:  *
                   5663:  * Converts a boolean to its string value.
                   5664:  *
                   5665:  * Returns a newly allocated string.
                   5666:  */
                   5667: xmlChar *
                   5668: xmlXPathCastBooleanToString (int val) {
                   5669:     xmlChar *ret;
                   5670:     if (val)
                   5671:        ret = xmlStrdup((const xmlChar *) "true");
                   5672:     else
                   5673:        ret = xmlStrdup((const xmlChar *) "false");
                   5674:     return(ret);
                   5675: }
                   5676: 
                   5677: /**
                   5678:  * xmlXPathCastNumberToString:
                   5679:  * @val:  a number
                   5680:  *
                   5681:  * Converts a number to its string value.
                   5682:  *
                   5683:  * Returns a newly allocated string.
                   5684:  */
                   5685: xmlChar *
                   5686: xmlXPathCastNumberToString (double val) {
                   5687:     xmlChar *ret;
                   5688:     switch (xmlXPathIsInf(val)) {
                   5689:     case 1:
                   5690:        ret = xmlStrdup((const xmlChar *) "Infinity");
                   5691:        break;
                   5692:     case -1:
                   5693:        ret = xmlStrdup((const xmlChar *) "-Infinity");
                   5694:        break;
                   5695:     default:
                   5696:        if (xmlXPathIsNaN(val)) {
                   5697:            ret = xmlStrdup((const xmlChar *) "NaN");
                   5698:        } else if (val == 0 && xmlXPathGetSign(val) != 0) {
                   5699:            ret = xmlStrdup((const xmlChar *) "0");
                   5700:        } else {
                   5701:            /* could be improved */
                   5702:            char buf[100];
                   5703:            xmlXPathFormatNumber(val, buf, 99);
                   5704:            buf[99] = 0;
                   5705:            ret = xmlStrdup((const xmlChar *) buf);
                   5706:        }
                   5707:     }
                   5708:     return(ret);
                   5709: }
                   5710: 
                   5711: /**
                   5712:  * xmlXPathCastNodeToString:
                   5713:  * @node:  a node
                   5714:  *
                   5715:  * Converts a node to its string value.
                   5716:  *
                   5717:  * Returns a newly allocated string.
                   5718:  */
                   5719: xmlChar *
                   5720: xmlXPathCastNodeToString (xmlNodePtr node) {
                   5721: xmlChar *ret;
                   5722:     if ((ret = xmlNodeGetContent(node)) == NULL)
                   5723:        ret = xmlStrdup((const xmlChar *) "");
                   5724:     return(ret);
                   5725: }
                   5726: 
                   5727: /**
                   5728:  * xmlXPathCastNodeSetToString:
                   5729:  * @ns:  a node-set
                   5730:  *
                   5731:  * Converts a node-set to its string value.
                   5732:  *
                   5733:  * Returns a newly allocated string.
                   5734:  */
                   5735: xmlChar *
                   5736: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
                   5737:     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
                   5738:        return(xmlStrdup((const xmlChar *) ""));
                   5739: 
                   5740:     if (ns->nodeNr > 1)
                   5741:        xmlXPathNodeSetSort(ns);
                   5742:     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
                   5743: }
                   5744: 
                   5745: /**
                   5746:  * xmlXPathCastToString:
                   5747:  * @val:  an XPath object
                   5748:  *
                   5749:  * Converts an existing object to its string() equivalent
                   5750:  *
                   5751:  * Returns the allocated string value of the object, NULL in case of error.
                   5752:  *         It's up to the caller to free the string memory with xmlFree().
                   5753:  */
                   5754: xmlChar *
                   5755: xmlXPathCastToString(xmlXPathObjectPtr val) {
                   5756:     xmlChar *ret = NULL;
                   5757: 
                   5758:     if (val == NULL)
                   5759:        return(xmlStrdup((const xmlChar *) ""));
                   5760:     switch (val->type) {
                   5761:        case XPATH_UNDEFINED:
                   5762: #ifdef DEBUG_EXPR
                   5763:            xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
                   5764: #endif
                   5765:            ret = xmlStrdup((const xmlChar *) "");
                   5766:            break;
                   5767:         case XPATH_NODESET:
                   5768:         case XPATH_XSLT_TREE:
                   5769:            ret = xmlXPathCastNodeSetToString(val->nodesetval);
                   5770:            break;
                   5771:        case XPATH_STRING:
                   5772:            return(xmlStrdup(val->stringval));
                   5773:         case XPATH_BOOLEAN:
                   5774:            ret = xmlXPathCastBooleanToString(val->boolval);
                   5775:            break;
                   5776:        case XPATH_NUMBER: {
                   5777:            ret = xmlXPathCastNumberToString(val->floatval);
                   5778:            break;
                   5779:        }
                   5780:        case XPATH_USERS:
                   5781:        case XPATH_POINT:
                   5782:        case XPATH_RANGE:
                   5783:        case XPATH_LOCATIONSET:
                   5784:            TODO
                   5785:            ret = xmlStrdup((const xmlChar *) "");
                   5786:            break;
                   5787:     }
                   5788:     return(ret);
                   5789: }
                   5790: 
                   5791: /**
                   5792:  * xmlXPathConvertString:
                   5793:  * @val:  an XPath object
                   5794:  *
                   5795:  * Converts an existing object to its string() equivalent
                   5796:  *
                   5797:  * Returns the new object, the old one is freed (or the operation
                   5798:  *         is done directly on @val)
                   5799:  */
                   5800: xmlXPathObjectPtr
                   5801: xmlXPathConvertString(xmlXPathObjectPtr val) {
                   5802:     xmlChar *res = NULL;
                   5803: 
                   5804:     if (val == NULL)
                   5805:        return(xmlXPathNewCString(""));
                   5806: 
                   5807:     switch (val->type) {
                   5808:     case XPATH_UNDEFINED:
                   5809: #ifdef DEBUG_EXPR
                   5810:        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
                   5811: #endif
                   5812:        break;
                   5813:     case XPATH_NODESET:
                   5814:     case XPATH_XSLT_TREE:
                   5815:        res = xmlXPathCastNodeSetToString(val->nodesetval);
                   5816:        break;
                   5817:     case XPATH_STRING:
                   5818:        return(val);
                   5819:     case XPATH_BOOLEAN:
                   5820:        res = xmlXPathCastBooleanToString(val->boolval);
                   5821:        break;
                   5822:     case XPATH_NUMBER:
                   5823:        res = xmlXPathCastNumberToString(val->floatval);
                   5824:        break;
                   5825:     case XPATH_USERS:
                   5826:     case XPATH_POINT:
                   5827:     case XPATH_RANGE:
                   5828:     case XPATH_LOCATIONSET:
                   5829:        TODO;
                   5830:        break;
                   5831:     }
                   5832:     xmlXPathFreeObject(val);
                   5833:     if (res == NULL)
                   5834:        return(xmlXPathNewCString(""));
                   5835:     return(xmlXPathWrapString(res));
                   5836: }
                   5837: 
                   5838: /**
                   5839:  * xmlXPathCastBooleanToNumber:
                   5840:  * @val:  a boolean
                   5841:  *
                   5842:  * Converts a boolean to its number value
                   5843:  *
                   5844:  * Returns the number value
                   5845:  */
                   5846: double
                   5847: xmlXPathCastBooleanToNumber(int val) {
                   5848:     if (val)
                   5849:        return(1.0);
                   5850:     return(0.0);
                   5851: }
                   5852: 
                   5853: /**
                   5854:  * xmlXPathCastStringToNumber:
                   5855:  * @val:  a string
                   5856:  *
                   5857:  * Converts a string to its number value
                   5858:  *
                   5859:  * Returns the number value
                   5860:  */
                   5861: double
                   5862: xmlXPathCastStringToNumber(const xmlChar * val) {
                   5863:     return(xmlXPathStringEvalNumber(val));
                   5864: }
                   5865: 
                   5866: /**
                   5867:  * xmlXPathCastNodeToNumber:
                   5868:  * @node:  a node
                   5869:  *
                   5870:  * Converts a node to its number value
                   5871:  *
                   5872:  * Returns the number value
                   5873:  */
                   5874: double
                   5875: xmlXPathCastNodeToNumber (xmlNodePtr node) {
                   5876:     xmlChar *strval;
                   5877:     double ret;
                   5878: 
                   5879:     if (node == NULL)
                   5880:        return(xmlXPathNAN);
                   5881:     strval = xmlXPathCastNodeToString(node);
                   5882:     if (strval == NULL)
                   5883:        return(xmlXPathNAN);
                   5884:     ret = xmlXPathCastStringToNumber(strval);
                   5885:     xmlFree(strval);
                   5886: 
                   5887:     return(ret);
                   5888: }
                   5889: 
                   5890: /**
                   5891:  * xmlXPathCastNodeSetToNumber:
                   5892:  * @ns:  a node-set
                   5893:  *
                   5894:  * Converts a node-set to its number value
                   5895:  *
                   5896:  * Returns the number value
                   5897:  */
                   5898: double
                   5899: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
                   5900:     xmlChar *str;
                   5901:     double ret;
                   5902: 
                   5903:     if (ns == NULL)
                   5904:        return(xmlXPathNAN);
                   5905:     str = xmlXPathCastNodeSetToString(ns);
                   5906:     ret = xmlXPathCastStringToNumber(str);
                   5907:     xmlFree(str);
                   5908:     return(ret);
                   5909: }
                   5910: 
                   5911: /**
                   5912:  * xmlXPathCastToNumber:
                   5913:  * @val:  an XPath object
                   5914:  *
                   5915:  * Converts an XPath object to its number value
                   5916:  *
                   5917:  * Returns the number value
                   5918:  */
                   5919: double
                   5920: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
                   5921:     double ret = 0.0;
                   5922: 
                   5923:     if (val == NULL)
                   5924:        return(xmlXPathNAN);
                   5925:     switch (val->type) {
                   5926:     case XPATH_UNDEFINED:
                   5927: #ifdef DEGUB_EXPR
                   5928:        xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
                   5929: #endif
                   5930:        ret = xmlXPathNAN;
                   5931:        break;
                   5932:     case XPATH_NODESET:
                   5933:     case XPATH_XSLT_TREE:
                   5934:        ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
                   5935:        break;
                   5936:     case XPATH_STRING:
                   5937:        ret = xmlXPathCastStringToNumber(val->stringval);
                   5938:        break;
                   5939:     case XPATH_NUMBER:
                   5940:        ret = val->floatval;
                   5941:        break;
                   5942:     case XPATH_BOOLEAN:
                   5943:        ret = xmlXPathCastBooleanToNumber(val->boolval);
                   5944:        break;
                   5945:     case XPATH_USERS:
                   5946:     case XPATH_POINT:
                   5947:     case XPATH_RANGE:
                   5948:     case XPATH_LOCATIONSET:
                   5949:        TODO;
                   5950:        ret = xmlXPathNAN;
                   5951:        break;
                   5952:     }
                   5953:     return(ret);
                   5954: }
                   5955: 
                   5956: /**
                   5957:  * xmlXPathConvertNumber:
                   5958:  * @val:  an XPath object
                   5959:  *
                   5960:  * Converts an existing object to its number() equivalent
                   5961:  *
                   5962:  * Returns the new object, the old one is freed (or the operation
                   5963:  *         is done directly on @val)
                   5964:  */
                   5965: xmlXPathObjectPtr
                   5966: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
                   5967:     xmlXPathObjectPtr ret;
                   5968: 
                   5969:     if (val == NULL)
                   5970:        return(xmlXPathNewFloat(0.0));
                   5971:     if (val->type == XPATH_NUMBER)
                   5972:        return(val);
                   5973:     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
                   5974:     xmlXPathFreeObject(val);
                   5975:     return(ret);
                   5976: }
                   5977: 
                   5978: /**
                   5979:  * xmlXPathCastNumberToBoolean:
                   5980:  * @val:  a number
                   5981:  *
                   5982:  * Converts a number to its boolean value
                   5983:  *
                   5984:  * Returns the boolean value
                   5985:  */
                   5986: int
                   5987: xmlXPathCastNumberToBoolean (double val) {
                   5988:      if (xmlXPathIsNaN(val) || (val == 0.0))
                   5989:         return(0);
                   5990:      return(1);
                   5991: }
                   5992: 
                   5993: /**
                   5994:  * xmlXPathCastStringToBoolean:
                   5995:  * @val:  a string
                   5996:  *
                   5997:  * Converts a string to its boolean value
                   5998:  *
                   5999:  * Returns the boolean value
                   6000:  */
                   6001: int
                   6002: xmlXPathCastStringToBoolean (const xmlChar *val) {
                   6003:     if ((val == NULL) || (xmlStrlen(val) == 0))
                   6004:        return(0);
                   6005:     return(1);
                   6006: }
                   6007: 
                   6008: /**
                   6009:  * xmlXPathCastNodeSetToBoolean:
                   6010:  * @ns:  a node-set
                   6011:  *
                   6012:  * Converts a node-set to its boolean value
                   6013:  *
                   6014:  * Returns the boolean value
                   6015:  */
                   6016: int
                   6017: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
                   6018:     if ((ns == NULL) || (ns->nodeNr == 0))
                   6019:        return(0);
                   6020:     return(1);
                   6021: }
                   6022: 
                   6023: /**
                   6024:  * xmlXPathCastToBoolean:
                   6025:  * @val:  an XPath object
                   6026:  *
                   6027:  * Converts an XPath object to its boolean value
                   6028:  *
                   6029:  * Returns the boolean value
                   6030:  */
                   6031: int
                   6032: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
                   6033:     int ret = 0;
                   6034: 
                   6035:     if (val == NULL)
                   6036:        return(0);
                   6037:     switch (val->type) {
                   6038:     case XPATH_UNDEFINED:
                   6039: #ifdef DEBUG_EXPR
                   6040:        xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
                   6041: #endif
                   6042:        ret = 0;
                   6043:        break;
                   6044:     case XPATH_NODESET:
                   6045:     case XPATH_XSLT_TREE:
                   6046:        ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
                   6047:        break;
                   6048:     case XPATH_STRING:
                   6049:        ret = xmlXPathCastStringToBoolean(val->stringval);
                   6050:        break;
                   6051:     case XPATH_NUMBER:
                   6052:        ret = xmlXPathCastNumberToBoolean(val->floatval);
                   6053:        break;
                   6054:     case XPATH_BOOLEAN:
                   6055:        ret = val->boolval;
                   6056:        break;
                   6057:     case XPATH_USERS:
                   6058:     case XPATH_POINT:
                   6059:     case XPATH_RANGE:
                   6060:     case XPATH_LOCATIONSET:
                   6061:        TODO;
                   6062:        ret = 0;
                   6063:        break;
                   6064:     }
                   6065:     return(ret);
                   6066: }
                   6067: 
                   6068: 
                   6069: /**
                   6070:  * xmlXPathConvertBoolean:
                   6071:  * @val:  an XPath object
                   6072:  *
                   6073:  * Converts an existing object to its boolean() equivalent
                   6074:  *
                   6075:  * Returns the new object, the old one is freed (or the operation
                   6076:  *         is done directly on @val)
                   6077:  */
                   6078: xmlXPathObjectPtr
                   6079: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
                   6080:     xmlXPathObjectPtr ret;
                   6081: 
                   6082:     if (val == NULL)
                   6083:        return(xmlXPathNewBoolean(0));
                   6084:     if (val->type == XPATH_BOOLEAN)
                   6085:        return(val);
                   6086:     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
                   6087:     xmlXPathFreeObject(val);
                   6088:     return(ret);
                   6089: }
                   6090: 
                   6091: /************************************************************************
                   6092:  *                                                                     *
                   6093:  *             Routines to handle XPath contexts                       *
                   6094:  *                                                                     *
                   6095:  ************************************************************************/
                   6096: 
                   6097: /**
                   6098:  * xmlXPathNewContext:
                   6099:  * @doc:  the XML document
                   6100:  *
                   6101:  * Create a new xmlXPathContext
                   6102:  *
                   6103:  * Returns the xmlXPathContext just allocated. The caller will need to free it.
                   6104:  */
                   6105: xmlXPathContextPtr
                   6106: xmlXPathNewContext(xmlDocPtr doc) {
                   6107:     xmlXPathContextPtr ret;
                   6108: 
                   6109:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
                   6110:     if (ret == NULL) {
                   6111:         xmlXPathErrMemory(NULL, "creating context\n");
                   6112:        return(NULL);
                   6113:     }
                   6114:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
                   6115:     ret->doc = doc;
                   6116:     ret->node = NULL;
                   6117: 
                   6118:     ret->varHash = NULL;
                   6119: 
                   6120:     ret->nb_types = 0;
                   6121:     ret->max_types = 0;
                   6122:     ret->types = NULL;
                   6123: 
                   6124:     ret->funcHash = xmlHashCreate(0);
                   6125: 
                   6126:     ret->nb_axis = 0;
                   6127:     ret->max_axis = 0;
                   6128:     ret->axis = NULL;
                   6129: 
                   6130:     ret->nsHash = NULL;
                   6131:     ret->user = NULL;
                   6132: 
                   6133:     ret->contextSize = -1;
                   6134:     ret->proximityPosition = -1;
                   6135: 
                   6136: #ifdef XP_DEFAULT_CACHE_ON
                   6137:     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
                   6138:        xmlXPathFreeContext(ret);
                   6139:        return(NULL);
                   6140:     }
                   6141: #endif
                   6142: 
                   6143:     xmlXPathRegisterAllFunctions(ret);
                   6144: 
                   6145:     return(ret);
                   6146: }
                   6147: 
                   6148: /**
                   6149:  * xmlXPathFreeContext:
                   6150:  * @ctxt:  the context to free
                   6151:  *
                   6152:  * Free up an xmlXPathContext
                   6153:  */
                   6154: void
                   6155: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
                   6156:     if (ctxt == NULL) return;
                   6157: 
                   6158:     if (ctxt->cache != NULL)
                   6159:        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
                   6160:     xmlXPathRegisteredNsCleanup(ctxt);
                   6161:     xmlXPathRegisteredFuncsCleanup(ctxt);
                   6162:     xmlXPathRegisteredVariablesCleanup(ctxt);
                   6163:     xmlResetError(&ctxt->lastError);
                   6164:     xmlFree(ctxt);
                   6165: }
                   6166: 
                   6167: /************************************************************************
                   6168:  *                                                                     *
                   6169:  *             Routines to handle XPath parser contexts                *
                   6170:  *                                                                     *
                   6171:  ************************************************************************/
                   6172: 
                   6173: #define CHECK_CTXT(ctxt)                                               \
                   6174:     if (ctxt == NULL) {                                                \
                   6175:        __xmlRaiseError(NULL, NULL, NULL,                               \
                   6176:                NULL, NULL, XML_FROM_XPATH,                             \
                   6177:                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
                   6178:                __FILE__, __LINE__,                                     \
                   6179:                NULL, NULL, NULL, 0, 0,                                 \
                   6180:                "NULL context pointer\n");                              \
                   6181:        return(NULL);                                                   \
                   6182:     }                                                                  \
                   6183: 
                   6184: #define CHECK_CTXT_NEG(ctxt)                                           \
                   6185:     if (ctxt == NULL) {                                                \
                   6186:        __xmlRaiseError(NULL, NULL, NULL,                               \
                   6187:                NULL, NULL, XML_FROM_XPATH,                             \
                   6188:                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
                   6189:                __FILE__, __LINE__,                                     \
                   6190:                NULL, NULL, NULL, 0, 0,                                 \
                   6191:                "NULL context pointer\n");                              \
                   6192:        return(-1);                                                     \
                   6193:     }                                                                  \
                   6194: 
                   6195: 
                   6196: #define CHECK_CONTEXT(ctxt)                                            \
                   6197:     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                       \
                   6198:         (ctxt->doc->children == NULL)) {                               \
                   6199:        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
                   6200:        return(NULL);                                                   \
                   6201:     }
                   6202: 
                   6203: 
                   6204: /**
                   6205:  * xmlXPathNewParserContext:
                   6206:  * @str:  the XPath expression
                   6207:  * @ctxt:  the XPath context
                   6208:  *
                   6209:  * Create a new xmlXPathParserContext
                   6210:  *
                   6211:  * Returns the xmlXPathParserContext just allocated.
                   6212:  */
                   6213: xmlXPathParserContextPtr
                   6214: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
                   6215:     xmlXPathParserContextPtr ret;
                   6216: 
                   6217:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
                   6218:     if (ret == NULL) {
                   6219:         xmlXPathErrMemory(ctxt, "creating parser context\n");
                   6220:        return(NULL);
                   6221:     }
                   6222:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
                   6223:     ret->cur = ret->base = str;
                   6224:     ret->context = ctxt;
                   6225: 
                   6226:     ret->comp = xmlXPathNewCompExpr();
                   6227:     if (ret->comp == NULL) {
                   6228:        xmlFree(ret->valueTab);
                   6229:        xmlFree(ret);
                   6230:        return(NULL);
                   6231:     }
                   6232:     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
                   6233:         ret->comp->dict = ctxt->dict;
                   6234:        xmlDictReference(ret->comp->dict);
                   6235:     }
                   6236: 
                   6237:     return(ret);
                   6238: }
                   6239: 
                   6240: /**
                   6241:  * xmlXPathCompParserContext:
                   6242:  * @comp:  the XPath compiled expression
                   6243:  * @ctxt:  the XPath context
                   6244:  *
                   6245:  * Create a new xmlXPathParserContext when processing a compiled expression
                   6246:  *
                   6247:  * Returns the xmlXPathParserContext just allocated.
                   6248:  */
                   6249: static xmlXPathParserContextPtr
                   6250: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
                   6251:     xmlXPathParserContextPtr ret;
                   6252: 
                   6253:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
                   6254:     if (ret == NULL) {
                   6255:         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
                   6256:        return(NULL);
                   6257:     }
                   6258:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
                   6259: 
                   6260:     /* Allocate the value stack */
                   6261:     ret->valueTab = (xmlXPathObjectPtr *)
                   6262:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
                   6263:     if (ret->valueTab == NULL) {
                   6264:        xmlFree(ret);
                   6265:        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
                   6266:        return(NULL);
                   6267:     }
                   6268:     ret->valueNr = 0;
                   6269:     ret->valueMax = 10;
                   6270:     ret->value = NULL;
1.1.1.2   misho    6271:     ret->valueFrame = 0;
1.1       misho    6272: 
                   6273:     ret->context = ctxt;
                   6274:     ret->comp = comp;
                   6275: 
                   6276:     return(ret);
                   6277: }
                   6278: 
                   6279: /**
                   6280:  * xmlXPathFreeParserContext:
                   6281:  * @ctxt:  the context to free
                   6282:  *
                   6283:  * Free up an xmlXPathParserContext
                   6284:  */
                   6285: void
                   6286: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
                   6287:     if (ctxt->valueTab != NULL) {
                   6288:         xmlFree(ctxt->valueTab);
                   6289:     }
                   6290:     if (ctxt->comp != NULL) {
                   6291: #ifdef XPATH_STREAMING
                   6292:        if (ctxt->comp->stream != NULL) {
                   6293:            xmlFreePatternList(ctxt->comp->stream);
                   6294:            ctxt->comp->stream = NULL;
                   6295:        }
                   6296: #endif
                   6297:        xmlXPathFreeCompExpr(ctxt->comp);
                   6298:     }
                   6299:     xmlFree(ctxt);
                   6300: }
                   6301: 
                   6302: /************************************************************************
                   6303:  *                                                                     *
                   6304:  *             The implicit core function library                      *
                   6305:  *                                                                     *
                   6306:  ************************************************************************/
                   6307: 
                   6308: /**
                   6309:  * xmlXPathNodeValHash:
                   6310:  * @node:  a node pointer
                   6311:  *
                   6312:  * Function computing the beginning of the string value of the node,
                   6313:  * used to speed up comparisons
                   6314:  *
                   6315:  * Returns an int usable as a hash
                   6316:  */
                   6317: static unsigned int
                   6318: xmlXPathNodeValHash(xmlNodePtr node) {
                   6319:     int len = 2;
                   6320:     const xmlChar * string = NULL;
                   6321:     xmlNodePtr tmp = NULL;
                   6322:     unsigned int ret = 0;
                   6323: 
                   6324:     if (node == NULL)
                   6325:        return(0);
                   6326: 
                   6327:     if (node->type == XML_DOCUMENT_NODE) {
                   6328:        tmp = xmlDocGetRootElement((xmlDocPtr) node);
                   6329:        if (tmp == NULL)
                   6330:            node = node->children;
                   6331:        else
                   6332:            node = tmp;
                   6333: 
                   6334:        if (node == NULL)
                   6335:            return(0);
                   6336:     }
                   6337: 
                   6338:     switch (node->type) {
                   6339:        case XML_COMMENT_NODE:
                   6340:        case XML_PI_NODE:
                   6341:        case XML_CDATA_SECTION_NODE:
                   6342:        case XML_TEXT_NODE:
                   6343:            string = node->content;
                   6344:            if (string == NULL)
                   6345:                return(0);
                   6346:            if (string[0] == 0)
                   6347:                return(0);
                   6348:            return(((unsigned int) string[0]) +
                   6349:                   (((unsigned int) string[1]) << 8));
                   6350:        case XML_NAMESPACE_DECL:
                   6351:            string = ((xmlNsPtr)node)->href;
                   6352:            if (string == NULL)
                   6353:                return(0);
                   6354:            if (string[0] == 0)
                   6355:                return(0);
                   6356:            return(((unsigned int) string[0]) +
                   6357:                   (((unsigned int) string[1]) << 8));
                   6358:        case XML_ATTRIBUTE_NODE:
                   6359:            tmp = ((xmlAttrPtr) node)->children;
                   6360:            break;
                   6361:        case XML_ELEMENT_NODE:
                   6362:            tmp = node->children;
                   6363:            break;
                   6364:        default:
                   6365:            return(0);
                   6366:     }
                   6367:     while (tmp != NULL) {
                   6368:        switch (tmp->type) {
                   6369:            case XML_COMMENT_NODE:
                   6370:            case XML_PI_NODE:
                   6371:            case XML_CDATA_SECTION_NODE:
                   6372:            case XML_TEXT_NODE:
                   6373:                string = tmp->content;
                   6374:                break;
                   6375:            case XML_NAMESPACE_DECL:
                   6376:                string = ((xmlNsPtr)tmp)->href;
                   6377:                break;
                   6378:            default:
                   6379:                break;
                   6380:        }
                   6381:        if ((string != NULL) && (string[0] != 0)) {
                   6382:            if (len == 1) {
                   6383:                return(ret + (((unsigned int) string[0]) << 8));
                   6384:            }
                   6385:            if (string[1] == 0) {
                   6386:                len = 1;
                   6387:                ret = (unsigned int) string[0];
                   6388:            } else {
                   6389:                return(((unsigned int) string[0]) +
                   6390:                       (((unsigned int) string[1]) << 8));
                   6391:            }
                   6392:        }
                   6393:        /*
                   6394:         * Skip to next node
                   6395:         */
                   6396:        if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
                   6397:            if (tmp->children->type != XML_ENTITY_DECL) {
                   6398:                tmp = tmp->children;
                   6399:                continue;
                   6400:            }
                   6401:        }
                   6402:        if (tmp == node)
                   6403:            break;
                   6404: 
                   6405:        if (tmp->next != NULL) {
                   6406:            tmp = tmp->next;
                   6407:            continue;
                   6408:        }
                   6409: 
                   6410:        do {
                   6411:            tmp = tmp->parent;
                   6412:            if (tmp == NULL)
                   6413:                break;
                   6414:            if (tmp == node) {
                   6415:                tmp = NULL;
                   6416:                break;
                   6417:            }
                   6418:            if (tmp->next != NULL) {
                   6419:                tmp = tmp->next;
                   6420:                break;
                   6421:            }
                   6422:        } while (tmp != NULL);
                   6423:     }
                   6424:     return(ret);
                   6425: }
                   6426: 
                   6427: /**
                   6428:  * xmlXPathStringHash:
                   6429:  * @string:  a string
                   6430:  *
                   6431:  * Function computing the beginning of the string value of the node,
                   6432:  * used to speed up comparisons
                   6433:  *
                   6434:  * Returns an int usable as a hash
                   6435:  */
                   6436: static unsigned int
                   6437: xmlXPathStringHash(const xmlChar * string) {
                   6438:     if (string == NULL)
                   6439:        return((unsigned int) 0);
                   6440:     if (string[0] == 0)
                   6441:        return(0);
                   6442:     return(((unsigned int) string[0]) +
                   6443:           (((unsigned int) string[1]) << 8));
                   6444: }
                   6445: 
                   6446: /**
                   6447:  * xmlXPathCompareNodeSetFloat:
                   6448:  * @ctxt:  the XPath Parser context
                   6449:  * @inf:  less than (1) or greater than (0)
                   6450:  * @strict:  is the comparison strict
                   6451:  * @arg:  the node set
                   6452:  * @f:  the value
                   6453:  *
                   6454:  * Implement the compare operation between a nodeset and a number
                   6455:  *     @ns < @val    (1, 1, ...
                   6456:  *     @ns <= @val   (1, 0, ...
                   6457:  *     @ns > @val    (0, 1, ...
                   6458:  *     @ns >= @val   (0, 0, ...
                   6459:  *
                   6460:  * If one object to be compared is a node-set and the other is a number,
                   6461:  * then the comparison will be true if and only if there is a node in the
                   6462:  * node-set such that the result of performing the comparison on the number
                   6463:  * to be compared and on the result of converting the string-value of that
                   6464:  * node to a number using the number function is true.
                   6465:  *
                   6466:  * Returns 0 or 1 depending on the results of the test.
                   6467:  */
                   6468: static int
                   6469: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
                   6470:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
                   6471:     int i, ret = 0;
                   6472:     xmlNodeSetPtr ns;
                   6473:     xmlChar *str2;
                   6474: 
                   6475:     if ((f == NULL) || (arg == NULL) ||
                   6476:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
                   6477:        xmlXPathReleaseObject(ctxt->context, arg);
                   6478:        xmlXPathReleaseObject(ctxt->context, f);
                   6479:         return(0);
                   6480:     }
                   6481:     ns = arg->nodesetval;
                   6482:     if (ns != NULL) {
                   6483:        for (i = 0;i < ns->nodeNr;i++) {
                   6484:             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
                   6485:             if (str2 != NULL) {
                   6486:                 valuePush(ctxt,
                   6487:                           xmlXPathCacheNewString(ctxt->context, str2));
                   6488:                 xmlFree(str2);
                   6489:                 xmlXPathNumberFunction(ctxt, 1);
                   6490:                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
                   6491:                 ret = xmlXPathCompareValues(ctxt, inf, strict);
                   6492:                 if (ret)
                   6493:                     break;
                   6494:             }
                   6495:        }
                   6496:     }
                   6497:     xmlXPathReleaseObject(ctxt->context, arg);
                   6498:     xmlXPathReleaseObject(ctxt->context, f);
                   6499:     return(ret);
                   6500: }
                   6501: 
                   6502: /**
                   6503:  * xmlXPathCompareNodeSetString:
                   6504:  * @ctxt:  the XPath Parser context
                   6505:  * @inf:  less than (1) or greater than (0)
                   6506:  * @strict:  is the comparison strict
                   6507:  * @arg:  the node set
                   6508:  * @s:  the value
                   6509:  *
                   6510:  * Implement the compare operation between a nodeset and a string
                   6511:  *     @ns < @val    (1, 1, ...
                   6512:  *     @ns <= @val   (1, 0, ...
                   6513:  *     @ns > @val    (0, 1, ...
                   6514:  *     @ns >= @val   (0, 0, ...
                   6515:  *
                   6516:  * If one object to be compared is a node-set and the other is a string,
                   6517:  * then the comparison will be true if and only if there is a node in
                   6518:  * the node-set such that the result of performing the comparison on the
                   6519:  * string-value of the node and the other string is true.
                   6520:  *
                   6521:  * Returns 0 or 1 depending on the results of the test.
                   6522:  */
                   6523: static int
                   6524: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
                   6525:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
                   6526:     int i, ret = 0;
                   6527:     xmlNodeSetPtr ns;
                   6528:     xmlChar *str2;
                   6529: 
                   6530:     if ((s == NULL) || (arg == NULL) ||
                   6531:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
                   6532:        xmlXPathReleaseObject(ctxt->context, arg);
                   6533:        xmlXPathReleaseObject(ctxt->context, s);
                   6534:         return(0);
                   6535:     }
                   6536:     ns = arg->nodesetval;
                   6537:     if (ns != NULL) {
                   6538:        for (i = 0;i < ns->nodeNr;i++) {
                   6539:             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
                   6540:             if (str2 != NULL) {
                   6541:                 valuePush(ctxt,
                   6542:                           xmlXPathCacheNewString(ctxt->context, str2));
                   6543:                 xmlFree(str2);
                   6544:                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
                   6545:                 ret = xmlXPathCompareValues(ctxt, inf, strict);
                   6546:                 if (ret)
                   6547:                     break;
                   6548:             }
                   6549:        }
                   6550:     }
                   6551:     xmlXPathReleaseObject(ctxt->context, arg);
                   6552:     xmlXPathReleaseObject(ctxt->context, s);
                   6553:     return(ret);
                   6554: }
                   6555: 
                   6556: /**
                   6557:  * xmlXPathCompareNodeSets:
                   6558:  * @inf:  less than (1) or greater than (0)
                   6559:  * @strict:  is the comparison strict
                   6560:  * @arg1:  the first node set object
                   6561:  * @arg2:  the second node set object
                   6562:  *
                   6563:  * Implement the compare operation on nodesets:
                   6564:  *
                   6565:  * If both objects to be compared are node-sets, then the comparison
                   6566:  * will be true if and only if there is a node in the first node-set
                   6567:  * and a node in the second node-set such that the result of performing
                   6568:  * the comparison on the string-values of the two nodes is true.
                   6569:  * ....
                   6570:  * When neither object to be compared is a node-set and the operator
                   6571:  * is <=, <, >= or >, then the objects are compared by converting both
                   6572:  * objects to numbers and comparing the numbers according to IEEE 754.
                   6573:  * ....
                   6574:  * The number function converts its argument to a number as follows:
                   6575:  *  - a string that consists of optional whitespace followed by an
                   6576:  *    optional minus sign followed by a Number followed by whitespace
                   6577:  *    is converted to the IEEE 754 number that is nearest (according
                   6578:  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
                   6579:  *    represented by the string; any other string is converted to NaN
                   6580:  *
                   6581:  * Conclusion all nodes need to be converted first to their string value
                   6582:  * and then the comparison must be done when possible
                   6583:  */
                   6584: static int
                   6585: xmlXPathCompareNodeSets(int inf, int strict,
                   6586:                        xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
                   6587:     int i, j, init = 0;
                   6588:     double val1;
                   6589:     double *values2;
                   6590:     int ret = 0;
                   6591:     xmlNodeSetPtr ns1;
                   6592:     xmlNodeSetPtr ns2;
                   6593: 
                   6594:     if ((arg1 == NULL) ||
                   6595:        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
                   6596:        xmlXPathFreeObject(arg2);
                   6597:         return(0);
                   6598:     }
                   6599:     if ((arg2 == NULL) ||
                   6600:        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
                   6601:        xmlXPathFreeObject(arg1);
                   6602:        xmlXPathFreeObject(arg2);
                   6603:         return(0);
                   6604:     }
                   6605: 
                   6606:     ns1 = arg1->nodesetval;
                   6607:     ns2 = arg2->nodesetval;
                   6608: 
                   6609:     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
                   6610:        xmlXPathFreeObject(arg1);
                   6611:        xmlXPathFreeObject(arg2);
                   6612:        return(0);
                   6613:     }
                   6614:     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
                   6615:        xmlXPathFreeObject(arg1);
                   6616:        xmlXPathFreeObject(arg2);
                   6617:        return(0);
                   6618:     }
                   6619: 
                   6620:     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
                   6621:     if (values2 == NULL) {
                   6622:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6623:        xmlXPathFreeObject(arg1);
                   6624:        xmlXPathFreeObject(arg2);
                   6625:        return(0);
                   6626:     }
                   6627:     for (i = 0;i < ns1->nodeNr;i++) {
                   6628:        val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
                   6629:        if (xmlXPathIsNaN(val1))
                   6630:            continue;
                   6631:        for (j = 0;j < ns2->nodeNr;j++) {
                   6632:            if (init == 0) {
                   6633:                values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
                   6634:            }
                   6635:            if (xmlXPathIsNaN(values2[j]))
                   6636:                continue;
                   6637:            if (inf && strict)
                   6638:                ret = (val1 < values2[j]);
                   6639:            else if (inf && !strict)
                   6640:                ret = (val1 <= values2[j]);
                   6641:            else if (!inf && strict)
                   6642:                ret = (val1 > values2[j]);
                   6643:            else if (!inf && !strict)
                   6644:                ret = (val1 >= values2[j]);
                   6645:            if (ret)
                   6646:                break;
                   6647:        }
                   6648:        if (ret)
                   6649:            break;
                   6650:        init = 1;
                   6651:     }
                   6652:     xmlFree(values2);
                   6653:     xmlXPathFreeObject(arg1);
                   6654:     xmlXPathFreeObject(arg2);
                   6655:     return(ret);
                   6656: }
                   6657: 
                   6658: /**
                   6659:  * xmlXPathCompareNodeSetValue:
                   6660:  * @ctxt:  the XPath Parser context
                   6661:  * @inf:  less than (1) or greater than (0)
                   6662:  * @strict:  is the comparison strict
                   6663:  * @arg:  the node set
                   6664:  * @val:  the value
                   6665:  *
                   6666:  * Implement the compare operation between a nodeset and a value
                   6667:  *     @ns < @val    (1, 1, ...
                   6668:  *     @ns <= @val   (1, 0, ...
                   6669:  *     @ns > @val    (0, 1, ...
                   6670:  *     @ns >= @val   (0, 0, ...
                   6671:  *
                   6672:  * If one object to be compared is a node-set and the other is a boolean,
                   6673:  * then the comparison will be true if and only if the result of performing
                   6674:  * the comparison on the boolean and on the result of converting
                   6675:  * the node-set to a boolean using the boolean function is true.
                   6676:  *
                   6677:  * Returns 0 or 1 depending on the results of the test.
                   6678:  */
                   6679: static int
                   6680: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
                   6681:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
                   6682:     if ((val == NULL) || (arg == NULL) ||
                   6683:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
                   6684:         return(0);
                   6685: 
                   6686:     switch(val->type) {
                   6687:         case XPATH_NUMBER:
                   6688:            return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
                   6689:         case XPATH_NODESET:
                   6690:         case XPATH_XSLT_TREE:
                   6691:            return(xmlXPathCompareNodeSets(inf, strict, arg, val));
                   6692:         case XPATH_STRING:
                   6693:            return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
                   6694:         case XPATH_BOOLEAN:
                   6695:            valuePush(ctxt, arg);
                   6696:            xmlXPathBooleanFunction(ctxt, 1);
                   6697:            valuePush(ctxt, val);
                   6698:            return(xmlXPathCompareValues(ctxt, inf, strict));
                   6699:        default:
                   6700:            TODO
                   6701:     }
                   6702:     return(0);
                   6703: }
                   6704: 
                   6705: /**
                   6706:  * xmlXPathEqualNodeSetString:
                   6707:  * @arg:  the nodeset object argument
                   6708:  * @str:  the string to compare to.
                   6709:  * @neq:  flag to show whether for '=' (0) or '!=' (1)
                   6710:  *
                   6711:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   6712:  * If one object to be compared is a node-set and the other is a string,
                   6713:  * then the comparison will be true if and only if there is a node in
                   6714:  * the node-set such that the result of performing the comparison on the
                   6715:  * string-value of the node and the other string is true.
                   6716:  *
                   6717:  * Returns 0 or 1 depending on the results of the test.
                   6718:  */
                   6719: static int
                   6720: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
                   6721: {
                   6722:     int i;
                   6723:     xmlNodeSetPtr ns;
                   6724:     xmlChar *str2;
                   6725:     unsigned int hash;
                   6726: 
                   6727:     if ((str == NULL) || (arg == NULL) ||
                   6728:         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
                   6729:         return (0);
                   6730:     ns = arg->nodesetval;
                   6731:     /*
                   6732:      * A NULL nodeset compared with a string is always false
                   6733:      * (since there is no node equal, and no node not equal)
                   6734:      */
                   6735:     if ((ns == NULL) || (ns->nodeNr <= 0) )
                   6736:         return (0);
                   6737:     hash = xmlXPathStringHash(str);
                   6738:     for (i = 0; i < ns->nodeNr; i++) {
                   6739:         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
                   6740:             str2 = xmlNodeGetContent(ns->nodeTab[i]);
                   6741:             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
                   6742:                 xmlFree(str2);
                   6743:                if (neq)
                   6744:                    continue;
                   6745:                 return (1);
                   6746:            } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
                   6747:                if (neq)
                   6748:                    continue;
                   6749:                 return (1);
                   6750:             } else if (neq) {
                   6751:                if (str2 != NULL)
                   6752:                    xmlFree(str2);
                   6753:                return (1);
                   6754:            }
                   6755:             if (str2 != NULL)
                   6756:                 xmlFree(str2);
                   6757:         } else if (neq)
                   6758:            return (1);
                   6759:     }
                   6760:     return (0);
                   6761: }
                   6762: 
                   6763: /**
                   6764:  * xmlXPathEqualNodeSetFloat:
                   6765:  * @arg:  the nodeset object argument
                   6766:  * @f:  the float to compare to
                   6767:  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
                   6768:  *
                   6769:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   6770:  * If one object to be compared is a node-set and the other is a number,
                   6771:  * then the comparison will be true if and only if there is a node in
                   6772:  * the node-set such that the result of performing the comparison on the
                   6773:  * number to be compared and on the result of converting the string-value
                   6774:  * of that node to a number using the number function is true.
                   6775:  *
                   6776:  * Returns 0 or 1 depending on the results of the test.
                   6777:  */
                   6778: static int
                   6779: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
                   6780:     xmlXPathObjectPtr arg, double f, int neq) {
                   6781:   int i, ret=0;
                   6782:   xmlNodeSetPtr ns;
                   6783:   xmlChar *str2;
                   6784:   xmlXPathObjectPtr val;
                   6785:   double v;
                   6786: 
                   6787:     if ((arg == NULL) ||
                   6788:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
                   6789:         return(0);
                   6790: 
                   6791:     ns = arg->nodesetval;
                   6792:     if (ns != NULL) {
                   6793:        for (i=0;i<ns->nodeNr;i++) {
                   6794:            str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
                   6795:            if (str2 != NULL) {
                   6796:                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
                   6797:                xmlFree(str2);
                   6798:                xmlXPathNumberFunction(ctxt, 1);
                   6799:                val = valuePop(ctxt);
                   6800:                v = val->floatval;
                   6801:                xmlXPathReleaseObject(ctxt->context, val);
                   6802:                if (!xmlXPathIsNaN(v)) {
                   6803:                    if ((!neq) && (v==f)) {
                   6804:                        ret = 1;
                   6805:                        break;
                   6806:                    } else if ((neq) && (v!=f)) {
                   6807:                        ret = 1;
                   6808:                        break;
                   6809:                    }
                   6810:                } else {        /* NaN is unequal to any value */
                   6811:                    if (neq)
                   6812:                        ret = 1;
                   6813:                }
                   6814:            }
                   6815:        }
                   6816:     }
                   6817: 
                   6818:     return(ret);
                   6819: }
                   6820: 
                   6821: 
                   6822: /**
                   6823:  * xmlXPathEqualNodeSets:
                   6824:  * @arg1:  first nodeset object argument
                   6825:  * @arg2:  second nodeset object argument
                   6826:  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
                   6827:  *
                   6828:  * Implement the equal / not equal operation on XPath nodesets:
                   6829:  * @arg1 == @arg2  or  @arg1 != @arg2
                   6830:  * If both objects to be compared are node-sets, then the comparison
                   6831:  * will be true if and only if there is a node in the first node-set and
                   6832:  * a node in the second node-set such that the result of performing the
                   6833:  * comparison on the string-values of the two nodes is true.
                   6834:  *
                   6835:  * (needless to say, this is a costly operation)
                   6836:  *
                   6837:  * Returns 0 or 1 depending on the results of the test.
                   6838:  */
                   6839: static int
                   6840: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
                   6841:     int i, j;
                   6842:     unsigned int *hashs1;
                   6843:     unsigned int *hashs2;
                   6844:     xmlChar **values1;
                   6845:     xmlChar **values2;
                   6846:     int ret = 0;
                   6847:     xmlNodeSetPtr ns1;
                   6848:     xmlNodeSetPtr ns2;
                   6849: 
                   6850:     if ((arg1 == NULL) ||
                   6851:        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
                   6852:         return(0);
                   6853:     if ((arg2 == NULL) ||
                   6854:        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
                   6855:         return(0);
                   6856: 
                   6857:     ns1 = arg1->nodesetval;
                   6858:     ns2 = arg2->nodesetval;
                   6859: 
                   6860:     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
                   6861:        return(0);
                   6862:     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
                   6863:        return(0);
                   6864: 
                   6865:     /*
                   6866:      * for equal, check if there is a node pertaining to both sets
                   6867:      */
                   6868:     if (neq == 0)
                   6869:        for (i = 0;i < ns1->nodeNr;i++)
                   6870:            for (j = 0;j < ns2->nodeNr;j++)
                   6871:                if (ns1->nodeTab[i] == ns2->nodeTab[j])
                   6872:                    return(1);
                   6873: 
                   6874:     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
                   6875:     if (values1 == NULL) {
                   6876:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6877:        return(0);
                   6878:     }
                   6879:     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
                   6880:     if (hashs1 == NULL) {
                   6881:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6882:        xmlFree(values1);
                   6883:        return(0);
                   6884:     }
                   6885:     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
                   6886:     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
                   6887:     if (values2 == NULL) {
                   6888:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6889:        xmlFree(hashs1);
                   6890:        xmlFree(values1);
                   6891:        return(0);
                   6892:     }
                   6893:     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
                   6894:     if (hashs2 == NULL) {
                   6895:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
                   6896:        xmlFree(hashs1);
                   6897:        xmlFree(values1);
                   6898:        xmlFree(values2);
                   6899:        return(0);
                   6900:     }
                   6901:     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
                   6902:     for (i = 0;i < ns1->nodeNr;i++) {
                   6903:        hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
                   6904:        for (j = 0;j < ns2->nodeNr;j++) {
                   6905:            if (i == 0)
                   6906:                hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
                   6907:            if (hashs1[i] != hashs2[j]) {
                   6908:                if (neq) {
                   6909:                    ret = 1;
                   6910:                    break;
                   6911:                }
                   6912:            }
                   6913:            else {
                   6914:                if (values1[i] == NULL)
                   6915:                    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
                   6916:                if (values2[j] == NULL)
                   6917:                    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
                   6918:                ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
                   6919:                if (ret)
                   6920:                    break;
                   6921:            }
                   6922:        }
                   6923:        if (ret)
                   6924:            break;
                   6925:     }
                   6926:     for (i = 0;i < ns1->nodeNr;i++)
                   6927:        if (values1[i] != NULL)
                   6928:            xmlFree(values1[i]);
                   6929:     for (j = 0;j < ns2->nodeNr;j++)
                   6930:        if (values2[j] != NULL)
                   6931:            xmlFree(values2[j]);
                   6932:     xmlFree(values1);
                   6933:     xmlFree(values2);
                   6934:     xmlFree(hashs1);
                   6935:     xmlFree(hashs2);
                   6936:     return(ret);
                   6937: }
                   6938: 
                   6939: static int
                   6940: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
                   6941:   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
                   6942:     int ret = 0;
                   6943:     /*
                   6944:      *At this point we are assured neither arg1 nor arg2
                   6945:      *is a nodeset, so we can just pick the appropriate routine.
                   6946:      */
                   6947:     switch (arg1->type) {
                   6948:         case XPATH_UNDEFINED:
                   6949: #ifdef DEBUG_EXPR
                   6950:            xmlGenericError(xmlGenericErrorContext,
                   6951:                    "Equal: undefined\n");
                   6952: #endif
                   6953:            break;
                   6954:         case XPATH_BOOLEAN:
                   6955:            switch (arg2->type) {
                   6956:                case XPATH_UNDEFINED:
                   6957: #ifdef DEBUG_EXPR
                   6958:                    xmlGenericError(xmlGenericErrorContext,
                   6959:                            "Equal: undefined\n");
                   6960: #endif
                   6961:                    break;
                   6962:                case XPATH_BOOLEAN:
                   6963: #ifdef DEBUG_EXPR
                   6964:                    xmlGenericError(xmlGenericErrorContext,
                   6965:                            "Equal: %d boolean %d \n",
                   6966:                            arg1->boolval, arg2->boolval);
                   6967: #endif
                   6968:                    ret = (arg1->boolval == arg2->boolval);
                   6969:                    break;
                   6970:                case XPATH_NUMBER:
                   6971:                    ret = (arg1->boolval ==
                   6972:                           xmlXPathCastNumberToBoolean(arg2->floatval));
                   6973:                    break;
                   6974:                case XPATH_STRING:
                   6975:                    if ((arg2->stringval == NULL) ||
                   6976:                        (arg2->stringval[0] == 0)) ret = 0;
                   6977:                    else
                   6978:                        ret = 1;
                   6979:                    ret = (arg1->boolval == ret);
                   6980:                    break;
                   6981:                case XPATH_USERS:
                   6982:                case XPATH_POINT:
                   6983:                case XPATH_RANGE:
                   6984:                case XPATH_LOCATIONSET:
                   6985:                    TODO
                   6986:                    break;
                   6987:                case XPATH_NODESET:
                   6988:                case XPATH_XSLT_TREE:
                   6989:                    break;
                   6990:            }
                   6991:            break;
                   6992:         case XPATH_NUMBER:
                   6993:            switch (arg2->type) {
                   6994:                case XPATH_UNDEFINED:
                   6995: #ifdef DEBUG_EXPR
                   6996:                    xmlGenericError(xmlGenericErrorContext,
                   6997:                            "Equal: undefined\n");
                   6998: #endif
                   6999:                    break;
                   7000:                case XPATH_BOOLEAN:
                   7001:                    ret = (arg2->boolval==
                   7002:                           xmlXPathCastNumberToBoolean(arg1->floatval));
                   7003:                    break;
                   7004:                case XPATH_STRING:
                   7005:                    valuePush(ctxt, arg2);
                   7006:                    xmlXPathNumberFunction(ctxt, 1);
                   7007:                    arg2 = valuePop(ctxt);
                   7008:                    /* no break on purpose */
                   7009:                case XPATH_NUMBER:
                   7010:                    /* Hand check NaN and Infinity equalities */
                   7011:                    if (xmlXPathIsNaN(arg1->floatval) ||
                   7012:                            xmlXPathIsNaN(arg2->floatval)) {
                   7013:                        ret = 0;
                   7014:                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
                   7015:                        if (xmlXPathIsInf(arg2->floatval) == 1)
                   7016:                            ret = 1;
                   7017:                        else
                   7018:                            ret = 0;
                   7019:                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
                   7020:                        if (xmlXPathIsInf(arg2->floatval) == -1)
                   7021:                            ret = 1;
                   7022:                        else
                   7023:                            ret = 0;
                   7024:                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
                   7025:                        if (xmlXPathIsInf(arg1->floatval) == 1)
                   7026:                            ret = 1;
                   7027:                        else
                   7028:                            ret = 0;
                   7029:                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
                   7030:                        if (xmlXPathIsInf(arg1->floatval) == -1)
                   7031:                            ret = 1;
                   7032:                        else
                   7033:                            ret = 0;
                   7034:                    } else {
                   7035:                        ret = (arg1->floatval == arg2->floatval);
                   7036:                    }
                   7037:                    break;
                   7038:                case XPATH_USERS:
                   7039:                case XPATH_POINT:
                   7040:                case XPATH_RANGE:
                   7041:                case XPATH_LOCATIONSET:
                   7042:                    TODO
                   7043:                    break;
                   7044:                case XPATH_NODESET:
                   7045:                case XPATH_XSLT_TREE:
                   7046:                    break;
                   7047:            }
                   7048:            break;
                   7049:         case XPATH_STRING:
                   7050:            switch (arg2->type) {
                   7051:                case XPATH_UNDEFINED:
                   7052: #ifdef DEBUG_EXPR
                   7053:                    xmlGenericError(xmlGenericErrorContext,
                   7054:                            "Equal: undefined\n");
                   7055: #endif
                   7056:                    break;
                   7057:                case XPATH_BOOLEAN:
                   7058:                    if ((arg1->stringval == NULL) ||
                   7059:                        (arg1->stringval[0] == 0)) ret = 0;
                   7060:                    else
                   7061:                        ret = 1;
                   7062:                    ret = (arg2->boolval == ret);
                   7063:                    break;
                   7064:                case XPATH_STRING:
                   7065:                    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
                   7066:                    break;
                   7067:                case XPATH_NUMBER:
                   7068:                    valuePush(ctxt, arg1);
                   7069:                    xmlXPathNumberFunction(ctxt, 1);
                   7070:                    arg1 = valuePop(ctxt);
                   7071:                    /* Hand check NaN and Infinity equalities */
                   7072:                    if (xmlXPathIsNaN(arg1->floatval) ||
                   7073:                            xmlXPathIsNaN(arg2->floatval)) {
                   7074:                        ret = 0;
                   7075:                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
                   7076:                        if (xmlXPathIsInf(arg2->floatval) == 1)
                   7077:                            ret = 1;
                   7078:                        else
                   7079:                            ret = 0;
                   7080:                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
                   7081:                        if (xmlXPathIsInf(arg2->floatval) == -1)
                   7082:                            ret = 1;
                   7083:                        else
                   7084:                            ret = 0;
                   7085:                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
                   7086:                        if (xmlXPathIsInf(arg1->floatval) == 1)
                   7087:                            ret = 1;
                   7088:                        else
                   7089:                            ret = 0;
                   7090:                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
                   7091:                        if (xmlXPathIsInf(arg1->floatval) == -1)
                   7092:                            ret = 1;
                   7093:                        else
                   7094:                            ret = 0;
                   7095:                    } else {
                   7096:                        ret = (arg1->floatval == arg2->floatval);
                   7097:                    }
                   7098:                    break;
                   7099:                case XPATH_USERS:
                   7100:                case XPATH_POINT:
                   7101:                case XPATH_RANGE:
                   7102:                case XPATH_LOCATIONSET:
                   7103:                    TODO
                   7104:                    break;
                   7105:                case XPATH_NODESET:
                   7106:                case XPATH_XSLT_TREE:
                   7107:                    break;
                   7108:            }
                   7109:            break;
                   7110:         case XPATH_USERS:
                   7111:        case XPATH_POINT:
                   7112:        case XPATH_RANGE:
                   7113:        case XPATH_LOCATIONSET:
                   7114:            TODO
                   7115:            break;
                   7116:        case XPATH_NODESET:
                   7117:        case XPATH_XSLT_TREE:
                   7118:            break;
                   7119:     }
                   7120:     xmlXPathReleaseObject(ctxt->context, arg1);
                   7121:     xmlXPathReleaseObject(ctxt->context, arg2);
                   7122:     return(ret);
                   7123: }
                   7124: 
                   7125: /**
                   7126:  * xmlXPathEqualValues:
                   7127:  * @ctxt:  the XPath Parser context
                   7128:  *
                   7129:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   7130:  *
                   7131:  * Returns 0 or 1 depending on the results of the test.
                   7132:  */
                   7133: int
                   7134: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
                   7135:     xmlXPathObjectPtr arg1, arg2, argtmp;
                   7136:     int ret = 0;
                   7137: 
                   7138:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
                   7139:     arg2 = valuePop(ctxt);
                   7140:     arg1 = valuePop(ctxt);
                   7141:     if ((arg1 == NULL) || (arg2 == NULL)) {
                   7142:        if (arg1 != NULL)
                   7143:            xmlXPathReleaseObject(ctxt->context, arg1);
                   7144:        else
                   7145:            xmlXPathReleaseObject(ctxt->context, arg2);
                   7146:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7147:     }
                   7148: 
                   7149:     if (arg1 == arg2) {
                   7150: #ifdef DEBUG_EXPR
                   7151:         xmlGenericError(xmlGenericErrorContext,
                   7152:                "Equal: by pointer\n");
                   7153: #endif
                   7154:        xmlXPathFreeObject(arg1);
                   7155:         return(1);
                   7156:     }
                   7157: 
                   7158:     /*
                   7159:      *If either argument is a nodeset, it's a 'special case'
                   7160:      */
                   7161:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
                   7162:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7163:        /*
                   7164:         *Hack it to assure arg1 is the nodeset
                   7165:         */
                   7166:        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
                   7167:                argtmp = arg2;
                   7168:                arg2 = arg1;
                   7169:                arg1 = argtmp;
                   7170:        }
                   7171:        switch (arg2->type) {
                   7172:            case XPATH_UNDEFINED:
                   7173: #ifdef DEBUG_EXPR
                   7174:                xmlGenericError(xmlGenericErrorContext,
                   7175:                        "Equal: undefined\n");
                   7176: #endif
                   7177:                break;
                   7178:            case XPATH_NODESET:
                   7179:            case XPATH_XSLT_TREE:
                   7180:                ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
                   7181:                break;
                   7182:            case XPATH_BOOLEAN:
                   7183:                if ((arg1->nodesetval == NULL) ||
                   7184:                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
                   7185:                else
                   7186:                    ret = 1;
                   7187:                ret = (ret == arg2->boolval);
                   7188:                break;
                   7189:            case XPATH_NUMBER:
                   7190:                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
                   7191:                break;
                   7192:            case XPATH_STRING:
                   7193:                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
                   7194:                break;
                   7195:            case XPATH_USERS:
                   7196:            case XPATH_POINT:
                   7197:            case XPATH_RANGE:
                   7198:            case XPATH_LOCATIONSET:
                   7199:                TODO
                   7200:                break;
                   7201:        }
                   7202:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7203:        xmlXPathReleaseObject(ctxt->context, arg2);
                   7204:        return(ret);
                   7205:     }
                   7206: 
                   7207:     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
                   7208: }
                   7209: 
                   7210: /**
                   7211:  * xmlXPathNotEqualValues:
                   7212:  * @ctxt:  the XPath Parser context
                   7213:  *
                   7214:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   7215:  *
                   7216:  * Returns 0 or 1 depending on the results of the test.
                   7217:  */
                   7218: int
                   7219: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
                   7220:     xmlXPathObjectPtr arg1, arg2, argtmp;
                   7221:     int ret = 0;
                   7222: 
                   7223:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
                   7224:     arg2 = valuePop(ctxt);
                   7225:     arg1 = valuePop(ctxt);
                   7226:     if ((arg1 == NULL) || (arg2 == NULL)) {
                   7227:        if (arg1 != NULL)
                   7228:            xmlXPathReleaseObject(ctxt->context, arg1);
                   7229:        else
                   7230:            xmlXPathReleaseObject(ctxt->context, arg2);
                   7231:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7232:     }
                   7233: 
                   7234:     if (arg1 == arg2) {
                   7235: #ifdef DEBUG_EXPR
                   7236:         xmlGenericError(xmlGenericErrorContext,
                   7237:                "NotEqual: by pointer\n");
                   7238: #endif
                   7239:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7240:         return(0);
                   7241:     }
                   7242: 
                   7243:     /*
                   7244:      *If either argument is a nodeset, it's a 'special case'
                   7245:      */
                   7246:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
                   7247:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7248:        /*
                   7249:         *Hack it to assure arg1 is the nodeset
                   7250:         */
                   7251:        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
                   7252:                argtmp = arg2;
                   7253:                arg2 = arg1;
                   7254:                arg1 = argtmp;
                   7255:        }
                   7256:        switch (arg2->type) {
                   7257:            case XPATH_UNDEFINED:
                   7258: #ifdef DEBUG_EXPR
                   7259:                xmlGenericError(xmlGenericErrorContext,
                   7260:                        "NotEqual: undefined\n");
                   7261: #endif
                   7262:                break;
                   7263:            case XPATH_NODESET:
                   7264:            case XPATH_XSLT_TREE:
                   7265:                ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
                   7266:                break;
                   7267:            case XPATH_BOOLEAN:
                   7268:                if ((arg1->nodesetval == NULL) ||
                   7269:                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
                   7270:                else
                   7271:                    ret = 1;
                   7272:                ret = (ret != arg2->boolval);
                   7273:                break;
                   7274:            case XPATH_NUMBER:
                   7275:                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
                   7276:                break;
                   7277:            case XPATH_STRING:
                   7278:                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
                   7279:                break;
                   7280:            case XPATH_USERS:
                   7281:            case XPATH_POINT:
                   7282:            case XPATH_RANGE:
                   7283:            case XPATH_LOCATIONSET:
                   7284:                TODO
                   7285:                break;
                   7286:        }
                   7287:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7288:        xmlXPathReleaseObject(ctxt->context, arg2);
                   7289:        return(ret);
                   7290:     }
                   7291: 
                   7292:     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
                   7293: }
                   7294: 
                   7295: /**
                   7296:  * xmlXPathCompareValues:
                   7297:  * @ctxt:  the XPath Parser context
                   7298:  * @inf:  less than (1) or greater than (0)
                   7299:  * @strict:  is the comparison strict
                   7300:  *
                   7301:  * Implement the compare operation on XPath objects:
                   7302:  *     @arg1 < @arg2    (1, 1, ...
                   7303:  *     @arg1 <= @arg2   (1, 0, ...
                   7304:  *     @arg1 > @arg2    (0, 1, ...
                   7305:  *     @arg1 >= @arg2   (0, 0, ...
                   7306:  *
                   7307:  * When neither object to be compared is a node-set and the operator is
                   7308:  * <=, <, >=, >, then the objects are compared by converted both objects
                   7309:  * to numbers and comparing the numbers according to IEEE 754. The <
                   7310:  * comparison will be true if and only if the first number is less than the
                   7311:  * second number. The <= comparison will be true if and only if the first
                   7312:  * number is less than or equal to the second number. The > comparison
                   7313:  * will be true if and only if the first number is greater than the second
                   7314:  * number. The >= comparison will be true if and only if the first number
                   7315:  * is greater than or equal to the second number.
                   7316:  *
                   7317:  * Returns 1 if the comparison succeeded, 0 if it failed
                   7318:  */
                   7319: int
                   7320: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
                   7321:     int ret = 0, arg1i = 0, arg2i = 0;
                   7322:     xmlXPathObjectPtr arg1, arg2;
                   7323: 
                   7324:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
                   7325:     arg2 = valuePop(ctxt);
                   7326:     arg1 = valuePop(ctxt);
                   7327:     if ((arg1 == NULL) || (arg2 == NULL)) {
                   7328:        if (arg1 != NULL)
                   7329:            xmlXPathReleaseObject(ctxt->context, arg1);
                   7330:        else
                   7331:            xmlXPathReleaseObject(ctxt->context, arg2);
                   7332:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7333:     }
                   7334: 
                   7335:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
                   7336:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7337:        /*
                   7338:         * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
                   7339:         * are not freed from within this routine; they will be freed from the
                   7340:         * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
                   7341:         */
                   7342:        if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
                   7343:          ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
                   7344:            ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
                   7345:        } else {
                   7346:            if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
                   7347:                ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
                   7348:                                                  arg1, arg2);
                   7349:            } else {
                   7350:                ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
                   7351:                                                  arg2, arg1);
                   7352:            }
                   7353:        }
                   7354:        return(ret);
                   7355:     }
                   7356: 
                   7357:     if (arg1->type != XPATH_NUMBER) {
                   7358:        valuePush(ctxt, arg1);
                   7359:        xmlXPathNumberFunction(ctxt, 1);
                   7360:        arg1 = valuePop(ctxt);
                   7361:     }
                   7362:     if (arg1->type != XPATH_NUMBER) {
                   7363:        xmlXPathFreeObject(arg1);
                   7364:        xmlXPathFreeObject(arg2);
                   7365:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7366:     }
                   7367:     if (arg2->type != XPATH_NUMBER) {
                   7368:        valuePush(ctxt, arg2);
                   7369:        xmlXPathNumberFunction(ctxt, 1);
                   7370:        arg2 = valuePop(ctxt);
                   7371:     }
                   7372:     if (arg2->type != XPATH_NUMBER) {
                   7373:        xmlXPathReleaseObject(ctxt->context, arg1);
                   7374:        xmlXPathReleaseObject(ctxt->context, arg2);
                   7375:        XP_ERROR0(XPATH_INVALID_OPERAND);
                   7376:     }
                   7377:     /*
                   7378:      * Add tests for infinity and nan
                   7379:      * => feedback on 3.4 for Inf and NaN
                   7380:      */
                   7381:     /* Hand check NaN and Infinity comparisons */
                   7382:     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
                   7383:        ret=0;
                   7384:     } else {
                   7385:        arg1i=xmlXPathIsInf(arg1->floatval);
                   7386:        arg2i=xmlXPathIsInf(arg2->floatval);
                   7387:        if (inf && strict) {
                   7388:            if ((arg1i == -1 && arg2i != -1) ||
                   7389:                (arg2i == 1 && arg1i != 1)) {
                   7390:                ret = 1;
                   7391:            } else if (arg1i == 0 && arg2i == 0) {
                   7392:                ret = (arg1->floatval < arg2->floatval);
                   7393:            } else {
                   7394:                ret = 0;
                   7395:            }
                   7396:        }
                   7397:        else if (inf && !strict) {
                   7398:            if (arg1i == -1 || arg2i == 1) {
                   7399:                ret = 1;
                   7400:            } else if (arg1i == 0 && arg2i == 0) {
                   7401:                ret = (arg1->floatval <= arg2->floatval);
                   7402:            } else {
                   7403:                ret = 0;
                   7404:            }
                   7405:        }
                   7406:        else if (!inf && strict) {
                   7407:            if ((arg1i == 1 && arg2i != 1) ||
                   7408:                (arg2i == -1 && arg1i != -1)) {
                   7409:                ret = 1;
                   7410:            } else if (arg1i == 0 && arg2i == 0) {
                   7411:                ret = (arg1->floatval > arg2->floatval);
                   7412:            } else {
                   7413:                ret = 0;
                   7414:            }
                   7415:        }
                   7416:        else if (!inf && !strict) {
                   7417:            if (arg1i == 1 || arg2i == -1) {
                   7418:                ret = 1;
                   7419:            } else if (arg1i == 0 && arg2i == 0) {
                   7420:                ret = (arg1->floatval >= arg2->floatval);
                   7421:            } else {
                   7422:                ret = 0;
                   7423:            }
                   7424:        }
                   7425:     }
                   7426:     xmlXPathReleaseObject(ctxt->context, arg1);
                   7427:     xmlXPathReleaseObject(ctxt->context, arg2);
                   7428:     return(ret);
                   7429: }
                   7430: 
                   7431: /**
                   7432:  * xmlXPathValueFlipSign:
                   7433:  * @ctxt:  the XPath Parser context
                   7434:  *
                   7435:  * Implement the unary - operation on an XPath object
                   7436:  * The numeric operators convert their operands to numbers as if
                   7437:  * by calling the number function.
                   7438:  */
                   7439: void
                   7440: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
                   7441:     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
                   7442:     CAST_TO_NUMBER;
                   7443:     CHECK_TYPE(XPATH_NUMBER);
                   7444:     if (xmlXPathIsNaN(ctxt->value->floatval))
                   7445:         ctxt->value->floatval=xmlXPathNAN;
                   7446:     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
                   7447:         ctxt->value->floatval=xmlXPathNINF;
                   7448:     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
                   7449:         ctxt->value->floatval=xmlXPathPINF;
                   7450:     else if (ctxt->value->floatval == 0) {
                   7451:         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
                   7452:            ctxt->value->floatval = xmlXPathNZERO;
                   7453:        else
                   7454:            ctxt->value->floatval = 0;
                   7455:     }
                   7456:     else
                   7457:         ctxt->value->floatval = - ctxt->value->floatval;
                   7458: }
                   7459: 
                   7460: /**
                   7461:  * xmlXPathAddValues:
                   7462:  * @ctxt:  the XPath Parser context
                   7463:  *
                   7464:  * Implement the add operation on XPath objects:
                   7465:  * The numeric operators convert their operands to numbers as if
                   7466:  * by calling the number function.
                   7467:  */
                   7468: void
                   7469: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
                   7470:     xmlXPathObjectPtr arg;
                   7471:     double val;
                   7472: 
                   7473:     arg = valuePop(ctxt);
                   7474:     if (arg == NULL)
                   7475:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7476:     val = xmlXPathCastToNumber(arg);
                   7477:     xmlXPathReleaseObject(ctxt->context, arg);
                   7478:     CAST_TO_NUMBER;
                   7479:     CHECK_TYPE(XPATH_NUMBER);
                   7480:     ctxt->value->floatval += val;
                   7481: }
                   7482: 
                   7483: /**
                   7484:  * xmlXPathSubValues:
                   7485:  * @ctxt:  the XPath Parser context
                   7486:  *
                   7487:  * Implement the subtraction operation on XPath objects:
                   7488:  * The numeric operators convert their operands to numbers as if
                   7489:  * by calling the number function.
                   7490:  */
                   7491: void
                   7492: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
                   7493:     xmlXPathObjectPtr arg;
                   7494:     double val;
                   7495: 
                   7496:     arg = valuePop(ctxt);
                   7497:     if (arg == NULL)
                   7498:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7499:     val = xmlXPathCastToNumber(arg);
                   7500:     xmlXPathReleaseObject(ctxt->context, arg);
                   7501:     CAST_TO_NUMBER;
                   7502:     CHECK_TYPE(XPATH_NUMBER);
                   7503:     ctxt->value->floatval -= val;
                   7504: }
                   7505: 
                   7506: /**
                   7507:  * xmlXPathMultValues:
                   7508:  * @ctxt:  the XPath Parser context
                   7509:  *
                   7510:  * Implement the multiply operation on XPath objects:
                   7511:  * The numeric operators convert their operands to numbers as if
                   7512:  * by calling the number function.
                   7513:  */
                   7514: void
                   7515: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
                   7516:     xmlXPathObjectPtr arg;
                   7517:     double val;
                   7518: 
                   7519:     arg = valuePop(ctxt);
                   7520:     if (arg == NULL)
                   7521:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7522:     val = xmlXPathCastToNumber(arg);
                   7523:     xmlXPathReleaseObject(ctxt->context, arg);
                   7524:     CAST_TO_NUMBER;
                   7525:     CHECK_TYPE(XPATH_NUMBER);
                   7526:     ctxt->value->floatval *= val;
                   7527: }
                   7528: 
                   7529: /**
                   7530:  * xmlXPathDivValues:
                   7531:  * @ctxt:  the XPath Parser context
                   7532:  *
                   7533:  * Implement the div operation on XPath objects @arg1 / @arg2:
                   7534:  * The numeric operators convert their operands to numbers as if
                   7535:  * by calling the number function.
                   7536:  */
                   7537: void
                   7538: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
                   7539:     xmlXPathObjectPtr arg;
                   7540:     double val;
                   7541: 
                   7542:     arg = valuePop(ctxt);
                   7543:     if (arg == NULL)
                   7544:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7545:     val = xmlXPathCastToNumber(arg);
                   7546:     xmlXPathReleaseObject(ctxt->context, arg);
                   7547:     CAST_TO_NUMBER;
                   7548:     CHECK_TYPE(XPATH_NUMBER);
                   7549:     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
                   7550:        ctxt->value->floatval = xmlXPathNAN;
                   7551:     else if (val == 0 && xmlXPathGetSign(val) != 0) {
                   7552:        if (ctxt->value->floatval == 0)
                   7553:            ctxt->value->floatval = xmlXPathNAN;
                   7554:        else if (ctxt->value->floatval > 0)
                   7555:            ctxt->value->floatval = xmlXPathNINF;
                   7556:        else if (ctxt->value->floatval < 0)
                   7557:            ctxt->value->floatval = xmlXPathPINF;
                   7558:     }
                   7559:     else if (val == 0) {
                   7560:        if (ctxt->value->floatval == 0)
                   7561:            ctxt->value->floatval = xmlXPathNAN;
                   7562:        else if (ctxt->value->floatval > 0)
                   7563:            ctxt->value->floatval = xmlXPathPINF;
                   7564:        else if (ctxt->value->floatval < 0)
                   7565:            ctxt->value->floatval = xmlXPathNINF;
                   7566:     } else
                   7567:        ctxt->value->floatval /= val;
                   7568: }
                   7569: 
                   7570: /**
                   7571:  * xmlXPathModValues:
                   7572:  * @ctxt:  the XPath Parser context
                   7573:  *
                   7574:  * Implement the mod operation on XPath objects: @arg1 / @arg2
                   7575:  * The numeric operators convert their operands to numbers as if
                   7576:  * by calling the number function.
                   7577:  */
                   7578: void
                   7579: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
                   7580:     xmlXPathObjectPtr arg;
                   7581:     double arg1, arg2;
                   7582: 
                   7583:     arg = valuePop(ctxt);
                   7584:     if (arg == NULL)
                   7585:        XP_ERROR(XPATH_INVALID_OPERAND);
                   7586:     arg2 = xmlXPathCastToNumber(arg);
                   7587:     xmlXPathReleaseObject(ctxt->context, arg);
                   7588:     CAST_TO_NUMBER;
                   7589:     CHECK_TYPE(XPATH_NUMBER);
                   7590:     arg1 = ctxt->value->floatval;
                   7591:     if (arg2 == 0)
                   7592:        ctxt->value->floatval = xmlXPathNAN;
                   7593:     else {
                   7594:        ctxt->value->floatval = fmod(arg1, arg2);
                   7595:     }
                   7596: }
                   7597: 
                   7598: /************************************************************************
                   7599:  *                                                                     *
                   7600:  *             The traversal functions                                 *
                   7601:  *                                                                     *
                   7602:  ************************************************************************/
                   7603: 
                   7604: /*
                   7605:  * A traversal function enumerates nodes along an axis.
                   7606:  * Initially it must be called with NULL, and it indicates
                   7607:  * termination on the axis by returning NULL.
                   7608:  */
                   7609: typedef xmlNodePtr (*xmlXPathTraversalFunction)
                   7610:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
                   7611: 
                   7612: /*
                   7613:  * xmlXPathTraversalFunctionExt:
                   7614:  * A traversal function enumerates nodes along an axis.
                   7615:  * Initially it must be called with NULL, and it indicates
                   7616:  * termination on the axis by returning NULL.
                   7617:  * The context node of the traversal is specified via @contextNode.
                   7618:  */
                   7619: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
                   7620:                     (xmlNodePtr cur, xmlNodePtr contextNode);
                   7621: 
                   7622: /*
                   7623:  * xmlXPathNodeSetMergeFunction:
                   7624:  * Used for merging node sets in xmlXPathCollectAndTest().
                   7625:  */
                   7626: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
                   7627:                    (xmlNodeSetPtr, xmlNodeSetPtr, int);
                   7628: 
                   7629: 
                   7630: /**
                   7631:  * xmlXPathNextSelf:
                   7632:  * @ctxt:  the XPath Parser context
                   7633:  * @cur:  the current node in the traversal
                   7634:  *
                   7635:  * Traversal function for the "self" direction
                   7636:  * The self axis contains just the context node itself
                   7637:  *
                   7638:  * Returns the next element following that axis
                   7639:  */
                   7640: xmlNodePtr
                   7641: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7642:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7643:     if (cur == NULL)
                   7644:         return(ctxt->context->node);
                   7645:     return(NULL);
                   7646: }
                   7647: 
                   7648: /**
                   7649:  * xmlXPathNextChild:
                   7650:  * @ctxt:  the XPath Parser context
                   7651:  * @cur:  the current node in the traversal
                   7652:  *
                   7653:  * Traversal function for the "child" direction
                   7654:  * The child axis contains the children of the context node in document order.
                   7655:  *
                   7656:  * Returns the next element following that axis
                   7657:  */
                   7658: xmlNodePtr
                   7659: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7660:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7661:     if (cur == NULL) {
                   7662:        if (ctxt->context->node == NULL) return(NULL);
                   7663:        switch (ctxt->context->node->type) {
                   7664:             case XML_ELEMENT_NODE:
                   7665:             case XML_TEXT_NODE:
                   7666:             case XML_CDATA_SECTION_NODE:
                   7667:             case XML_ENTITY_REF_NODE:
                   7668:             case XML_ENTITY_NODE:
                   7669:             case XML_PI_NODE:
                   7670:             case XML_COMMENT_NODE:
                   7671:             case XML_NOTATION_NODE:
                   7672:             case XML_DTD_NODE:
                   7673:                return(ctxt->context->node->children);
                   7674:             case XML_DOCUMENT_NODE:
                   7675:             case XML_DOCUMENT_TYPE_NODE:
                   7676:             case XML_DOCUMENT_FRAG_NODE:
                   7677:             case XML_HTML_DOCUMENT_NODE:
                   7678: #ifdef LIBXML_DOCB_ENABLED
                   7679:            case XML_DOCB_DOCUMENT_NODE:
                   7680: #endif
                   7681:                return(((xmlDocPtr) ctxt->context->node)->children);
                   7682:            case XML_ELEMENT_DECL:
                   7683:            case XML_ATTRIBUTE_DECL:
                   7684:            case XML_ENTITY_DECL:
                   7685:             case XML_ATTRIBUTE_NODE:
                   7686:            case XML_NAMESPACE_DECL:
                   7687:            case XML_XINCLUDE_START:
                   7688:            case XML_XINCLUDE_END:
                   7689:                return(NULL);
                   7690:        }
                   7691:        return(NULL);
                   7692:     }
                   7693:     if ((cur->type == XML_DOCUMENT_NODE) ||
                   7694:         (cur->type == XML_HTML_DOCUMENT_NODE))
                   7695:        return(NULL);
                   7696:     return(cur->next);
                   7697: }
                   7698: 
                   7699: /**
                   7700:  * xmlXPathNextChildElement:
                   7701:  * @ctxt:  the XPath Parser context
                   7702:  * @cur:  the current node in the traversal
                   7703:  *
                   7704:  * Traversal function for the "child" direction and nodes of type element.
                   7705:  * The child axis contains the children of the context node in document order.
                   7706:  *
                   7707:  * Returns the next element following that axis
                   7708:  */
                   7709: static xmlNodePtr
                   7710: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7711:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7712:     if (cur == NULL) {
                   7713:        cur = ctxt->context->node;
                   7714:        if (cur == NULL) return(NULL);
                   7715:        /*
                   7716:        * Get the first element child.
                   7717:        */
                   7718:        switch (cur->type) {
                   7719:             case XML_ELEMENT_NODE:
                   7720:            case XML_DOCUMENT_FRAG_NODE:
                   7721:            case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
                   7722:             case XML_ENTITY_NODE:
                   7723:                cur = cur->children;
                   7724:                if (cur != NULL) {
                   7725:                    if (cur->type == XML_ELEMENT_NODE)
                   7726:                        return(cur);
                   7727:                    do {
                   7728:                        cur = cur->next;
                   7729:                    } while ((cur != NULL) &&
                   7730:                        (cur->type != XML_ELEMENT_NODE));
                   7731:                    return(cur);
                   7732:                }
                   7733:                return(NULL);
                   7734:             case XML_DOCUMENT_NODE:
                   7735:             case XML_HTML_DOCUMENT_NODE:
                   7736: #ifdef LIBXML_DOCB_ENABLED
                   7737:            case XML_DOCB_DOCUMENT_NODE:
                   7738: #endif
                   7739:                return(xmlDocGetRootElement((xmlDocPtr) cur));
                   7740:            default:
                   7741:                return(NULL);
                   7742:        }
                   7743:        return(NULL);
                   7744:     }
                   7745:     /*
                   7746:     * Get the next sibling element node.
                   7747:     */
                   7748:     switch (cur->type) {
                   7749:        case XML_ELEMENT_NODE:
                   7750:        case XML_TEXT_NODE:
                   7751:        case XML_ENTITY_REF_NODE:
                   7752:        case XML_ENTITY_NODE:
                   7753:        case XML_CDATA_SECTION_NODE:
                   7754:        case XML_PI_NODE:
                   7755:        case XML_COMMENT_NODE:
                   7756:        case XML_XINCLUDE_END:
                   7757:            break;
                   7758:        /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
                   7759:        default:
                   7760:            return(NULL);
                   7761:     }
                   7762:     if (cur->next != NULL) {
                   7763:        if (cur->next->type == XML_ELEMENT_NODE)
                   7764:            return(cur->next);
                   7765:        cur = cur->next;
                   7766:        do {
                   7767:            cur = cur->next;
                   7768:        } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
                   7769:        return(cur);
                   7770:     }
                   7771:     return(NULL);
                   7772: }
                   7773: 
1.1.1.3 ! misho    7774: #if 0
1.1       misho    7775: /**
                   7776:  * xmlXPathNextDescendantOrSelfElemParent:
                   7777:  * @ctxt:  the XPath Parser context
                   7778:  * @cur:  the current node in the traversal
                   7779:  *
                   7780:  * Traversal function for the "descendant-or-self" axis.
                   7781:  * Additionally it returns only nodes which can be parents of
                   7782:  * element nodes.
                   7783:  *
                   7784:  *
                   7785:  * Returns the next element following that axis
                   7786:  */
                   7787: static xmlNodePtr
                   7788: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
                   7789:                                       xmlNodePtr contextNode)
                   7790: {
                   7791:     if (cur == NULL) {
                   7792:        if (contextNode == NULL)
                   7793:            return(NULL);
                   7794:        switch (contextNode->type) {
                   7795:            case XML_ELEMENT_NODE:
                   7796:            case XML_XINCLUDE_START:
                   7797:            case XML_DOCUMENT_FRAG_NODE:
                   7798:            case XML_DOCUMENT_NODE:
                   7799: #ifdef LIBXML_DOCB_ENABLED
                   7800:            case XML_DOCB_DOCUMENT_NODE:
                   7801: #endif
1.1.1.3 ! misho    7802:            case XML_HTML_DOCUMENT_NODE:
1.1       misho    7803:                return(contextNode);
                   7804:            default:
                   7805:                return(NULL);
                   7806:        }
                   7807:        return(NULL);
                   7808:     } else {
                   7809:        xmlNodePtr start = cur;
                   7810: 
                   7811:        while (cur != NULL) {
                   7812:            switch (cur->type) {
                   7813:                case XML_ELEMENT_NODE:
                   7814:                /* TODO: OK to have XInclude here? */
                   7815:                case XML_XINCLUDE_START:
                   7816:                case XML_DOCUMENT_FRAG_NODE:
                   7817:                    if (cur != start)
                   7818:                        return(cur);
                   7819:                    if (cur->children != NULL) {
                   7820:                        cur = cur->children;
                   7821:                        continue;
                   7822:                    }
                   7823:                    break;
                   7824:                /* Not sure if we need those here. */
                   7825:                case XML_DOCUMENT_NODE:
                   7826: #ifdef LIBXML_DOCB_ENABLED
                   7827:                case XML_DOCB_DOCUMENT_NODE:
                   7828: #endif
                   7829:                case XML_HTML_DOCUMENT_NODE:
                   7830:                    if (cur != start)
                   7831:                        return(cur);
                   7832:                    return(xmlDocGetRootElement((xmlDocPtr) cur));
                   7833:                default:
                   7834:                    break;
                   7835:            }
                   7836: 
                   7837: next_sibling:
                   7838:            if ((cur == NULL) || (cur == contextNode))
                   7839:                return(NULL);
                   7840:            if (cur->next != NULL) {
                   7841:                cur = cur->next;
                   7842:            } else {
                   7843:                cur = cur->parent;
                   7844:                goto next_sibling;
                   7845:            }
                   7846:        }
                   7847:     }
                   7848:     return(NULL);
                   7849: }
1.1.1.3 ! misho    7850: #endif
1.1       misho    7851: 
                   7852: /**
                   7853:  * xmlXPathNextDescendant:
                   7854:  * @ctxt:  the XPath Parser context
                   7855:  * @cur:  the current node in the traversal
                   7856:  *
                   7857:  * Traversal function for the "descendant" direction
                   7858:  * the descendant axis contains the descendants of the context node in document
                   7859:  * order; a descendant is a child or a child of a child and so on.
                   7860:  *
                   7861:  * Returns the next element following that axis
                   7862:  */
                   7863: xmlNodePtr
                   7864: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7865:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7866:     if (cur == NULL) {
                   7867:        if (ctxt->context->node == NULL)
                   7868:            return(NULL);
                   7869:        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   7870:            (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   7871:            return(NULL);
                   7872: 
                   7873:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
                   7874:            return(ctxt->context->doc->children);
                   7875:         return(ctxt->context->node->children);
                   7876:     }
                   7877: 
1.1.1.3 ! misho    7878:     if (cur->type == XML_NAMESPACE_DECL)
        !          7879:         return(NULL);
1.1       misho    7880:     if (cur->children != NULL) {
                   7881:        /*
                   7882:         * Do not descend on entities declarations
                   7883:         */
                   7884:        if (cur->children->type != XML_ENTITY_DECL) {
                   7885:            cur = cur->children;
                   7886:            /*
                   7887:             * Skip DTDs
                   7888:             */
                   7889:            if (cur->type != XML_DTD_NODE)
                   7890:                return(cur);
                   7891:        }
                   7892:     }
                   7893: 
                   7894:     if (cur == ctxt->context->node) return(NULL);
                   7895: 
                   7896:     while (cur->next != NULL) {
                   7897:        cur = cur->next;
                   7898:        if ((cur->type != XML_ENTITY_DECL) &&
                   7899:            (cur->type != XML_DTD_NODE))
                   7900:            return(cur);
                   7901:     }
                   7902: 
                   7903:     do {
                   7904:         cur = cur->parent;
                   7905:        if (cur == NULL) break;
                   7906:        if (cur == ctxt->context->node) return(NULL);
                   7907:        if (cur->next != NULL) {
                   7908:            cur = cur->next;
                   7909:            return(cur);
                   7910:        }
                   7911:     } while (cur != NULL);
                   7912:     return(cur);
                   7913: }
                   7914: 
                   7915: /**
                   7916:  * xmlXPathNextDescendantOrSelf:
                   7917:  * @ctxt:  the XPath Parser context
                   7918:  * @cur:  the current node in the traversal
                   7919:  *
                   7920:  * Traversal function for the "descendant-or-self" direction
                   7921:  * the descendant-or-self axis contains the context node and the descendants
                   7922:  * of the context node in document order; thus the context node is the first
                   7923:  * node on the axis, and the first child of the context node is the second node
                   7924:  * on the axis
                   7925:  *
                   7926:  * Returns the next element following that axis
                   7927:  */
                   7928: xmlNodePtr
                   7929: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7930:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7931:     if (cur == NULL) {
                   7932:        if (ctxt->context->node == NULL)
                   7933:            return(NULL);
                   7934:        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   7935:            (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   7936:            return(NULL);
                   7937:         return(ctxt->context->node);
                   7938:     }
                   7939: 
                   7940:     return(xmlXPathNextDescendant(ctxt, cur));
                   7941: }
                   7942: 
                   7943: /**
                   7944:  * xmlXPathNextParent:
                   7945:  * @ctxt:  the XPath Parser context
                   7946:  * @cur:  the current node in the traversal
                   7947:  *
                   7948:  * Traversal function for the "parent" direction
                   7949:  * The parent axis contains the parent of the context node, if there is one.
                   7950:  *
                   7951:  * Returns the next element following that axis
                   7952:  */
                   7953: xmlNodePtr
                   7954: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   7955:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   7956:     /*
                   7957:      * the parent of an attribute or namespace node is the element
                   7958:      * to which the attribute or namespace node is attached
                   7959:      * Namespace handling !!!
                   7960:      */
                   7961:     if (cur == NULL) {
                   7962:        if (ctxt->context->node == NULL) return(NULL);
                   7963:        switch (ctxt->context->node->type) {
                   7964:             case XML_ELEMENT_NODE:
                   7965:             case XML_TEXT_NODE:
                   7966:             case XML_CDATA_SECTION_NODE:
                   7967:             case XML_ENTITY_REF_NODE:
                   7968:             case XML_ENTITY_NODE:
                   7969:             case XML_PI_NODE:
                   7970:             case XML_COMMENT_NODE:
                   7971:             case XML_NOTATION_NODE:
                   7972:             case XML_DTD_NODE:
                   7973:            case XML_ELEMENT_DECL:
                   7974:            case XML_ATTRIBUTE_DECL:
                   7975:            case XML_XINCLUDE_START:
                   7976:            case XML_XINCLUDE_END:
                   7977:            case XML_ENTITY_DECL:
                   7978:                if (ctxt->context->node->parent == NULL)
                   7979:                    return((xmlNodePtr) ctxt->context->doc);
                   7980:                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
                   7981:                    ((ctxt->context->node->parent->name[0] == ' ') ||
                   7982:                     (xmlStrEqual(ctxt->context->node->parent->name,
                   7983:                                 BAD_CAST "fake node libxslt"))))
                   7984:                    return(NULL);
                   7985:                return(ctxt->context->node->parent);
                   7986:             case XML_ATTRIBUTE_NODE: {
                   7987:                xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
                   7988: 
                   7989:                return(att->parent);
                   7990:            }
                   7991:             case XML_DOCUMENT_NODE:
                   7992:             case XML_DOCUMENT_TYPE_NODE:
                   7993:             case XML_DOCUMENT_FRAG_NODE:
                   7994:             case XML_HTML_DOCUMENT_NODE:
                   7995: #ifdef LIBXML_DOCB_ENABLED
                   7996:            case XML_DOCB_DOCUMENT_NODE:
                   7997: #endif
                   7998:                 return(NULL);
                   7999:            case XML_NAMESPACE_DECL: {
                   8000:                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
                   8001: 
                   8002:                if ((ns->next != NULL) &&
                   8003:                    (ns->next->type != XML_NAMESPACE_DECL))
                   8004:                    return((xmlNodePtr) ns->next);
                   8005:                 return(NULL);
                   8006:            }
                   8007:        }
                   8008:     }
                   8009:     return(NULL);
                   8010: }
                   8011: 
                   8012: /**
                   8013:  * xmlXPathNextAncestor:
                   8014:  * @ctxt:  the XPath Parser context
                   8015:  * @cur:  the current node in the traversal
                   8016:  *
                   8017:  * Traversal function for the "ancestor" direction
                   8018:  * the ancestor axis contains the ancestors of the context node; the ancestors
                   8019:  * of the context node consist of the parent of context node and the parent's
                   8020:  * parent and so on; the nodes are ordered in reverse document order; thus the
                   8021:  * parent is the first node on the axis, and the parent's parent is the second
                   8022:  * node on the axis
                   8023:  *
                   8024:  * Returns the next element following that axis
                   8025:  */
                   8026: xmlNodePtr
                   8027: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8028:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8029:     /*
                   8030:      * the parent of an attribute or namespace node is the element
                   8031:      * to which the attribute or namespace node is attached
                   8032:      * !!!!!!!!!!!!!
                   8033:      */
                   8034:     if (cur == NULL) {
                   8035:        if (ctxt->context->node == NULL) return(NULL);
                   8036:        switch (ctxt->context->node->type) {
                   8037:             case XML_ELEMENT_NODE:
                   8038:             case XML_TEXT_NODE:
                   8039:             case XML_CDATA_SECTION_NODE:
                   8040:             case XML_ENTITY_REF_NODE:
                   8041:             case XML_ENTITY_NODE:
                   8042:             case XML_PI_NODE:
                   8043:             case XML_COMMENT_NODE:
                   8044:            case XML_DTD_NODE:
                   8045:            case XML_ELEMENT_DECL:
                   8046:            case XML_ATTRIBUTE_DECL:
                   8047:            case XML_ENTITY_DECL:
                   8048:             case XML_NOTATION_NODE:
                   8049:            case XML_XINCLUDE_START:
                   8050:            case XML_XINCLUDE_END:
                   8051:                if (ctxt->context->node->parent == NULL)
                   8052:                    return((xmlNodePtr) ctxt->context->doc);
                   8053:                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
                   8054:                    ((ctxt->context->node->parent->name[0] == ' ') ||
                   8055:                     (xmlStrEqual(ctxt->context->node->parent->name,
                   8056:                                 BAD_CAST "fake node libxslt"))))
                   8057:                    return(NULL);
                   8058:                return(ctxt->context->node->parent);
                   8059:             case XML_ATTRIBUTE_NODE: {
                   8060:                xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
                   8061: 
                   8062:                return(tmp->parent);
                   8063:            }
                   8064:             case XML_DOCUMENT_NODE:
                   8065:             case XML_DOCUMENT_TYPE_NODE:
                   8066:             case XML_DOCUMENT_FRAG_NODE:
                   8067:             case XML_HTML_DOCUMENT_NODE:
                   8068: #ifdef LIBXML_DOCB_ENABLED
                   8069:            case XML_DOCB_DOCUMENT_NODE:
                   8070: #endif
                   8071:                 return(NULL);
                   8072:            case XML_NAMESPACE_DECL: {
                   8073:                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
                   8074: 
                   8075:                if ((ns->next != NULL) &&
                   8076:                    (ns->next->type != XML_NAMESPACE_DECL))
                   8077:                    return((xmlNodePtr) ns->next);
                   8078:                /* Bad, how did that namespace end up here ? */
                   8079:                 return(NULL);
                   8080:            }
                   8081:        }
                   8082:        return(NULL);
                   8083:     }
                   8084:     if (cur == ctxt->context->doc->children)
                   8085:        return((xmlNodePtr) ctxt->context->doc);
                   8086:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   8087:        return(NULL);
                   8088:     switch (cur->type) {
                   8089:        case XML_ELEMENT_NODE:
                   8090:        case XML_TEXT_NODE:
                   8091:        case XML_CDATA_SECTION_NODE:
                   8092:        case XML_ENTITY_REF_NODE:
                   8093:        case XML_ENTITY_NODE:
                   8094:        case XML_PI_NODE:
                   8095:        case XML_COMMENT_NODE:
                   8096:        case XML_NOTATION_NODE:
                   8097:        case XML_DTD_NODE:
                   8098:         case XML_ELEMENT_DECL:
                   8099:         case XML_ATTRIBUTE_DECL:
                   8100:         case XML_ENTITY_DECL:
                   8101:        case XML_XINCLUDE_START:
                   8102:        case XML_XINCLUDE_END:
                   8103:            if (cur->parent == NULL)
                   8104:                return(NULL);
                   8105:            if ((cur->parent->type == XML_ELEMENT_NODE) &&
                   8106:                ((cur->parent->name[0] == ' ') ||
                   8107:                 (xmlStrEqual(cur->parent->name,
                   8108:                              BAD_CAST "fake node libxslt"))))
                   8109:                return(NULL);
                   8110:            return(cur->parent);
                   8111:        case XML_ATTRIBUTE_NODE: {
                   8112:            xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
                   8113: 
                   8114:            return(att->parent);
                   8115:        }
                   8116:        case XML_NAMESPACE_DECL: {
                   8117:            xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
                   8118: 
                   8119:            if ((ns->next != NULL) &&
                   8120:                (ns->next->type != XML_NAMESPACE_DECL))
                   8121:                return((xmlNodePtr) ns->next);
                   8122:            /* Bad, how did that namespace end up here ? */
                   8123:             return(NULL);
                   8124:        }
                   8125:        case XML_DOCUMENT_NODE:
                   8126:        case XML_DOCUMENT_TYPE_NODE:
                   8127:        case XML_DOCUMENT_FRAG_NODE:
                   8128:        case XML_HTML_DOCUMENT_NODE:
                   8129: #ifdef LIBXML_DOCB_ENABLED
                   8130:        case XML_DOCB_DOCUMENT_NODE:
                   8131: #endif
                   8132:            return(NULL);
                   8133:     }
                   8134:     return(NULL);
                   8135: }
                   8136: 
                   8137: /**
                   8138:  * xmlXPathNextAncestorOrSelf:
                   8139:  * @ctxt:  the XPath Parser context
                   8140:  * @cur:  the current node in the traversal
                   8141:  *
                   8142:  * Traversal function for the "ancestor-or-self" direction
                   8143:  * he ancestor-or-self axis contains the context node and ancestors of
                   8144:  * the context node in reverse document order; thus the context node is
                   8145:  * the first node on the axis, and the context node's parent the second;
                   8146:  * parent here is defined the same as with the parent axis.
                   8147:  *
                   8148:  * Returns the next element following that axis
                   8149:  */
                   8150: xmlNodePtr
                   8151: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8152:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8153:     if (cur == NULL)
                   8154:         return(ctxt->context->node);
                   8155:     return(xmlXPathNextAncestor(ctxt, cur));
                   8156: }
                   8157: 
                   8158: /**
                   8159:  * xmlXPathNextFollowingSibling:
                   8160:  * @ctxt:  the XPath Parser context
                   8161:  * @cur:  the current node in the traversal
                   8162:  *
                   8163:  * Traversal function for the "following-sibling" direction
                   8164:  * The following-sibling axis contains the following siblings of the context
                   8165:  * node in document order.
                   8166:  *
                   8167:  * Returns the next element following that axis
                   8168:  */
                   8169: xmlNodePtr
                   8170: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8171:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8172:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   8173:        (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   8174:        return(NULL);
                   8175:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   8176:         return(NULL);
                   8177:     if (cur == NULL)
                   8178:         return(ctxt->context->node->next);
                   8179:     return(cur->next);
                   8180: }
                   8181: 
                   8182: /**
                   8183:  * xmlXPathNextPrecedingSibling:
                   8184:  * @ctxt:  the XPath Parser context
                   8185:  * @cur:  the current node in the traversal
                   8186:  *
                   8187:  * Traversal function for the "preceding-sibling" direction
                   8188:  * The preceding-sibling axis contains the preceding siblings of the context
                   8189:  * node in reverse document order; the first preceding sibling is first on the
                   8190:  * axis; the sibling preceding that node is the second on the axis and so on.
                   8191:  *
                   8192:  * Returns the next element following that axis
                   8193:  */
                   8194: xmlNodePtr
                   8195: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8196:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8197:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
                   8198:        (ctxt->context->node->type == XML_NAMESPACE_DECL))
                   8199:        return(NULL);
                   8200:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   8201:         return(NULL);
                   8202:     if (cur == NULL)
                   8203:         return(ctxt->context->node->prev);
                   8204:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
                   8205:        cur = cur->prev;
                   8206:        if (cur == NULL)
                   8207:            return(ctxt->context->node->prev);
                   8208:     }
                   8209:     return(cur->prev);
                   8210: }
                   8211: 
                   8212: /**
                   8213:  * xmlXPathNextFollowing:
                   8214:  * @ctxt:  the XPath Parser context
                   8215:  * @cur:  the current node in the traversal
                   8216:  *
                   8217:  * Traversal function for the "following" direction
                   8218:  * The following axis contains all nodes in the same document as the context
                   8219:  * node that are after the context node in document order, excluding any
                   8220:  * descendants and excluding attribute nodes and namespace nodes; the nodes
                   8221:  * are ordered in document order
                   8222:  *
                   8223:  * Returns the next element following that axis
                   8224:  */
                   8225: xmlNodePtr
                   8226: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8227:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8228:     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
                   8229:         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
                   8230:         return(cur->children);
                   8231: 
                   8232:     if (cur == NULL) {
                   8233:         cur = ctxt->context->node;
                   8234:         if (cur->type == XML_NAMESPACE_DECL)
                   8235:             return(NULL);
                   8236:         if (cur->type == XML_ATTRIBUTE_NODE)
                   8237:             cur = cur->parent;
                   8238:     }
                   8239:     if (cur == NULL) return(NULL) ; /* ERROR */
                   8240:     if (cur->next != NULL) return(cur->next) ;
                   8241:     do {
                   8242:         cur = cur->parent;
                   8243:         if (cur == NULL) break;
                   8244:         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
                   8245:         if (cur->next != NULL) return(cur->next);
                   8246:     } while (cur != NULL);
                   8247:     return(cur);
                   8248: }
                   8249: 
                   8250: /*
                   8251:  * xmlXPathIsAncestor:
                   8252:  * @ancestor:  the ancestor node
                   8253:  * @node:  the current node
                   8254:  *
                   8255:  * Check that @ancestor is a @node's ancestor
                   8256:  *
                   8257:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
                   8258:  */
                   8259: static int
                   8260: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
                   8261:     if ((ancestor == NULL) || (node == NULL)) return(0);
1.1.1.3 ! misho    8262:     if (node->type == XML_NAMESPACE_DECL)
        !          8263:         return(0);
        !          8264:     if (ancestor->type == XML_NAMESPACE_DECL)
        !          8265:         return(0);
1.1       misho    8266:     /* nodes need to be in the same document */
                   8267:     if (ancestor->doc != node->doc) return(0);
                   8268:     /* avoid searching if ancestor or node is the root node */
                   8269:     if (ancestor == (xmlNodePtr) node->doc) return(1);
                   8270:     if (node == (xmlNodePtr) ancestor->doc) return(0);
                   8271:     while (node->parent != NULL) {
                   8272:         if (node->parent == ancestor)
                   8273:             return(1);
                   8274:        node = node->parent;
                   8275:     }
                   8276:     return(0);
                   8277: }
                   8278: 
                   8279: /**
                   8280:  * xmlXPathNextPreceding:
                   8281:  * @ctxt:  the XPath Parser context
                   8282:  * @cur:  the current node in the traversal
                   8283:  *
                   8284:  * Traversal function for the "preceding" direction
                   8285:  * the preceding axis contains all nodes in the same document as the context
                   8286:  * node that are before the context node in document order, excluding any
                   8287:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
                   8288:  * ordered in reverse document order
                   8289:  *
                   8290:  * Returns the next element following that axis
                   8291:  */
                   8292: xmlNodePtr
                   8293: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
                   8294: {
                   8295:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8296:     if (cur == NULL) {
                   8297:         cur = ctxt->context->node;
                   8298:         if (cur->type == XML_NAMESPACE_DECL)
                   8299:             return(NULL);
                   8300:         if (cur->type == XML_ATTRIBUTE_NODE)
                   8301:             return(cur->parent);
                   8302:     }
1.1.1.3 ! misho    8303:     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
1.1       misho    8304:        return (NULL);
                   8305:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
                   8306:        cur = cur->prev;
                   8307:     do {
                   8308:         if (cur->prev != NULL) {
                   8309:             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
                   8310:             return (cur);
                   8311:         }
                   8312: 
                   8313:         cur = cur->parent;
                   8314:         if (cur == NULL)
                   8315:             return (NULL);
                   8316:         if (cur == ctxt->context->doc->children)
                   8317:             return (NULL);
                   8318:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
                   8319:     return (cur);
                   8320: }
                   8321: 
                   8322: /**
                   8323:  * xmlXPathNextPrecedingInternal:
                   8324:  * @ctxt:  the XPath Parser context
                   8325:  * @cur:  the current node in the traversal
                   8326:  *
                   8327:  * Traversal function for the "preceding" direction
                   8328:  * the preceding axis contains all nodes in the same document as the context
                   8329:  * node that are before the context node in document order, excluding any
                   8330:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
                   8331:  * ordered in reverse document order
                   8332:  * This is a faster implementation but internal only since it requires a
                   8333:  * state kept in the parser context: ctxt->ancestor.
                   8334:  *
                   8335:  * Returns the next element following that axis
                   8336:  */
                   8337: static xmlNodePtr
                   8338: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
                   8339:                               xmlNodePtr cur)
                   8340: {
                   8341:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8342:     if (cur == NULL) {
                   8343:         cur = ctxt->context->node;
                   8344:         if (cur == NULL)
                   8345:             return (NULL);
                   8346:         if (cur->type == XML_NAMESPACE_DECL)
                   8347:             return (NULL);
                   8348:         ctxt->ancestor = cur->parent;
                   8349:     }
1.1.1.3 ! misho    8350:     if (cur->type == XML_NAMESPACE_DECL)
        !          8351:         return(NULL);
1.1       misho    8352:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
                   8353:        cur = cur->prev;
                   8354:     while (cur->prev == NULL) {
                   8355:         cur = cur->parent;
                   8356:         if (cur == NULL)
                   8357:             return (NULL);
                   8358:         if (cur == ctxt->context->doc->children)
                   8359:             return (NULL);
                   8360:         if (cur != ctxt->ancestor)
                   8361:             return (cur);
                   8362:         ctxt->ancestor = cur->parent;
                   8363:     }
                   8364:     cur = cur->prev;
                   8365:     while (cur->last != NULL)
                   8366:         cur = cur->last;
                   8367:     return (cur);
                   8368: }
                   8369: 
                   8370: /**
                   8371:  * xmlXPathNextNamespace:
                   8372:  * @ctxt:  the XPath Parser context
                   8373:  * @cur:  the current attribute in the traversal
                   8374:  *
                   8375:  * Traversal function for the "namespace" direction
                   8376:  * the namespace axis contains the namespace nodes of the context node;
                   8377:  * the order of nodes on this axis is implementation-defined; the axis will
                   8378:  * be empty unless the context node is an element
                   8379:  *
                   8380:  * We keep the XML namespace node at the end of the list.
                   8381:  *
                   8382:  * Returns the next element following that axis
                   8383:  */
                   8384: xmlNodePtr
                   8385: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8386:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8387:     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
                   8388:     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
                   8389:         if (ctxt->context->tmpNsList != NULL)
                   8390:            xmlFree(ctxt->context->tmpNsList);
                   8391:        ctxt->context->tmpNsList =
                   8392:            xmlGetNsList(ctxt->context->doc, ctxt->context->node);
                   8393:        ctxt->context->tmpNsNr = 0;
                   8394:        if (ctxt->context->tmpNsList != NULL) {
                   8395:            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
                   8396:                ctxt->context->tmpNsNr++;
                   8397:            }
                   8398:        }
                   8399:        return((xmlNodePtr) xmlXPathXMLNamespace);
                   8400:     }
                   8401:     if (ctxt->context->tmpNsNr > 0) {
                   8402:        return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
                   8403:     } else {
                   8404:        if (ctxt->context->tmpNsList != NULL)
                   8405:            xmlFree(ctxt->context->tmpNsList);
                   8406:        ctxt->context->tmpNsList = NULL;
                   8407:        return(NULL);
                   8408:     }
                   8409: }
                   8410: 
                   8411: /**
                   8412:  * xmlXPathNextAttribute:
                   8413:  * @ctxt:  the XPath Parser context
                   8414:  * @cur:  the current attribute in the traversal
                   8415:  *
                   8416:  * Traversal function for the "attribute" direction
                   8417:  * TODO: support DTD inherited default attributes
                   8418:  *
                   8419:  * Returns the next element following that axis
                   8420:  */
                   8421: xmlNodePtr
                   8422: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   8423:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
                   8424:     if (ctxt->context->node == NULL)
                   8425:        return(NULL);
                   8426:     if (ctxt->context->node->type != XML_ELEMENT_NODE)
                   8427:        return(NULL);
                   8428:     if (cur == NULL) {
                   8429:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
                   8430:            return(NULL);
                   8431:         return((xmlNodePtr)ctxt->context->node->properties);
                   8432:     }
                   8433:     return((xmlNodePtr)cur->next);
                   8434: }
                   8435: 
                   8436: /************************************************************************
                   8437:  *                                                                     *
                   8438:  *             NodeTest Functions                                      *
                   8439:  *                                                                     *
                   8440:  ************************************************************************/
                   8441: 
                   8442: #define IS_FUNCTION                    200
                   8443: 
                   8444: 
                   8445: /************************************************************************
                   8446:  *                                                                     *
                   8447:  *             Implicit tree core function library                     *
                   8448:  *                                                                     *
                   8449:  ************************************************************************/
                   8450: 
                   8451: /**
                   8452:  * xmlXPathRoot:
                   8453:  * @ctxt:  the XPath Parser context
                   8454:  *
                   8455:  * Initialize the context to the root of the document
                   8456:  */
                   8457: void
                   8458: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
                   8459:     if ((ctxt == NULL) || (ctxt->context == NULL))
                   8460:        return;
                   8461:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
                   8462:     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8463:        ctxt->context->node));
                   8464: }
                   8465: 
                   8466: /************************************************************************
                   8467:  *                                                                     *
                   8468:  *             The explicit core function library                      *
                   8469:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib        *
                   8470:  *                                                                     *
                   8471:  ************************************************************************/
                   8472: 
                   8473: 
                   8474: /**
                   8475:  * xmlXPathLastFunction:
                   8476:  * @ctxt:  the XPath Parser context
                   8477:  * @nargs:  the number of arguments
                   8478:  *
                   8479:  * Implement the last() XPath function
                   8480:  *    number last()
                   8481:  * The last function returns the number of nodes in the context node list.
                   8482:  */
                   8483: void
                   8484: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8485:     CHECK_ARITY(0);
                   8486:     if (ctxt->context->contextSize >= 0) {
                   8487:        valuePush(ctxt,
                   8488:            xmlXPathCacheNewFloat(ctxt->context,
                   8489:                (double) ctxt->context->contextSize));
                   8490: #ifdef DEBUG_EXPR
                   8491:        xmlGenericError(xmlGenericErrorContext,
                   8492:                "last() : %d\n", ctxt->context->contextSize);
                   8493: #endif
                   8494:     } else {
                   8495:        XP_ERROR(XPATH_INVALID_CTXT_SIZE);
                   8496:     }
                   8497: }
                   8498: 
                   8499: /**
                   8500:  * xmlXPathPositionFunction:
                   8501:  * @ctxt:  the XPath Parser context
                   8502:  * @nargs:  the number of arguments
                   8503:  *
                   8504:  * Implement the position() XPath function
                   8505:  *    number position()
                   8506:  * The position function returns the position of the context node in the
                   8507:  * context node list. The first position is 1, and so the last position
                   8508:  * will be equal to last().
                   8509:  */
                   8510: void
                   8511: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8512:     CHECK_ARITY(0);
                   8513:     if (ctxt->context->proximityPosition >= 0) {
                   8514:        valuePush(ctxt,
                   8515:              xmlXPathCacheNewFloat(ctxt->context,
                   8516:                (double) ctxt->context->proximityPosition));
                   8517: #ifdef DEBUG_EXPR
                   8518:        xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
                   8519:                ctxt->context->proximityPosition);
                   8520: #endif
                   8521:     } else {
                   8522:        XP_ERROR(XPATH_INVALID_CTXT_POSITION);
                   8523:     }
                   8524: }
                   8525: 
                   8526: /**
                   8527:  * xmlXPathCountFunction:
                   8528:  * @ctxt:  the XPath Parser context
                   8529:  * @nargs:  the number of arguments
                   8530:  *
                   8531:  * Implement the count() XPath function
                   8532:  *    number count(node-set)
                   8533:  */
                   8534: void
                   8535: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8536:     xmlXPathObjectPtr cur;
                   8537: 
                   8538:     CHECK_ARITY(1);
                   8539:     if ((ctxt->value == NULL) ||
                   8540:        ((ctxt->value->type != XPATH_NODESET) &&
                   8541:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   8542:        XP_ERROR(XPATH_INVALID_TYPE);
                   8543:     cur = valuePop(ctxt);
                   8544: 
                   8545:     if ((cur == NULL) || (cur->nodesetval == NULL))
                   8546:        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
                   8547:     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
                   8548:        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
                   8549:            (double) cur->nodesetval->nodeNr));
                   8550:     } else {
                   8551:        if ((cur->nodesetval->nodeNr != 1) ||
                   8552:            (cur->nodesetval->nodeTab == NULL)) {
                   8553:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
                   8554:        } else {
                   8555:            xmlNodePtr tmp;
                   8556:            int i = 0;
                   8557: 
                   8558:            tmp = cur->nodesetval->nodeTab[0];
1.1.1.3 ! misho    8559:            if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
1.1       misho    8560:                tmp = tmp->children;
                   8561:                while (tmp != NULL) {
                   8562:                    tmp = tmp->next;
                   8563:                    i++;
                   8564:                }
                   8565:            }
                   8566:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
                   8567:        }
                   8568:     }
                   8569:     xmlXPathReleaseObject(ctxt->context, cur);
                   8570: }
                   8571: 
                   8572: /**
                   8573:  * xmlXPathGetElementsByIds:
                   8574:  * @doc:  the document
                   8575:  * @ids:  a whitespace separated list of IDs
                   8576:  *
                   8577:  * Selects elements by their unique ID.
                   8578:  *
                   8579:  * Returns a node-set of selected elements.
                   8580:  */
                   8581: static xmlNodeSetPtr
                   8582: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
                   8583:     xmlNodeSetPtr ret;
                   8584:     const xmlChar *cur = ids;
                   8585:     xmlChar *ID;
                   8586:     xmlAttrPtr attr;
                   8587:     xmlNodePtr elem = NULL;
                   8588: 
                   8589:     if (ids == NULL) return(NULL);
                   8590: 
                   8591:     ret = xmlXPathNodeSetCreate(NULL);
                   8592:     if (ret == NULL)
                   8593:         return(ret);
                   8594: 
                   8595:     while (IS_BLANK_CH(*cur)) cur++;
                   8596:     while (*cur != 0) {
                   8597:        while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
                   8598:            cur++;
                   8599: 
                   8600:         ID = xmlStrndup(ids, cur - ids);
                   8601:        if (ID != NULL) {
                   8602:            /*
                   8603:             * We used to check the fact that the value passed
                   8604:             * was an NCName, but this generated much troubles for
                   8605:             * me and Aleksey Sanin, people blatantly violated that
                   8606:             * constaint, like Visa3D spec.
                   8607:             * if (xmlValidateNCName(ID, 1) == 0)
                   8608:             */
                   8609:            attr = xmlGetID(doc, ID);
                   8610:            if (attr != NULL) {
                   8611:                if (attr->type == XML_ATTRIBUTE_NODE)
                   8612:                    elem = attr->parent;
                   8613:                else if (attr->type == XML_ELEMENT_NODE)
                   8614:                    elem = (xmlNodePtr) attr;
                   8615:                else
                   8616:                    elem = NULL;
                   8617:                if (elem != NULL)
                   8618:                    xmlXPathNodeSetAdd(ret, elem);
                   8619:            }
                   8620:            xmlFree(ID);
                   8621:        }
                   8622: 
                   8623:        while (IS_BLANK_CH(*cur)) cur++;
                   8624:        ids = cur;
                   8625:     }
                   8626:     return(ret);
                   8627: }
                   8628: 
                   8629: /**
                   8630:  * xmlXPathIdFunction:
                   8631:  * @ctxt:  the XPath Parser context
                   8632:  * @nargs:  the number of arguments
                   8633:  *
                   8634:  * Implement the id() XPath function
                   8635:  *    node-set id(object)
                   8636:  * The id function selects elements by their unique ID
                   8637:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
                   8638:  * then the result is the union of the result of applying id to the
                   8639:  * string value of each of the nodes in the argument node-set. When the
                   8640:  * argument to id is of any other type, the argument is converted to a
                   8641:  * string as if by a call to the string function; the string is split
                   8642:  * into a whitespace-separated list of tokens (whitespace is any sequence
                   8643:  * of characters matching the production S); the result is a node-set
                   8644:  * containing the elements in the same document as the context node that
                   8645:  * have a unique ID equal to any of the tokens in the list.
                   8646:  */
                   8647: void
                   8648: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8649:     xmlChar *tokens;
                   8650:     xmlNodeSetPtr ret;
                   8651:     xmlXPathObjectPtr obj;
                   8652: 
                   8653:     CHECK_ARITY(1);
                   8654:     obj = valuePop(ctxt);
                   8655:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   8656:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
                   8657:        xmlNodeSetPtr ns;
                   8658:        int i;
                   8659: 
                   8660:        ret = xmlXPathNodeSetCreate(NULL);
                   8661:         /*
                   8662:          * FIXME -- in an out-of-memory condition this will behave badly.
                   8663:          * The solution is not clear -- we already popped an item from
                   8664:          * ctxt, so the object is in a corrupt state.
                   8665:          */
                   8666: 
                   8667:        if (obj->nodesetval != NULL) {
                   8668:            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
                   8669:                tokens =
                   8670:                    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
                   8671:                ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
                   8672:                ret = xmlXPathNodeSetMerge(ret, ns);
                   8673:                xmlXPathFreeNodeSet(ns);
                   8674:                if (tokens != NULL)
                   8675:                    xmlFree(tokens);
                   8676:            }
                   8677:        }
                   8678:        xmlXPathReleaseObject(ctxt->context, obj);
                   8679:        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
                   8680:        return;
                   8681:     }
                   8682:     obj = xmlXPathCacheConvertString(ctxt->context, obj);
                   8683:     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
                   8684:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
                   8685:     xmlXPathReleaseObject(ctxt->context, obj);
                   8686:     return;
                   8687: }
                   8688: 
                   8689: /**
                   8690:  * xmlXPathLocalNameFunction:
                   8691:  * @ctxt:  the XPath Parser context
                   8692:  * @nargs:  the number of arguments
                   8693:  *
                   8694:  * Implement the local-name() XPath function
                   8695:  *    string local-name(node-set?)
                   8696:  * The local-name function returns a string containing the local part
                   8697:  * of the name of the node in the argument node-set that is first in
                   8698:  * document order. If the node-set is empty or the first node has no
                   8699:  * name, an empty string is returned. If the argument is omitted it
                   8700:  * defaults to the context node.
                   8701:  */
                   8702: void
                   8703: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8704:     xmlXPathObjectPtr cur;
                   8705: 
                   8706:     if (ctxt == NULL) return;
                   8707: 
                   8708:     if (nargs == 0) {
                   8709:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8710:            ctxt->context->node));
                   8711:        nargs = 1;
                   8712:     }
                   8713: 
                   8714:     CHECK_ARITY(1);
                   8715:     if ((ctxt->value == NULL) ||
                   8716:        ((ctxt->value->type != XPATH_NODESET) &&
                   8717:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   8718:        XP_ERROR(XPATH_INVALID_TYPE);
                   8719:     cur = valuePop(ctxt);
                   8720: 
                   8721:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
                   8722:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8723:     } else {
                   8724:        int i = 0; /* Should be first in document order !!!!! */
                   8725:        switch (cur->nodesetval->nodeTab[i]->type) {
                   8726:        case XML_ELEMENT_NODE:
                   8727:        case XML_ATTRIBUTE_NODE:
                   8728:        case XML_PI_NODE:
                   8729:            if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
                   8730:                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8731:            else
                   8732:                valuePush(ctxt,
                   8733:                      xmlXPathCacheNewString(ctxt->context,
                   8734:                        cur->nodesetval->nodeTab[i]->name));
                   8735:            break;
                   8736:        case XML_NAMESPACE_DECL:
                   8737:            valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   8738:                        ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
                   8739:            break;
                   8740:        default:
                   8741:            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8742:        }
                   8743:     }
                   8744:     xmlXPathReleaseObject(ctxt->context, cur);
                   8745: }
                   8746: 
                   8747: /**
                   8748:  * xmlXPathNamespaceURIFunction:
                   8749:  * @ctxt:  the XPath Parser context
                   8750:  * @nargs:  the number of arguments
                   8751:  *
                   8752:  * Implement the namespace-uri() XPath function
                   8753:  *    string namespace-uri(node-set?)
                   8754:  * The namespace-uri function returns a string containing the
                   8755:  * namespace URI of the expanded name of the node in the argument
                   8756:  * node-set that is first in document order. If the node-set is empty,
                   8757:  * the first node has no name, or the expanded name has no namespace
                   8758:  * URI, an empty string is returned. If the argument is omitted it
                   8759:  * defaults to the context node.
                   8760:  */
                   8761: void
                   8762: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8763:     xmlXPathObjectPtr cur;
                   8764: 
                   8765:     if (ctxt == NULL) return;
                   8766: 
                   8767:     if (nargs == 0) {
                   8768:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8769:            ctxt->context->node));
                   8770:        nargs = 1;
                   8771:     }
                   8772:     CHECK_ARITY(1);
                   8773:     if ((ctxt->value == NULL) ||
                   8774:        ((ctxt->value->type != XPATH_NODESET) &&
                   8775:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   8776:        XP_ERROR(XPATH_INVALID_TYPE);
                   8777:     cur = valuePop(ctxt);
                   8778: 
                   8779:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
                   8780:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8781:     } else {
                   8782:        int i = 0; /* Should be first in document order !!!!! */
                   8783:        switch (cur->nodesetval->nodeTab[i]->type) {
                   8784:        case XML_ELEMENT_NODE:
                   8785:        case XML_ATTRIBUTE_NODE:
                   8786:            if (cur->nodesetval->nodeTab[i]->ns == NULL)
                   8787:                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8788:            else
                   8789:                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
                   8790:                          cur->nodesetval->nodeTab[i]->ns->href));
                   8791:            break;
                   8792:        default:
                   8793:            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8794:        }
                   8795:     }
                   8796:     xmlXPathReleaseObject(ctxt->context, cur);
                   8797: }
                   8798: 
                   8799: /**
                   8800:  * xmlXPathNameFunction:
                   8801:  * @ctxt:  the XPath Parser context
                   8802:  * @nargs:  the number of arguments
                   8803:  *
                   8804:  * Implement the name() XPath function
                   8805:  *    string name(node-set?)
                   8806:  * The name function returns a string containing a QName representing
                   8807:  * the name of the node in the argument node-set that is first in document
                   8808:  * order. The QName must represent the name with respect to the namespace
                   8809:  * declarations in effect on the node whose name is being represented.
                   8810:  * Typically, this will be the form in which the name occurred in the XML
                   8811:  * source. This need not be the case if there are namespace declarations
                   8812:  * in effect on the node that associate multiple prefixes with the same
                   8813:  * namespace. However, an implementation may include information about
                   8814:  * the original prefix in its representation of nodes; in this case, an
                   8815:  * implementation can ensure that the returned string is always the same
                   8816:  * as the QName used in the XML source. If the argument it omitted it
                   8817:  * defaults to the context node.
                   8818:  * Libxml keep the original prefix so the "real qualified name" used is
                   8819:  * returned.
                   8820:  */
                   8821: static void
                   8822: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
                   8823: {
                   8824:     xmlXPathObjectPtr cur;
                   8825: 
                   8826:     if (nargs == 0) {
                   8827:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8828:            ctxt->context->node));
                   8829:         nargs = 1;
                   8830:     }
                   8831: 
                   8832:     CHECK_ARITY(1);
                   8833:     if ((ctxt->value == NULL) ||
                   8834:         ((ctxt->value->type != XPATH_NODESET) &&
                   8835:          (ctxt->value->type != XPATH_XSLT_TREE)))
                   8836:         XP_ERROR(XPATH_INVALID_TYPE);
                   8837:     cur = valuePop(ctxt);
                   8838: 
                   8839:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
                   8840:         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   8841:     } else {
                   8842:         int i = 0;              /* Should be first in document order !!!!! */
                   8843: 
                   8844:         switch (cur->nodesetval->nodeTab[i]->type) {
                   8845:             case XML_ELEMENT_NODE:
                   8846:             case XML_ATTRIBUTE_NODE:
                   8847:                if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
                   8848:                    valuePush(ctxt,
                   8849:                        xmlXPathCacheNewCString(ctxt->context, ""));
                   8850:                else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
                   8851:                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
                   8852:                    valuePush(ctxt,
                   8853:                        xmlXPathCacheNewString(ctxt->context,
                   8854:                            cur->nodesetval->nodeTab[i]->name));
                   8855:                } else {
                   8856:                    xmlChar *fullname;
                   8857: 
                   8858:                    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
                   8859:                                     cur->nodesetval->nodeTab[i]->ns->prefix,
                   8860:                                     NULL, 0);
                   8861:                    if (fullname == cur->nodesetval->nodeTab[i]->name)
                   8862:                        fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
                   8863:                    if (fullname == NULL) {
                   8864:                        XP_ERROR(XPATH_MEMORY_ERROR);
                   8865:                    }
                   8866:                    valuePush(ctxt, xmlXPathCacheWrapString(
                   8867:                        ctxt->context, fullname));
                   8868:                 }
                   8869:                 break;
                   8870:             default:
                   8871:                valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   8872:                    cur->nodesetval->nodeTab[i]));
                   8873:                 xmlXPathLocalNameFunction(ctxt, 1);
                   8874:         }
                   8875:     }
                   8876:     xmlXPathReleaseObject(ctxt->context, cur);
                   8877: }
                   8878: 
                   8879: 
                   8880: /**
                   8881:  * xmlXPathStringFunction:
                   8882:  * @ctxt:  the XPath Parser context
                   8883:  * @nargs:  the number of arguments
                   8884:  *
                   8885:  * Implement the string() XPath function
                   8886:  *    string string(object?)
                   8887:  * The string function converts an object to a string as follows:
                   8888:  *    - A node-set is converted to a string by returning the value of
                   8889:  *      the node in the node-set that is first in document order.
                   8890:  *      If the node-set is empty, an empty string is returned.
                   8891:  *    - A number is converted to a string as follows
                   8892:  *      + NaN is converted to the string NaN
                   8893:  *      + positive zero is converted to the string 0
                   8894:  *      + negative zero is converted to the string 0
                   8895:  *      + positive infinity is converted to the string Infinity
                   8896:  *      + negative infinity is converted to the string -Infinity
                   8897:  *      + if the number is an integer, the number is represented in
                   8898:  *        decimal form as a Number with no decimal point and no leading
                   8899:  *        zeros, preceded by a minus sign (-) if the number is negative
                   8900:  *      + otherwise, the number is represented in decimal form as a
                   8901:  *        Number including a decimal point with at least one digit
                   8902:  *        before the decimal point and at least one digit after the
                   8903:  *        decimal point, preceded by a minus sign (-) if the number
                   8904:  *        is negative; there must be no leading zeros before the decimal
                   8905:  *        point apart possibly from the one required digit immediately
                   8906:  *        before the decimal point; beyond the one required digit
                   8907:  *        after the decimal point there must be as many, but only as
                   8908:  *        many, more digits as are needed to uniquely distinguish the
                   8909:  *        number from all other IEEE 754 numeric values.
                   8910:  *    - The boolean false value is converted to the string false.
                   8911:  *      The boolean true value is converted to the string true.
                   8912:  *
                   8913:  * If the argument is omitted, it defaults to a node-set with the
                   8914:  * context node as its only member.
                   8915:  */
                   8916: void
                   8917: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8918:     xmlXPathObjectPtr cur;
                   8919: 
                   8920:     if (ctxt == NULL) return;
                   8921:     if (nargs == 0) {
                   8922:     valuePush(ctxt,
                   8923:        xmlXPathCacheWrapString(ctxt->context,
                   8924:            xmlXPathCastNodeToString(ctxt->context->node)));
                   8925:        return;
                   8926:     }
                   8927: 
                   8928:     CHECK_ARITY(1);
                   8929:     cur = valuePop(ctxt);
                   8930:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   8931:     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
                   8932: }
                   8933: 
                   8934: /**
                   8935:  * xmlXPathStringLengthFunction:
                   8936:  * @ctxt:  the XPath Parser context
                   8937:  * @nargs:  the number of arguments
                   8938:  *
                   8939:  * Implement the string-length() XPath function
                   8940:  *    number string-length(string?)
                   8941:  * The string-length returns the number of characters in the string
                   8942:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
                   8943:  * the context node converted to a string, in other words the value
                   8944:  * of the context node.
                   8945:  */
                   8946: void
                   8947: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8948:     xmlXPathObjectPtr cur;
                   8949: 
                   8950:     if (nargs == 0) {
                   8951:         if ((ctxt == NULL) || (ctxt->context == NULL))
                   8952:            return;
                   8953:        if (ctxt->context->node == NULL) {
                   8954:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
                   8955:        } else {
                   8956:            xmlChar *content;
                   8957: 
                   8958:            content = xmlXPathCastNodeToString(ctxt->context->node);
                   8959:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
                   8960:                xmlUTF8Strlen(content)));
                   8961:            xmlFree(content);
                   8962:        }
                   8963:        return;
                   8964:     }
                   8965:     CHECK_ARITY(1);
                   8966:     CAST_TO_STRING;
                   8967:     CHECK_TYPE(XPATH_STRING);
                   8968:     cur = valuePop(ctxt);
                   8969:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
                   8970:        xmlUTF8Strlen(cur->stringval)));
                   8971:     xmlXPathReleaseObject(ctxt->context, cur);
                   8972: }
                   8973: 
                   8974: /**
                   8975:  * xmlXPathConcatFunction:
                   8976:  * @ctxt:  the XPath Parser context
                   8977:  * @nargs:  the number of arguments
                   8978:  *
                   8979:  * Implement the concat() XPath function
                   8980:  *    string concat(string, string, string*)
                   8981:  * The concat function returns the concatenation of its arguments.
                   8982:  */
                   8983: void
                   8984: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   8985:     xmlXPathObjectPtr cur, newobj;
                   8986:     xmlChar *tmp;
                   8987: 
                   8988:     if (ctxt == NULL) return;
                   8989:     if (nargs < 2) {
                   8990:        CHECK_ARITY(2);
                   8991:     }
                   8992: 
                   8993:     CAST_TO_STRING;
                   8994:     cur = valuePop(ctxt);
                   8995:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
                   8996:        xmlXPathReleaseObject(ctxt->context, cur);
                   8997:        return;
                   8998:     }
                   8999:     nargs--;
                   9000: 
                   9001:     while (nargs > 0) {
                   9002:        CAST_TO_STRING;
                   9003:        newobj = valuePop(ctxt);
                   9004:        if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
                   9005:            xmlXPathReleaseObject(ctxt->context, newobj);
                   9006:            xmlXPathReleaseObject(ctxt->context, cur);
                   9007:            XP_ERROR(XPATH_INVALID_TYPE);
                   9008:        }
                   9009:        tmp = xmlStrcat(newobj->stringval, cur->stringval);
                   9010:        newobj->stringval = cur->stringval;
                   9011:        cur->stringval = tmp;
                   9012:        xmlXPathReleaseObject(ctxt->context, newobj);
                   9013:        nargs--;
                   9014:     }
                   9015:     valuePush(ctxt, cur);
                   9016: }
                   9017: 
                   9018: /**
                   9019:  * xmlXPathContainsFunction:
                   9020:  * @ctxt:  the XPath Parser context
                   9021:  * @nargs:  the number of arguments
                   9022:  *
                   9023:  * Implement the contains() XPath function
                   9024:  *    boolean contains(string, string)
                   9025:  * The contains function returns true if the first argument string
                   9026:  * contains the second argument string, and otherwise returns false.
                   9027:  */
                   9028: void
                   9029: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9030:     xmlXPathObjectPtr hay, needle;
                   9031: 
                   9032:     CHECK_ARITY(2);
                   9033:     CAST_TO_STRING;
                   9034:     CHECK_TYPE(XPATH_STRING);
                   9035:     needle = valuePop(ctxt);
                   9036:     CAST_TO_STRING;
                   9037:     hay = valuePop(ctxt);
                   9038: 
                   9039:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
                   9040:        xmlXPathReleaseObject(ctxt->context, hay);
                   9041:        xmlXPathReleaseObject(ctxt->context, needle);
                   9042:        XP_ERROR(XPATH_INVALID_TYPE);
                   9043:     }
                   9044:     if (xmlStrstr(hay->stringval, needle->stringval))
                   9045:        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
                   9046:     else
                   9047:        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
                   9048:     xmlXPathReleaseObject(ctxt->context, hay);
                   9049:     xmlXPathReleaseObject(ctxt->context, needle);
                   9050: }
                   9051: 
                   9052: /**
                   9053:  * xmlXPathStartsWithFunction:
                   9054:  * @ctxt:  the XPath Parser context
                   9055:  * @nargs:  the number of arguments
                   9056:  *
                   9057:  * Implement the starts-with() XPath function
                   9058:  *    boolean starts-with(string, string)
                   9059:  * The starts-with function returns true if the first argument string
                   9060:  * starts with the second argument string, and otherwise returns false.
                   9061:  */
                   9062: void
                   9063: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9064:     xmlXPathObjectPtr hay, needle;
                   9065:     int n;
                   9066: 
                   9067:     CHECK_ARITY(2);
                   9068:     CAST_TO_STRING;
                   9069:     CHECK_TYPE(XPATH_STRING);
                   9070:     needle = valuePop(ctxt);
                   9071:     CAST_TO_STRING;
                   9072:     hay = valuePop(ctxt);
                   9073: 
                   9074:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
                   9075:        xmlXPathReleaseObject(ctxt->context, hay);
                   9076:        xmlXPathReleaseObject(ctxt->context, needle);
                   9077:        XP_ERROR(XPATH_INVALID_TYPE);
                   9078:     }
                   9079:     n = xmlStrlen(needle->stringval);
                   9080:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
                   9081:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
                   9082:     else
                   9083:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
                   9084:     xmlXPathReleaseObject(ctxt->context, hay);
                   9085:     xmlXPathReleaseObject(ctxt->context, needle);
                   9086: }
                   9087: 
                   9088: /**
                   9089:  * xmlXPathSubstringFunction:
                   9090:  * @ctxt:  the XPath Parser context
                   9091:  * @nargs:  the number of arguments
                   9092:  *
                   9093:  * Implement the substring() XPath function
                   9094:  *    string substring(string, number, number?)
                   9095:  * The substring function returns the substring of the first argument
                   9096:  * starting at the position specified in the second argument with
                   9097:  * length specified in the third argument. For example,
                   9098:  * substring("12345",2,3) returns "234". If the third argument is not
                   9099:  * specified, it returns the substring starting at the position specified
                   9100:  * in the second argument and continuing to the end of the string. For
                   9101:  * example, substring("12345",2) returns "2345".  More precisely, each
                   9102:  * character in the string (see [3.6 Strings]) is considered to have a
                   9103:  * numeric position: the position of the first character is 1, the position
                   9104:  * of the second character is 2 and so on. The returned substring contains
                   9105:  * those characters for which the position of the character is greater than
                   9106:  * or equal to the second argument and, if the third argument is specified,
                   9107:  * less than the sum of the second and third arguments; the comparisons
                   9108:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
                   9109:  *  - substring("12345", 1.5, 2.6) returns "234"
                   9110:  *  - substring("12345", 0, 3) returns "12"
                   9111:  *  - substring("12345", 0 div 0, 3) returns ""
                   9112:  *  - substring("12345", 1, 0 div 0) returns ""
                   9113:  *  - substring("12345", -42, 1 div 0) returns "12345"
                   9114:  *  - substring("12345", -1 div 0, 1 div 0) returns ""
                   9115:  */
                   9116: void
                   9117: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9118:     xmlXPathObjectPtr str, start, len;
                   9119:     double le=0, in;
                   9120:     int i, l, m;
                   9121:     xmlChar *ret;
                   9122: 
                   9123:     if (nargs < 2) {
                   9124:        CHECK_ARITY(2);
                   9125:     }
                   9126:     if (nargs > 3) {
                   9127:        CHECK_ARITY(3);
                   9128:     }
                   9129:     /*
                   9130:      * take care of possible last (position) argument
                   9131:     */
                   9132:     if (nargs == 3) {
                   9133:        CAST_TO_NUMBER;
                   9134:        CHECK_TYPE(XPATH_NUMBER);
                   9135:        len = valuePop(ctxt);
                   9136:        le = len->floatval;
                   9137:        xmlXPathReleaseObject(ctxt->context, len);
                   9138:     }
                   9139: 
                   9140:     CAST_TO_NUMBER;
                   9141:     CHECK_TYPE(XPATH_NUMBER);
                   9142:     start = valuePop(ctxt);
                   9143:     in = start->floatval;
                   9144:     xmlXPathReleaseObject(ctxt->context, start);
                   9145:     CAST_TO_STRING;
                   9146:     CHECK_TYPE(XPATH_STRING);
                   9147:     str = valuePop(ctxt);
                   9148:     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
                   9149: 
                   9150:     /*
                   9151:      * If last pos not present, calculate last position
                   9152:     */
                   9153:     if (nargs != 3) {
                   9154:        le = (double)m;
                   9155:        if (in < 1.0)
                   9156:            in = 1.0;
                   9157:     }
                   9158: 
                   9159:     /* Need to check for the special cases where either
                   9160:      * the index is NaN, the length is NaN, or both
                   9161:      * arguments are infinity (relying on Inf + -Inf = NaN)
                   9162:      */
                   9163:     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
                   9164:         /*
                   9165:          * To meet the requirements of the spec, the arguments
                   9166:         * must be converted to integer format before
                   9167:         * initial index calculations are done
                   9168:          *
                   9169:          * First we go to integer form, rounding up
                   9170:         * and checking for special cases
                   9171:          */
                   9172:         i = (int) in;
                   9173:         if (((double)i)+0.5 <= in) i++;
                   9174: 
                   9175:        if (xmlXPathIsInf(le) == 1) {
                   9176:            l = m;
                   9177:            if (i < 1)
                   9178:                i = 1;
                   9179:        }
                   9180:        else if (xmlXPathIsInf(le) == -1 || le < 0.0)
                   9181:            l = 0;
                   9182:        else {
                   9183:            l = (int) le;
                   9184:            if (((double)l)+0.5 <= le) l++;
                   9185:        }
                   9186: 
                   9187:        /* Now we normalize inidices */
                   9188:         i -= 1;
                   9189:         l += i;
                   9190:         if (i < 0)
                   9191:             i = 0;
                   9192:         if (l > m)
                   9193:             l = m;
                   9194: 
                   9195:         /* number of chars to copy */
                   9196:         l -= i;
                   9197: 
                   9198:         ret = xmlUTF8Strsub(str->stringval, i, l);
                   9199:     }
                   9200:     else {
                   9201:         ret = NULL;
                   9202:     }
                   9203:     if (ret == NULL)
                   9204:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
                   9205:     else {
                   9206:        valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
                   9207:        xmlFree(ret);
                   9208:     }
                   9209:     xmlXPathReleaseObject(ctxt->context, str);
                   9210: }
                   9211: 
                   9212: /**
                   9213:  * xmlXPathSubstringBeforeFunction:
                   9214:  * @ctxt:  the XPath Parser context
                   9215:  * @nargs:  the number of arguments
                   9216:  *
                   9217:  * Implement the substring-before() XPath function
                   9218:  *    string substring-before(string, string)
                   9219:  * The substring-before function returns the substring of the first
                   9220:  * argument string that precedes the first occurrence of the second
                   9221:  * argument string in the first argument string, or the empty string
                   9222:  * if the first argument string does not contain the second argument
                   9223:  * string. For example, substring-before("1999/04/01","/") returns 1999.
                   9224:  */
                   9225: void
                   9226: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9227:   xmlXPathObjectPtr str;
                   9228:   xmlXPathObjectPtr find;
1.1.1.3 ! misho    9229:   xmlBufPtr target;
1.1       misho    9230:   const xmlChar *point;
                   9231:   int offset;
                   9232: 
                   9233:   CHECK_ARITY(2);
                   9234:   CAST_TO_STRING;
                   9235:   find = valuePop(ctxt);
                   9236:   CAST_TO_STRING;
                   9237:   str = valuePop(ctxt);
                   9238: 
1.1.1.3 ! misho    9239:   target = xmlBufCreate();
1.1       misho    9240:   if (target) {
                   9241:     point = xmlStrstr(str->stringval, find->stringval);
                   9242:     if (point) {
                   9243:       offset = (int)(point - str->stringval);
1.1.1.3 ! misho    9244:       xmlBufAdd(target, str->stringval, offset);
1.1       misho    9245:     }
                   9246:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
1.1.1.3 ! misho    9247:        xmlBufContent(target)));
        !          9248:     xmlBufFree(target);
1.1       misho    9249:   }
                   9250:   xmlXPathReleaseObject(ctxt->context, str);
                   9251:   xmlXPathReleaseObject(ctxt->context, find);
                   9252: }
                   9253: 
                   9254: /**
                   9255:  * xmlXPathSubstringAfterFunction:
                   9256:  * @ctxt:  the XPath Parser context
                   9257:  * @nargs:  the number of arguments
                   9258:  *
                   9259:  * Implement the substring-after() XPath function
                   9260:  *    string substring-after(string, string)
                   9261:  * The substring-after function returns the substring of the first
                   9262:  * argument string that follows the first occurrence of the second
                   9263:  * argument string in the first argument string, or the empty stringi
                   9264:  * if the first argument string does not contain the second argument
                   9265:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
                   9266:  * and substring-after("1999/04/01","19") returns 99/04/01.
                   9267:  */
                   9268: void
                   9269: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9270:   xmlXPathObjectPtr str;
                   9271:   xmlXPathObjectPtr find;
1.1.1.3 ! misho    9272:   xmlBufPtr target;
1.1       misho    9273:   const xmlChar *point;
                   9274:   int offset;
                   9275: 
                   9276:   CHECK_ARITY(2);
                   9277:   CAST_TO_STRING;
                   9278:   find = valuePop(ctxt);
                   9279:   CAST_TO_STRING;
                   9280:   str = valuePop(ctxt);
                   9281: 
1.1.1.3 ! misho    9282:   target = xmlBufCreate();
1.1       misho    9283:   if (target) {
                   9284:     point = xmlStrstr(str->stringval, find->stringval);
                   9285:     if (point) {
                   9286:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
1.1.1.3 ! misho    9287:       xmlBufAdd(target, &str->stringval[offset],
1.1       misho    9288:                   xmlStrlen(str->stringval) - offset);
                   9289:     }
                   9290:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
1.1.1.3 ! misho    9291:        xmlBufContent(target)));
        !          9292:     xmlBufFree(target);
1.1       misho    9293:   }
                   9294:   xmlXPathReleaseObject(ctxt->context, str);
                   9295:   xmlXPathReleaseObject(ctxt->context, find);
                   9296: }
                   9297: 
                   9298: /**
                   9299:  * xmlXPathNormalizeFunction:
                   9300:  * @ctxt:  the XPath Parser context
                   9301:  * @nargs:  the number of arguments
                   9302:  *
                   9303:  * Implement the normalize-space() XPath function
                   9304:  *    string normalize-space(string?)
                   9305:  * The normalize-space function returns the argument string with white
                   9306:  * space normalized by stripping leading and trailing whitespace
                   9307:  * and replacing sequences of whitespace characters by a single
                   9308:  * space. Whitespace characters are the same allowed by the S production
                   9309:  * in XML. If the argument is omitted, it defaults to the context
                   9310:  * node converted to a string, in other words the value of the context node.
                   9311:  */
                   9312: void
                   9313: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9314:   xmlXPathObjectPtr obj = NULL;
                   9315:   xmlChar *source = NULL;
1.1.1.3 ! misho    9316:   xmlBufPtr target;
1.1       misho    9317:   xmlChar blank;
                   9318: 
                   9319:   if (ctxt == NULL) return;
                   9320:   if (nargs == 0) {
                   9321:     /* Use current context node */
                   9322:       valuePush(ctxt,
                   9323:          xmlXPathCacheWrapString(ctxt->context,
                   9324:            xmlXPathCastNodeToString(ctxt->context->node)));
                   9325:     nargs = 1;
                   9326:   }
                   9327: 
                   9328:   CHECK_ARITY(1);
                   9329:   CAST_TO_STRING;
                   9330:   CHECK_TYPE(XPATH_STRING);
                   9331:   obj = valuePop(ctxt);
                   9332:   source = obj->stringval;
                   9333: 
1.1.1.3 ! misho    9334:   target = xmlBufCreate();
1.1       misho    9335:   if (target && source) {
                   9336: 
                   9337:     /* Skip leading whitespaces */
                   9338:     while (IS_BLANK_CH(*source))
                   9339:       source++;
                   9340: 
                   9341:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
                   9342:     blank = 0;
                   9343:     while (*source) {
                   9344:       if (IS_BLANK_CH(*source)) {
                   9345:        blank = 0x20;
                   9346:       } else {
                   9347:        if (blank) {
1.1.1.3 ! misho    9348:          xmlBufAdd(target, &blank, 1);
1.1       misho    9349:          blank = 0;
                   9350:        }
1.1.1.3 ! misho    9351:        xmlBufAdd(target, source, 1);
1.1       misho    9352:       }
                   9353:       source++;
                   9354:     }
                   9355:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
1.1.1.3 ! misho    9356:        xmlBufContent(target)));
        !          9357:     xmlBufFree(target);
1.1       misho    9358:   }
                   9359:   xmlXPathReleaseObject(ctxt->context, obj);
                   9360: }
                   9361: 
                   9362: /**
                   9363:  * xmlXPathTranslateFunction:
                   9364:  * @ctxt:  the XPath Parser context
                   9365:  * @nargs:  the number of arguments
                   9366:  *
                   9367:  * Implement the translate() XPath function
                   9368:  *    string translate(string, string, string)
                   9369:  * The translate function returns the first argument string with
                   9370:  * occurrences of characters in the second argument string replaced
                   9371:  * by the character at the corresponding position in the third argument
                   9372:  * string. For example, translate("bar","abc","ABC") returns the string
                   9373:  * BAr. If there is a character in the second argument string with no
                   9374:  * character at a corresponding position in the third argument string
                   9375:  * (because the second argument string is longer than the third argument
                   9376:  * string), then occurrences of that character in the first argument
                   9377:  * string are removed. For example, translate("--aaa--","abc-","ABC")
                   9378:  * returns "AAA". If a character occurs more than once in second
                   9379:  * argument string, then the first occurrence determines the replacement
                   9380:  * character. If the third argument string is longer than the second
                   9381:  * argument string, then excess characters are ignored.
                   9382:  */
                   9383: void
                   9384: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9385:     xmlXPathObjectPtr str;
                   9386:     xmlXPathObjectPtr from;
                   9387:     xmlXPathObjectPtr to;
1.1.1.3 ! misho    9388:     xmlBufPtr target;
1.1       misho    9389:     int offset, max;
                   9390:     xmlChar ch;
                   9391:     const xmlChar *point;
                   9392:     xmlChar *cptr;
                   9393: 
                   9394:     CHECK_ARITY(3);
                   9395: 
                   9396:     CAST_TO_STRING;
                   9397:     to = valuePop(ctxt);
                   9398:     CAST_TO_STRING;
                   9399:     from = valuePop(ctxt);
                   9400:     CAST_TO_STRING;
                   9401:     str = valuePop(ctxt);
                   9402: 
1.1.1.3 ! misho    9403:     target = xmlBufCreate();
1.1       misho    9404:     if (target) {
                   9405:        max = xmlUTF8Strlen(to->stringval);
                   9406:        for (cptr = str->stringval; (ch=*cptr); ) {
                   9407:            offset = xmlUTF8Strloc(from->stringval, cptr);
                   9408:            if (offset >= 0) {
                   9409:                if (offset < max) {
                   9410:                    point = xmlUTF8Strpos(to->stringval, offset);
                   9411:                    if (point)
1.1.1.3 ! misho    9412:                        xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
1.1       misho    9413:                }
                   9414:            } else
1.1.1.3 ! misho    9415:                xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
1.1       misho    9416: 
                   9417:            /* Step to next character in input */
                   9418:            cptr++;
                   9419:            if ( ch & 0x80 ) {
                   9420:                /* if not simple ascii, verify proper format */
                   9421:                if ( (ch & 0xc0) != 0xc0 ) {
                   9422:                    xmlGenericError(xmlGenericErrorContext,
                   9423:                        "xmlXPathTranslateFunction: Invalid UTF8 string\n");
1.1.1.2   misho    9424:                     /* not asserting an XPath error is probably better */
1.1       misho    9425:                    break;
                   9426:                }
                   9427:                /* then skip over remaining bytes for this char */
                   9428:                while ( (ch <<= 1) & 0x80 )
                   9429:                    if ( (*cptr++ & 0xc0) != 0x80 ) {
                   9430:                        xmlGenericError(xmlGenericErrorContext,
                   9431:                            "xmlXPathTranslateFunction: Invalid UTF8 string\n");
1.1.1.2   misho    9432:                         /* not asserting an XPath error is probably better */
1.1       misho    9433:                        break;
                   9434:                    }
                   9435:                if (ch & 0x80) /* must have had error encountered */
                   9436:                    break;
                   9437:            }
                   9438:        }
                   9439:     }
                   9440:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
1.1.1.3 ! misho    9441:        xmlBufContent(target)));
        !          9442:     xmlBufFree(target);
1.1       misho    9443:     xmlXPathReleaseObject(ctxt->context, str);
                   9444:     xmlXPathReleaseObject(ctxt->context, from);
                   9445:     xmlXPathReleaseObject(ctxt->context, to);
                   9446: }
                   9447: 
                   9448: /**
                   9449:  * xmlXPathBooleanFunction:
                   9450:  * @ctxt:  the XPath Parser context
                   9451:  * @nargs:  the number of arguments
                   9452:  *
                   9453:  * Implement the boolean() XPath function
                   9454:  *    boolean boolean(object)
                   9455:  * The boolean function converts its argument to a boolean as follows:
                   9456:  *    - a number is true if and only if it is neither positive or
                   9457:  *      negative zero nor NaN
                   9458:  *    - a node-set is true if and only if it is non-empty
                   9459:  *    - a string is true if and only if its length is non-zero
                   9460:  */
                   9461: void
                   9462: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9463:     xmlXPathObjectPtr cur;
                   9464: 
                   9465:     CHECK_ARITY(1);
                   9466:     cur = valuePop(ctxt);
                   9467:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   9468:     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
                   9469:     valuePush(ctxt, cur);
                   9470: }
                   9471: 
                   9472: /**
                   9473:  * xmlXPathNotFunction:
                   9474:  * @ctxt:  the XPath Parser context
                   9475:  * @nargs:  the number of arguments
                   9476:  *
                   9477:  * Implement the not() XPath function
                   9478:  *    boolean not(boolean)
                   9479:  * The not function returns true if its argument is false,
                   9480:  * and false otherwise.
                   9481:  */
                   9482: void
                   9483: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9484:     CHECK_ARITY(1);
                   9485:     CAST_TO_BOOLEAN;
                   9486:     CHECK_TYPE(XPATH_BOOLEAN);
                   9487:     ctxt->value->boolval = ! ctxt->value->boolval;
                   9488: }
                   9489: 
                   9490: /**
                   9491:  * xmlXPathTrueFunction:
                   9492:  * @ctxt:  the XPath Parser context
                   9493:  * @nargs:  the number of arguments
                   9494:  *
                   9495:  * Implement the true() XPath function
                   9496:  *    boolean true()
                   9497:  */
                   9498: void
                   9499: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9500:     CHECK_ARITY(0);
                   9501:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
                   9502: }
                   9503: 
                   9504: /**
                   9505:  * xmlXPathFalseFunction:
                   9506:  * @ctxt:  the XPath Parser context
                   9507:  * @nargs:  the number of arguments
                   9508:  *
                   9509:  * Implement the false() XPath function
                   9510:  *    boolean false()
                   9511:  */
                   9512: void
                   9513: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9514:     CHECK_ARITY(0);
                   9515:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
                   9516: }
                   9517: 
                   9518: /**
                   9519:  * xmlXPathLangFunction:
                   9520:  * @ctxt:  the XPath Parser context
                   9521:  * @nargs:  the number of arguments
                   9522:  *
                   9523:  * Implement the lang() XPath function
                   9524:  *    boolean lang(string)
                   9525:  * The lang function returns true or false depending on whether the
                   9526:  * language of the context node as specified by xml:lang attributes
                   9527:  * is the same as or is a sublanguage of the language specified by
                   9528:  * the argument string. The language of the context node is determined
                   9529:  * by the value of the xml:lang attribute on the context node, or, if
                   9530:  * the context node has no xml:lang attribute, by the value of the
                   9531:  * xml:lang attribute on the nearest ancestor of the context node that
                   9532:  * has an xml:lang attribute. If there is no such attribute, then lang
                   9533:  * returns false. If there is such an attribute, then lang returns
                   9534:  * true if the attribute value is equal to the argument ignoring case,
                   9535:  * or if there is some suffix starting with - such that the attribute
                   9536:  * value is equal to the argument ignoring that suffix of the attribute
                   9537:  * value and ignoring case.
                   9538:  */
                   9539: void
                   9540: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9541:     xmlXPathObjectPtr val = NULL;
                   9542:     const xmlChar *theLang = NULL;
                   9543:     const xmlChar *lang;
                   9544:     int ret = 0;
                   9545:     int i;
                   9546: 
                   9547:     CHECK_ARITY(1);
                   9548:     CAST_TO_STRING;
                   9549:     CHECK_TYPE(XPATH_STRING);
                   9550:     val = valuePop(ctxt);
                   9551:     lang = val->stringval;
                   9552:     theLang = xmlNodeGetLang(ctxt->context->node);
                   9553:     if ((theLang != NULL) && (lang != NULL)) {
                   9554:         for (i = 0;lang[i] != 0;i++)
                   9555:            if (toupper(lang[i]) != toupper(theLang[i]))
                   9556:                goto not_equal;
                   9557:        if ((theLang[i] == 0) || (theLang[i] == '-'))
                   9558:            ret = 1;
                   9559:     }
                   9560: not_equal:
                   9561:     if (theLang != NULL)
                   9562:        xmlFree((void *)theLang);
                   9563: 
                   9564:     xmlXPathReleaseObject(ctxt->context, val);
                   9565:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
                   9566: }
                   9567: 
                   9568: /**
                   9569:  * xmlXPathNumberFunction:
                   9570:  * @ctxt:  the XPath Parser context
                   9571:  * @nargs:  the number of arguments
                   9572:  *
                   9573:  * Implement the number() XPath function
                   9574:  *    number number(object?)
                   9575:  */
                   9576: void
                   9577: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9578:     xmlXPathObjectPtr cur;
                   9579:     double res;
                   9580: 
                   9581:     if (ctxt == NULL) return;
                   9582:     if (nargs == 0) {
                   9583:        if (ctxt->context->node == NULL) {
                   9584:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
                   9585:        } else {
                   9586:            xmlChar* content = xmlNodeGetContent(ctxt->context->node);
                   9587: 
                   9588:            res = xmlXPathStringEvalNumber(content);
                   9589:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
                   9590:            xmlFree(content);
                   9591:        }
                   9592:        return;
                   9593:     }
                   9594: 
                   9595:     CHECK_ARITY(1);
                   9596:     cur = valuePop(ctxt);
                   9597:     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
                   9598: }
                   9599: 
                   9600: /**
                   9601:  * xmlXPathSumFunction:
                   9602:  * @ctxt:  the XPath Parser context
                   9603:  * @nargs:  the number of arguments
                   9604:  *
                   9605:  * Implement the sum() XPath function
                   9606:  *    number sum(node-set)
                   9607:  * The sum function returns the sum of the values of the nodes in
                   9608:  * the argument node-set.
                   9609:  */
                   9610: void
                   9611: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9612:     xmlXPathObjectPtr cur;
                   9613:     int i;
                   9614:     double res = 0.0;
                   9615: 
                   9616:     CHECK_ARITY(1);
                   9617:     if ((ctxt->value == NULL) ||
                   9618:        ((ctxt->value->type != XPATH_NODESET) &&
                   9619:         (ctxt->value->type != XPATH_XSLT_TREE)))
                   9620:        XP_ERROR(XPATH_INVALID_TYPE);
                   9621:     cur = valuePop(ctxt);
                   9622: 
                   9623:     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
                   9624:        for (i = 0; i < cur->nodesetval->nodeNr; i++) {
                   9625:            res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
                   9626:        }
                   9627:     }
                   9628:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
                   9629:     xmlXPathReleaseObject(ctxt->context, cur);
                   9630: }
                   9631: 
                   9632: /*
                   9633:  * To assure working code on multiple platforms, we want to only depend
                   9634:  * upon the characteristic truncation of converting a floating point value
                   9635:  * to an integer.  Unfortunately, because of the different storage sizes
                   9636:  * of our internal floating point value (double) and integer (int), we
                   9637:  * can't directly convert (see bug 301162).  This macro is a messy
                   9638:  * 'workaround'
                   9639:  */
                   9640: #define XTRUNC(f, v)            \
                   9641:     f = fmod((v), INT_MAX);     \
                   9642:     f = (v) - (f) + (double)((int)(f));
                   9643: 
                   9644: /**
                   9645:  * xmlXPathFloorFunction:
                   9646:  * @ctxt:  the XPath Parser context
                   9647:  * @nargs:  the number of arguments
                   9648:  *
                   9649:  * Implement the floor() XPath function
                   9650:  *    number floor(number)
                   9651:  * The floor function returns the largest (closest to positive infinity)
                   9652:  * number that is not greater than the argument and that is an integer.
                   9653:  */
                   9654: void
                   9655: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9656:     double f;
                   9657: 
                   9658:     CHECK_ARITY(1);
                   9659:     CAST_TO_NUMBER;
                   9660:     CHECK_TYPE(XPATH_NUMBER);
                   9661: 
                   9662:     XTRUNC(f, ctxt->value->floatval);
                   9663:     if (f != ctxt->value->floatval) {
                   9664:        if (ctxt->value->floatval > 0)
                   9665:            ctxt->value->floatval = f;
                   9666:        else
                   9667:            ctxt->value->floatval = f - 1;
                   9668:     }
                   9669: }
                   9670: 
                   9671: /**
                   9672:  * xmlXPathCeilingFunction:
                   9673:  * @ctxt:  the XPath Parser context
                   9674:  * @nargs:  the number of arguments
                   9675:  *
                   9676:  * Implement the ceiling() XPath function
                   9677:  *    number ceiling(number)
                   9678:  * The ceiling function returns the smallest (closest to negative infinity)
                   9679:  * number that is not less than the argument and that is an integer.
                   9680:  */
                   9681: void
                   9682: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9683:     double f;
                   9684: 
                   9685:     CHECK_ARITY(1);
                   9686:     CAST_TO_NUMBER;
                   9687:     CHECK_TYPE(XPATH_NUMBER);
                   9688: 
                   9689: #if 0
                   9690:     ctxt->value->floatval = ceil(ctxt->value->floatval);
                   9691: #else
                   9692:     XTRUNC(f, ctxt->value->floatval);
                   9693:     if (f != ctxt->value->floatval) {
                   9694:        if (ctxt->value->floatval > 0)
                   9695:            ctxt->value->floatval = f + 1;
                   9696:        else {
                   9697:            if (ctxt->value->floatval < 0 && f == 0)
                   9698:                ctxt->value->floatval = xmlXPathNZERO;
                   9699:            else
                   9700:                ctxt->value->floatval = f;
                   9701:        }
                   9702: 
                   9703:     }
                   9704: #endif
                   9705: }
                   9706: 
                   9707: /**
                   9708:  * xmlXPathRoundFunction:
                   9709:  * @ctxt:  the XPath Parser context
                   9710:  * @nargs:  the number of arguments
                   9711:  *
                   9712:  * Implement the round() XPath function
                   9713:  *    number round(number)
                   9714:  * The round function returns the number that is closest to the
                   9715:  * argument and that is an integer. If there are two such numbers,
                   9716:  * then the one that is even is returned.
                   9717:  */
                   9718: void
                   9719: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   9720:     double f;
                   9721: 
                   9722:     CHECK_ARITY(1);
                   9723:     CAST_TO_NUMBER;
                   9724:     CHECK_TYPE(XPATH_NUMBER);
                   9725: 
                   9726:     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
                   9727:        (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
                   9728:        (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
                   9729:        (ctxt->value->floatval == 0.0))
                   9730:        return;
                   9731: 
                   9732:     XTRUNC(f, ctxt->value->floatval);
                   9733:     if (ctxt->value->floatval < 0) {
                   9734:        if (ctxt->value->floatval < f - 0.5)
                   9735:            ctxt->value->floatval = f - 1;
                   9736:        else
                   9737:            ctxt->value->floatval = f;
                   9738:        if (ctxt->value->floatval == 0)
                   9739:            ctxt->value->floatval = xmlXPathNZERO;
                   9740:     } else {
                   9741:        if (ctxt->value->floatval < f + 0.5)
                   9742:            ctxt->value->floatval = f;
                   9743:        else
                   9744:            ctxt->value->floatval = f + 1;
                   9745:     }
                   9746: }
                   9747: 
                   9748: /************************************************************************
                   9749:  *                                                                     *
                   9750:  *                     The Parser                                      *
                   9751:  *                                                                     *
                   9752:  ************************************************************************/
                   9753: 
                   9754: /*
                   9755:  * a few forward declarations since we use a recursive call based
                   9756:  * implementation.
                   9757:  */
                   9758: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
                   9759: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
                   9760: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
                   9761: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
                   9762: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
                   9763:                                          int qualified);
                   9764: 
                   9765: /**
                   9766:  * xmlXPathCurrentChar:
                   9767:  * @ctxt:  the XPath parser context
                   9768:  * @cur:  pointer to the beginning of the char
                   9769:  * @len:  pointer to the length of the char read
                   9770:  *
                   9771:  * The current char value, if using UTF-8 this may actually span multiple
                   9772:  * bytes in the input buffer.
                   9773:  *
                   9774:  * Returns the current char value and its length
                   9775:  */
                   9776: 
                   9777: static int
                   9778: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
                   9779:     unsigned char c;
                   9780:     unsigned int val;
                   9781:     const xmlChar *cur;
                   9782: 
                   9783:     if (ctxt == NULL)
                   9784:        return(0);
                   9785:     cur = ctxt->cur;
                   9786: 
                   9787:     /*
                   9788:      * We are supposed to handle UTF8, check it's valid
                   9789:      * From rfc2044: encoding of the Unicode values on UTF-8:
                   9790:      *
                   9791:      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
                   9792:      * 0000 0000-0000 007F   0xxxxxxx
                   9793:      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
                   9794:      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
                   9795:      *
                   9796:      * Check for the 0x110000 limit too
                   9797:      */
                   9798:     c = *cur;
                   9799:     if (c & 0x80) {
                   9800:        if ((cur[1] & 0xc0) != 0x80)
                   9801:            goto encoding_error;
                   9802:        if ((c & 0xe0) == 0xe0) {
                   9803: 
                   9804:            if ((cur[2] & 0xc0) != 0x80)
                   9805:                goto encoding_error;
                   9806:            if ((c & 0xf0) == 0xf0) {
                   9807:                if (((c & 0xf8) != 0xf0) ||
                   9808:                    ((cur[3] & 0xc0) != 0x80))
                   9809:                    goto encoding_error;
                   9810:                /* 4-byte code */
                   9811:                *len = 4;
                   9812:                val = (cur[0] & 0x7) << 18;
                   9813:                val |= (cur[1] & 0x3f) << 12;
                   9814:                val |= (cur[2] & 0x3f) << 6;
                   9815:                val |= cur[3] & 0x3f;
                   9816:            } else {
                   9817:              /* 3-byte code */
                   9818:                *len = 3;
                   9819:                val = (cur[0] & 0xf) << 12;
                   9820:                val |= (cur[1] & 0x3f) << 6;
                   9821:                val |= cur[2] & 0x3f;
                   9822:            }
                   9823:        } else {
                   9824:          /* 2-byte code */
                   9825:            *len = 2;
                   9826:            val = (cur[0] & 0x1f) << 6;
                   9827:            val |= cur[1] & 0x3f;
                   9828:        }
                   9829:        if (!IS_CHAR(val)) {
                   9830:            XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
                   9831:        }
                   9832:        return(val);
                   9833:     } else {
                   9834:        /* 1-byte code */
                   9835:        *len = 1;
                   9836:        return((int) *cur);
                   9837:     }
                   9838: encoding_error:
                   9839:     /*
                   9840:      * If we detect an UTF8 error that probably means that the
                   9841:      * input encoding didn't get properly advertised in the
                   9842:      * declaration header. Report the error and switch the encoding
                   9843:      * to ISO-Latin-1 (if you don't like this policy, just declare the
                   9844:      * encoding !)
                   9845:      */
                   9846:     *len = 0;
                   9847:     XP_ERROR0(XPATH_ENCODING_ERROR);
                   9848: }
                   9849: 
                   9850: /**
                   9851:  * xmlXPathParseNCName:
                   9852:  * @ctxt:  the XPath Parser context
                   9853:  *
                   9854:  * parse an XML namespace non qualified name.
                   9855:  *
                   9856:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
                   9857:  *
                   9858:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
                   9859:  *                       CombiningChar | Extender
                   9860:  *
                   9861:  * Returns the namespace name or NULL
                   9862:  */
                   9863: 
                   9864: xmlChar *
                   9865: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
                   9866:     const xmlChar *in;
                   9867:     xmlChar *ret;
                   9868:     int count = 0;
                   9869: 
                   9870:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
                   9871:     /*
                   9872:      * Accelerator for simple ASCII names
                   9873:      */
                   9874:     in = ctxt->cur;
                   9875:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9876:        ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9877:        (*in == '_')) {
                   9878:        in++;
                   9879:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9880:               ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9881:               ((*in >= 0x30) && (*in <= 0x39)) ||
                   9882:               (*in == '_') || (*in == '.') ||
                   9883:               (*in == '-'))
                   9884:            in++;
                   9885:        if ((*in == ' ') || (*in == '>') || (*in == '/') ||
                   9886:             (*in == '[') || (*in == ']') || (*in == ':') ||
                   9887:             (*in == '@') || (*in == '*')) {
                   9888:            count = in - ctxt->cur;
                   9889:            if (count == 0)
                   9890:                return(NULL);
                   9891:            ret = xmlStrndup(ctxt->cur, count);
                   9892:            ctxt->cur = in;
                   9893:            return(ret);
                   9894:        }
                   9895:     }
                   9896:     return(xmlXPathParseNameComplex(ctxt, 0));
                   9897: }
                   9898: 
                   9899: 
                   9900: /**
                   9901:  * xmlXPathParseQName:
                   9902:  * @ctxt:  the XPath Parser context
                   9903:  * @prefix:  a xmlChar **
                   9904:  *
                   9905:  * parse an XML qualified name
                   9906:  *
                   9907:  * [NS 5] QName ::= (Prefix ':')? LocalPart
                   9908:  *
                   9909:  * [NS 6] Prefix ::= NCName
                   9910:  *
                   9911:  * [NS 7] LocalPart ::= NCName
                   9912:  *
                   9913:  * Returns the function returns the local part, and prefix is updated
                   9914:  *   to get the Prefix if any.
                   9915:  */
                   9916: 
                   9917: static xmlChar *
                   9918: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
                   9919:     xmlChar *ret = NULL;
                   9920: 
                   9921:     *prefix = NULL;
                   9922:     ret = xmlXPathParseNCName(ctxt);
                   9923:     if (ret && CUR == ':') {
                   9924:         *prefix = ret;
                   9925:        NEXT;
                   9926:        ret = xmlXPathParseNCName(ctxt);
                   9927:     }
                   9928:     return(ret);
                   9929: }
                   9930: 
                   9931: /**
                   9932:  * xmlXPathParseName:
                   9933:  * @ctxt:  the XPath Parser context
                   9934:  *
                   9935:  * parse an XML name
                   9936:  *
                   9937:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                   9938:  *                  CombiningChar | Extender
                   9939:  *
                   9940:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                   9941:  *
                   9942:  * Returns the namespace name or NULL
                   9943:  */
                   9944: 
                   9945: xmlChar *
                   9946: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
                   9947:     const xmlChar *in;
                   9948:     xmlChar *ret;
1.1.1.3 ! misho    9949:     size_t count = 0;
1.1       misho    9950: 
                   9951:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
                   9952:     /*
                   9953:      * Accelerator for simple ASCII names
                   9954:      */
                   9955:     in = ctxt->cur;
                   9956:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9957:        ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9958:        (*in == '_') || (*in == ':')) {
                   9959:        in++;
                   9960:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
                   9961:               ((*in >= 0x41) && (*in <= 0x5A)) ||
                   9962:               ((*in >= 0x30) && (*in <= 0x39)) ||
                   9963:               (*in == '_') || (*in == '-') ||
                   9964:               (*in == ':') || (*in == '.'))
                   9965:            in++;
                   9966:        if ((*in > 0) && (*in < 0x80)) {
                   9967:            count = in - ctxt->cur;
1.1.1.3 ! misho    9968:             if (count > XML_MAX_NAME_LENGTH) {
        !          9969:                 ctxt->cur = in;
        !          9970:                 XP_ERRORNULL(XPATH_EXPR_ERROR);
        !          9971:             }
1.1       misho    9972:            ret = xmlStrndup(ctxt->cur, count);
                   9973:            ctxt->cur = in;
                   9974:            return(ret);
                   9975:        }
                   9976:     }
                   9977:     return(xmlXPathParseNameComplex(ctxt, 1));
                   9978: }
                   9979: 
                   9980: static xmlChar *
                   9981: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
                   9982:     xmlChar buf[XML_MAX_NAMELEN + 5];
                   9983:     int len = 0, l;
                   9984:     int c;
                   9985: 
                   9986:     /*
                   9987:      * Handler for more complex cases
                   9988:      */
                   9989:     c = CUR_CHAR(l);
                   9990:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
                   9991:         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
                   9992:         (c == '*') || /* accelerators */
                   9993:        (!IS_LETTER(c) && (c != '_') &&
                   9994:          ((qualified) && (c != ':')))) {
                   9995:        return(NULL);
                   9996:     }
                   9997: 
                   9998:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
                   9999:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
                   10000:             (c == '.') || (c == '-') ||
                   10001:            (c == '_') || ((qualified) && (c == ':')) ||
                   10002:            (IS_COMBINING(c)) ||
                   10003:            (IS_EXTENDER(c)))) {
                   10004:        COPY_BUF(l,buf,len,c);
                   10005:        NEXTL(l);
                   10006:        c = CUR_CHAR(l);
                   10007:        if (len >= XML_MAX_NAMELEN) {
                   10008:            /*
                   10009:             * Okay someone managed to make a huge name, so he's ready to pay
                   10010:             * for the processing speed.
                   10011:             */
                   10012:            xmlChar *buffer;
                   10013:            int max = len * 2;
                   10014: 
1.1.1.3 ! misho    10015:             if (len > XML_MAX_NAME_LENGTH) {
        !          10016:                 XP_ERRORNULL(XPATH_EXPR_ERROR);
        !          10017:             }
1.1       misho    10018:            buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
                   10019:            if (buffer == NULL) {
                   10020:                XP_ERRORNULL(XPATH_MEMORY_ERROR);
                   10021:            }
                   10022:            memcpy(buffer, buf, len);
                   10023:            while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
                   10024:                   (c == '.') || (c == '-') ||
                   10025:                   (c == '_') || ((qualified) && (c == ':')) ||
                   10026:                   (IS_COMBINING(c)) ||
                   10027:                   (IS_EXTENDER(c))) {
                   10028:                if (len + 10 > max) {
1.1.1.3 ! misho    10029:                     if (max > XML_MAX_NAME_LENGTH) {
        !          10030:                         XP_ERRORNULL(XPATH_EXPR_ERROR);
        !          10031:                     }
1.1       misho    10032:                    max *= 2;
                   10033:                    buffer = (xmlChar *) xmlRealloc(buffer,
                   10034:                                                    max * sizeof(xmlChar));
                   10035:                    if (buffer == NULL) {
                   10036:                        XP_ERRORNULL(XPATH_MEMORY_ERROR);
                   10037:                    }
                   10038:                }
                   10039:                COPY_BUF(l,buffer,len,c);
                   10040:                NEXTL(l);
                   10041:                c = CUR_CHAR(l);
                   10042:            }
                   10043:            buffer[len] = 0;
                   10044:            return(buffer);
                   10045:        }
                   10046:     }
                   10047:     if (len == 0)
                   10048:        return(NULL);
                   10049:     return(xmlStrndup(buf, len));
                   10050: }
                   10051: 
                   10052: #define MAX_FRAC 20
                   10053: 
                   10054: /*
                   10055:  * These are used as divisors for the fractional part of a number.
                   10056:  * Since the table includes 1.0 (representing '0' fractional digits),
                   10057:  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
                   10058:  */
                   10059: static double my_pow10[MAX_FRAC+1] = {
                   10060:     1.0, 10.0, 100.0, 1000.0, 10000.0,
                   10061:     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
                   10062:     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
                   10063:     100000000000000.0,
                   10064:     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
                   10065:     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
                   10066: };
                   10067: 
                   10068: /**
                   10069:  * xmlXPathStringEvalNumber:
                   10070:  * @str:  A string to scan
                   10071:  *
                   10072:  *  [30a]  Float  ::= Number ('e' Digits?)?
                   10073:  *
                   10074:  *  [30]   Number ::=   Digits ('.' Digits?)?
                   10075:  *                    | '.' Digits
                   10076:  *  [31]   Digits ::=   [0-9]+
                   10077:  *
                   10078:  * Compile a Number in the string
                   10079:  * In complement of the Number expression, this function also handles
                   10080:  * negative values : '-' Number.
                   10081:  *
                   10082:  * Returns the double value.
                   10083:  */
                   10084: double
                   10085: xmlXPathStringEvalNumber(const xmlChar *str) {
                   10086:     const xmlChar *cur = str;
                   10087:     double ret;
                   10088:     int ok = 0;
                   10089:     int isneg = 0;
                   10090:     int exponent = 0;
                   10091:     int is_exponent_negative = 0;
                   10092: #ifdef __GNUC__
                   10093:     unsigned long tmp = 0;
                   10094:     double temp;
                   10095: #endif
                   10096:     if (cur == NULL) return(0);
                   10097:     while (IS_BLANK_CH(*cur)) cur++;
                   10098:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
                   10099:         return(xmlXPathNAN);
                   10100:     }
                   10101:     if (*cur == '-') {
                   10102:        isneg = 1;
                   10103:        cur++;
                   10104:     }
                   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:        cur++;
                   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:        cur++;
                   10126:     }
                   10127: #endif
                   10128: 
                   10129:     if (*cur == '.') {
                   10130:        int v, frac = 0;
                   10131:        double fraction = 0;
                   10132: 
                   10133:         cur++;
                   10134:        if (((*cur < '0') || (*cur > '9')) && (!ok)) {
                   10135:            return(xmlXPathNAN);
                   10136:        }
                   10137:        while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
                   10138:            v = (*cur - '0');
                   10139:            fraction = fraction * 10 + v;
                   10140:            frac = frac + 1;
                   10141:            cur++;
                   10142:        }
                   10143:        fraction /= my_pow10[frac];
                   10144:        ret = ret + fraction;
                   10145:        while ((*cur >= '0') && (*cur <= '9'))
                   10146:            cur++;
                   10147:     }
                   10148:     if ((*cur == 'e') || (*cur == 'E')) {
                   10149:       cur++;
                   10150:       if (*cur == '-') {
                   10151:        is_exponent_negative = 1;
                   10152:        cur++;
                   10153:       } else if (*cur == '+') {
                   10154:         cur++;
                   10155:       }
                   10156:       while ((*cur >= '0') && (*cur <= '9')) {
                   10157:        exponent = exponent * 10 + (*cur - '0');
                   10158:        cur++;
                   10159:       }
                   10160:     }
                   10161:     while (IS_BLANK_CH(*cur)) cur++;
                   10162:     if (*cur != 0) return(xmlXPathNAN);
                   10163:     if (isneg) ret = -ret;
                   10164:     if (is_exponent_negative) exponent = -exponent;
                   10165:     ret *= pow(10.0, (double)exponent);
                   10166:     return(ret);
                   10167: }
                   10168: 
                   10169: /**
                   10170:  * xmlXPathCompNumber:
                   10171:  * @ctxt:  the XPath Parser context
                   10172:  *
                   10173:  *  [30]   Number ::=   Digits ('.' Digits?)?
                   10174:  *                    | '.' Digits
                   10175:  *  [31]   Digits ::=   [0-9]+
                   10176:  *
                   10177:  * Compile a Number, then push it on the stack
                   10178:  *
                   10179:  */
                   10180: static void
                   10181: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
                   10182: {
                   10183:     double ret = 0.0;
                   10184:     int ok = 0;
                   10185:     int exponent = 0;
                   10186:     int is_exponent_negative = 0;
                   10187: #ifdef __GNUC__
                   10188:     unsigned long tmp = 0;
                   10189:     double temp;
                   10190: #endif
                   10191: 
                   10192:     CHECK_ERROR;
                   10193:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
                   10194:         XP_ERROR(XPATH_NUMBER_ERROR);
                   10195:     }
                   10196: #ifdef __GNUC__
                   10197:     /*
                   10198:      * tmp/temp is a workaround against a gcc compiler bug
                   10199:      * http://veillard.com/gcc.bug
                   10200:      */
                   10201:     ret = 0;
                   10202:     while ((CUR >= '0') && (CUR <= '9')) {
                   10203:        ret = ret * 10;
                   10204:        tmp = (CUR - '0');
                   10205:         ok = 1;
                   10206:         NEXT;
                   10207:        temp = (double) tmp;
                   10208:        ret = ret + temp;
                   10209:     }
                   10210: #else
                   10211:     ret = 0;
                   10212:     while ((CUR >= '0') && (CUR <= '9')) {
                   10213:        ret = ret * 10 + (CUR - '0');
                   10214:        ok = 1;
                   10215:        NEXT;
                   10216:     }
                   10217: #endif
                   10218:     if (CUR == '.') {
                   10219:        int v, frac = 0;
                   10220:        double fraction = 0;
                   10221: 
                   10222:         NEXT;
                   10223:         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
                   10224:             XP_ERROR(XPATH_NUMBER_ERROR);
                   10225:         }
                   10226:         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
                   10227:            v = (CUR - '0');
                   10228:            fraction = fraction * 10 + v;
                   10229:            frac = frac + 1;
                   10230:             NEXT;
                   10231:         }
                   10232:         fraction /= my_pow10[frac];
                   10233:         ret = ret + fraction;
                   10234:         while ((CUR >= '0') && (CUR <= '9'))
                   10235:             NEXT;
                   10236:     }
                   10237:     if ((CUR == 'e') || (CUR == 'E')) {
                   10238:         NEXT;
                   10239:         if (CUR == '-') {
                   10240:             is_exponent_negative = 1;
                   10241:             NEXT;
                   10242:         } else if (CUR == '+') {
                   10243:            NEXT;
                   10244:        }
                   10245:         while ((CUR >= '0') && (CUR <= '9')) {
                   10246:             exponent = exponent * 10 + (CUR - '0');
                   10247:             NEXT;
                   10248:         }
                   10249:         if (is_exponent_negative)
                   10250:             exponent = -exponent;
                   10251:         ret *= pow(10.0, (double) exponent);
                   10252:     }
                   10253:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
                   10254:                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
                   10255: }
                   10256: 
                   10257: /**
                   10258:  * xmlXPathParseLiteral:
                   10259:  * @ctxt:  the XPath Parser context
                   10260:  *
                   10261:  * Parse a Literal
                   10262:  *
                   10263:  *  [29]   Literal ::=   '"' [^"]* '"'
                   10264:  *                    | "'" [^']* "'"
                   10265:  *
                   10266:  * Returns the value found or NULL in case of error
                   10267:  */
                   10268: static xmlChar *
                   10269: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
                   10270:     const xmlChar *q;
                   10271:     xmlChar *ret = NULL;
                   10272: 
                   10273:     if (CUR == '"') {
                   10274:         NEXT;
                   10275:        q = CUR_PTR;
                   10276:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
                   10277:            NEXT;
                   10278:        if (!IS_CHAR_CH(CUR)) {
                   10279:            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
                   10280:        } else {
                   10281:            ret = xmlStrndup(q, CUR_PTR - q);
                   10282:            NEXT;
                   10283:         }
                   10284:     } else if (CUR == '\'') {
                   10285:         NEXT;
                   10286:        q = CUR_PTR;
                   10287:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
                   10288:            NEXT;
                   10289:        if (!IS_CHAR_CH(CUR)) {
                   10290:            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
                   10291:        } else {
                   10292:            ret = xmlStrndup(q, CUR_PTR - q);
                   10293:            NEXT;
                   10294:         }
                   10295:     } else {
                   10296:        XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
                   10297:     }
                   10298:     return(ret);
                   10299: }
                   10300: 
                   10301: /**
                   10302:  * xmlXPathCompLiteral:
                   10303:  * @ctxt:  the XPath Parser context
                   10304:  *
                   10305:  * Parse a Literal and push it on the stack.
                   10306:  *
                   10307:  *  [29]   Literal ::=   '"' [^"]* '"'
                   10308:  *                    | "'" [^']* "'"
                   10309:  *
                   10310:  * TODO: xmlXPathCompLiteral memory allocation could be improved.
                   10311:  */
                   10312: static void
                   10313: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
                   10314:     const xmlChar *q;
                   10315:     xmlChar *ret = NULL;
                   10316: 
                   10317:     if (CUR == '"') {
                   10318:         NEXT;
                   10319:        q = CUR_PTR;
                   10320:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
                   10321:            NEXT;
                   10322:        if (!IS_CHAR_CH(CUR)) {
                   10323:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
                   10324:        } else {
                   10325:            ret = xmlStrndup(q, CUR_PTR - q);
                   10326:            NEXT;
                   10327:         }
                   10328:     } else if (CUR == '\'') {
                   10329:         NEXT;
                   10330:        q = CUR_PTR;
                   10331:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
                   10332:            NEXT;
                   10333:        if (!IS_CHAR_CH(CUR)) {
                   10334:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
                   10335:        } else {
                   10336:            ret = xmlStrndup(q, CUR_PTR - q);
                   10337:            NEXT;
                   10338:         }
                   10339:     } else {
                   10340:        XP_ERROR(XPATH_START_LITERAL_ERROR);
                   10341:     }
                   10342:     if (ret == NULL) return;
                   10343:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
                   10344:                   xmlXPathCacheNewString(ctxt->context, ret), NULL);
                   10345:     xmlFree(ret);
                   10346: }
                   10347: 
                   10348: /**
                   10349:  * xmlXPathCompVariableReference:
                   10350:  * @ctxt:  the XPath Parser context
                   10351:  *
                   10352:  * Parse a VariableReference, evaluate it and push it on the stack.
                   10353:  *
                   10354:  * The variable bindings consist of a mapping from variable names
                   10355:  * to variable values. The value of a variable is an object, which can be
                   10356:  * of any of the types that are possible for the value of an expression,
                   10357:  * and may also be of additional types not specified here.
                   10358:  *
                   10359:  * Early evaluation is possible since:
                   10360:  * The variable bindings [...] used to evaluate a subexpression are
                   10361:  * always the same as those used to evaluate the containing expression.
                   10362:  *
                   10363:  *  [36]   VariableReference ::=   '$' QName
                   10364:  */
                   10365: static void
                   10366: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
                   10367:     xmlChar *name;
                   10368:     xmlChar *prefix;
                   10369: 
                   10370:     SKIP_BLANKS;
                   10371:     if (CUR != '$') {
                   10372:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
                   10373:     }
                   10374:     NEXT;
                   10375:     name = xmlXPathParseQName(ctxt, &prefix);
                   10376:     if (name == NULL) {
                   10377:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
                   10378:     }
                   10379:     ctxt->comp->last = -1;
                   10380:     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
                   10381:                   name, prefix);
                   10382:     SKIP_BLANKS;
                   10383:     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
1.1.1.3 ! misho    10384:        XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
1.1       misho    10385:     }
                   10386: }
                   10387: 
                   10388: /**
                   10389:  * xmlXPathIsNodeType:
                   10390:  * @name:  a name string
                   10391:  *
                   10392:  * Is the name given a NodeType one.
                   10393:  *
                   10394:  *  [38]   NodeType ::=   'comment'
                   10395:  *                    | 'text'
                   10396:  *                    | 'processing-instruction'
                   10397:  *                    | 'node'
                   10398:  *
                   10399:  * Returns 1 if true 0 otherwise
                   10400:  */
                   10401: int
                   10402: xmlXPathIsNodeType(const xmlChar *name) {
                   10403:     if (name == NULL)
                   10404:        return(0);
                   10405: 
                   10406:     if (xmlStrEqual(name, BAD_CAST "node"))
                   10407:        return(1);
                   10408:     if (xmlStrEqual(name, BAD_CAST "text"))
                   10409:        return(1);
                   10410:     if (xmlStrEqual(name, BAD_CAST "comment"))
                   10411:        return(1);
                   10412:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
                   10413:        return(1);
                   10414:     return(0);
                   10415: }
                   10416: 
                   10417: /**
                   10418:  * xmlXPathCompFunctionCall:
                   10419:  * @ctxt:  the XPath Parser context
                   10420:  *
                   10421:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
                   10422:  *  [17]   Argument ::=   Expr
                   10423:  *
                   10424:  * Compile a function call, the evaluation of all arguments are
                   10425:  * pushed on the stack
                   10426:  */
                   10427: static void
                   10428: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
                   10429:     xmlChar *name;
                   10430:     xmlChar *prefix;
                   10431:     int nbargs = 0;
                   10432:     int sort = 1;
                   10433: 
                   10434:     name = xmlXPathParseQName(ctxt, &prefix);
                   10435:     if (name == NULL) {
                   10436:        xmlFree(prefix);
                   10437:        XP_ERROR(XPATH_EXPR_ERROR);
                   10438:     }
                   10439:     SKIP_BLANKS;
                   10440: #ifdef DEBUG_EXPR
                   10441:     if (prefix == NULL)
                   10442:        xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
                   10443:                        name);
                   10444:     else
                   10445:        xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
                   10446:                        prefix, name);
                   10447: #endif
                   10448: 
                   10449:     if (CUR != '(') {
                   10450:        XP_ERROR(XPATH_EXPR_ERROR);
                   10451:     }
                   10452:     NEXT;
                   10453:     SKIP_BLANKS;
                   10454: 
                   10455:     /*
                   10456:     * Optimization for count(): we don't need the node-set to be sorted.
                   10457:     */
                   10458:     if ((prefix == NULL) && (name[0] == 'c') &&
                   10459:        xmlStrEqual(name, BAD_CAST "count"))
                   10460:     {
                   10461:        sort = 0;
                   10462:     }
                   10463:     ctxt->comp->last = -1;
                   10464:     if (CUR != ')') {
                   10465:        while (CUR != 0) {
                   10466:            int op1 = ctxt->comp->last;
                   10467:            ctxt->comp->last = -1;
                   10468:            xmlXPathCompileExpr(ctxt, sort);
                   10469:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   10470:                xmlFree(name);
                   10471:                xmlFree(prefix);
                   10472:                return;
                   10473:            }
                   10474:            PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
                   10475:            nbargs++;
                   10476:            if (CUR == ')') break;
                   10477:            if (CUR != ',') {
                   10478:                XP_ERROR(XPATH_EXPR_ERROR);
                   10479:            }
                   10480:            NEXT;
                   10481:            SKIP_BLANKS;
                   10482:        }
                   10483:     }
                   10484:     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
                   10485:                   name, prefix);
                   10486:     NEXT;
                   10487:     SKIP_BLANKS;
                   10488: }
                   10489: 
                   10490: /**
                   10491:  * xmlXPathCompPrimaryExpr:
                   10492:  * @ctxt:  the XPath Parser context
                   10493:  *
                   10494:  *  [15]   PrimaryExpr ::=   VariableReference
                   10495:  *                | '(' Expr ')'
                   10496:  *                | Literal
                   10497:  *                | Number
                   10498:  *                | FunctionCall
                   10499:  *
                   10500:  * Compile a primary expression.
                   10501:  */
                   10502: static void
                   10503: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
                   10504:     SKIP_BLANKS;
                   10505:     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
                   10506:     else if (CUR == '(') {
                   10507:        NEXT;
                   10508:        SKIP_BLANKS;
                   10509:        xmlXPathCompileExpr(ctxt, 1);
                   10510:        CHECK_ERROR;
                   10511:        if (CUR != ')') {
                   10512:            XP_ERROR(XPATH_EXPR_ERROR);
                   10513:        }
                   10514:        NEXT;
                   10515:        SKIP_BLANKS;
                   10516:     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
                   10517:        xmlXPathCompNumber(ctxt);
                   10518:     } else if ((CUR == '\'') || (CUR == '"')) {
                   10519:        xmlXPathCompLiteral(ctxt);
                   10520:     } else {
                   10521:        xmlXPathCompFunctionCall(ctxt);
                   10522:     }
                   10523:     SKIP_BLANKS;
                   10524: }
                   10525: 
                   10526: /**
                   10527:  * xmlXPathCompFilterExpr:
                   10528:  * @ctxt:  the XPath Parser context
                   10529:  *
                   10530:  *  [20]   FilterExpr ::=   PrimaryExpr
                   10531:  *               | FilterExpr Predicate
                   10532:  *
                   10533:  * Compile a filter expression.
                   10534:  * Square brackets are used to filter expressions in the same way that
                   10535:  * they are used in location paths. It is an error if the expression to
                   10536:  * be filtered does not evaluate to a node-set. The context node list
                   10537:  * used for evaluating the expression in square brackets is the node-set
                   10538:  * to be filtered listed in document order.
                   10539:  */
                   10540: 
                   10541: static void
                   10542: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
                   10543:     xmlXPathCompPrimaryExpr(ctxt);
                   10544:     CHECK_ERROR;
                   10545:     SKIP_BLANKS;
                   10546: 
                   10547:     while (CUR == '[') {
                   10548:        xmlXPathCompPredicate(ctxt, 1);
                   10549:        SKIP_BLANKS;
                   10550:     }
                   10551: 
                   10552: 
                   10553: }
                   10554: 
                   10555: /**
                   10556:  * xmlXPathScanName:
                   10557:  * @ctxt:  the XPath Parser context
                   10558:  *
                   10559:  * Trickery: parse an XML name but without consuming the input flow
                   10560:  * Needed to avoid insanity in the parser state.
                   10561:  *
                   10562:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                   10563:  *                  CombiningChar | Extender
                   10564:  *
                   10565:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                   10566:  *
                   10567:  * [6] Names ::= Name (S Name)*
                   10568:  *
                   10569:  * Returns the Name parsed or NULL
                   10570:  */
                   10571: 
                   10572: static xmlChar *
                   10573: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
                   10574:     int len = 0, l;
                   10575:     int c;
                   10576:     const xmlChar *cur;
                   10577:     xmlChar *ret;
                   10578: 
                   10579:     cur = ctxt->cur;
                   10580: 
                   10581:     c = CUR_CHAR(l);
                   10582:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
                   10583:        (!IS_LETTER(c) && (c != '_') &&
                   10584:          (c != ':'))) {
                   10585:        return(NULL);
                   10586:     }
                   10587: 
                   10588:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
                   10589:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
                   10590:             (c == '.') || (c == '-') ||
                   10591:            (c == '_') || (c == ':') ||
                   10592:            (IS_COMBINING(c)) ||
                   10593:            (IS_EXTENDER(c)))) {
                   10594:        len += l;
                   10595:        NEXTL(l);
                   10596:        c = CUR_CHAR(l);
                   10597:     }
                   10598:     ret = xmlStrndup(cur, ctxt->cur - cur);
                   10599:     ctxt->cur = cur;
                   10600:     return(ret);
                   10601: }
                   10602: 
                   10603: /**
                   10604:  * xmlXPathCompPathExpr:
                   10605:  * @ctxt:  the XPath Parser context
                   10606:  *
                   10607:  *  [19]   PathExpr ::=   LocationPath
                   10608:  *               | FilterExpr
                   10609:  *               | FilterExpr '/' RelativeLocationPath
                   10610:  *               | FilterExpr '//' RelativeLocationPath
                   10611:  *
                   10612:  * Compile a path expression.
                   10613:  * The / operator and // operators combine an arbitrary expression
                   10614:  * and a relative location path. It is an error if the expression
                   10615:  * does not evaluate to a node-set.
                   10616:  * The / operator does composition in the same way as when / is
                   10617:  * used in a location path. As in location paths, // is short for
                   10618:  * /descendant-or-self::node()/.
                   10619:  */
                   10620: 
                   10621: static void
                   10622: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
                   10623:     int lc = 1;           /* Should we branch to LocationPath ?         */
                   10624:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
                   10625: 
                   10626:     SKIP_BLANKS;
                   10627:     if ((CUR == '$') || (CUR == '(') ||
                   10628:        (IS_ASCII_DIGIT(CUR)) ||
                   10629:         (CUR == '\'') || (CUR == '"') ||
                   10630:        (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
                   10631:        lc = 0;
                   10632:     } else if (CUR == '*') {
                   10633:        /* relative or absolute location path */
                   10634:        lc = 1;
                   10635:     } else if (CUR == '/') {
                   10636:        /* relative or absolute location path */
                   10637:        lc = 1;
                   10638:     } else if (CUR == '@') {
                   10639:        /* relative abbreviated attribute location path */
                   10640:        lc = 1;
                   10641:     } else if (CUR == '.') {
                   10642:        /* relative abbreviated attribute location path */
                   10643:        lc = 1;
                   10644:     } else {
                   10645:        /*
                   10646:         * Problem is finding if we have a name here whether it's:
                   10647:         *   - a nodetype
                   10648:         *   - a function call in which case it's followed by '('
                   10649:         *   - an axis in which case it's followed by ':'
                   10650:         *   - a element name
                   10651:         * We do an a priori analysis here rather than having to
                   10652:         * maintain parsed token content through the recursive function
                   10653:         * calls. This looks uglier but makes the code easier to
                   10654:         * read/write/debug.
                   10655:         */
                   10656:        SKIP_BLANKS;
                   10657:        name = xmlXPathScanName(ctxt);
                   10658:        if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
                   10659: #ifdef DEBUG_STEP
                   10660:            xmlGenericError(xmlGenericErrorContext,
                   10661:                    "PathExpr: Axis\n");
                   10662: #endif
                   10663:            lc = 1;
                   10664:            xmlFree(name);
                   10665:        } else if (name != NULL) {
                   10666:            int len =xmlStrlen(name);
                   10667: 
                   10668: 
                   10669:            while (NXT(len) != 0) {
                   10670:                if (NXT(len) == '/') {
                   10671:                    /* element name */
                   10672: #ifdef DEBUG_STEP
                   10673:                    xmlGenericError(xmlGenericErrorContext,
                   10674:                            "PathExpr: AbbrRelLocation\n");
                   10675: #endif
                   10676:                    lc = 1;
                   10677:                    break;
                   10678:                } else if (IS_BLANK_CH(NXT(len))) {
                   10679:                    /* ignore blanks */
                   10680:                    ;
                   10681:                } else if (NXT(len) == ':') {
                   10682: #ifdef DEBUG_STEP
                   10683:                    xmlGenericError(xmlGenericErrorContext,
                   10684:                            "PathExpr: AbbrRelLocation\n");
                   10685: #endif
                   10686:                    lc = 1;
                   10687:                    break;
                   10688:                } else if ((NXT(len) == '(')) {
                   10689:                    /* Note Type or Function */
                   10690:                    if (xmlXPathIsNodeType(name)) {
                   10691: #ifdef DEBUG_STEP
                   10692:                        xmlGenericError(xmlGenericErrorContext,
                   10693:                                "PathExpr: Type search\n");
                   10694: #endif
                   10695:                        lc = 1;
                   10696:                    } else {
                   10697: #ifdef DEBUG_STEP
                   10698:                        xmlGenericError(xmlGenericErrorContext,
                   10699:                                "PathExpr: function call\n");
                   10700: #endif
                   10701:                        lc = 0;
                   10702:                    }
                   10703:                     break;
                   10704:                } else if ((NXT(len) == '[')) {
                   10705:                    /* element name */
                   10706: #ifdef DEBUG_STEP
                   10707:                    xmlGenericError(xmlGenericErrorContext,
                   10708:                            "PathExpr: AbbrRelLocation\n");
                   10709: #endif
                   10710:                    lc = 1;
                   10711:                    break;
                   10712:                } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
                   10713:                           (NXT(len) == '=')) {
                   10714:                    lc = 1;
                   10715:                    break;
                   10716:                } else {
                   10717:                    lc = 1;
                   10718:                    break;
                   10719:                }
                   10720:                len++;
                   10721:            }
                   10722:            if (NXT(len) == 0) {
                   10723: #ifdef DEBUG_STEP
                   10724:                xmlGenericError(xmlGenericErrorContext,
                   10725:                        "PathExpr: AbbrRelLocation\n");
                   10726: #endif
                   10727:                /* element name */
                   10728:                lc = 1;
                   10729:            }
                   10730:            xmlFree(name);
                   10731:        } else {
                   10732:            /* make sure all cases are covered explicitly */
                   10733:            XP_ERROR(XPATH_EXPR_ERROR);
                   10734:        }
                   10735:     }
                   10736: 
                   10737:     if (lc) {
                   10738:        if (CUR == '/') {
                   10739:            PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
                   10740:        } else {
                   10741:            PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
                   10742:        }
                   10743:        xmlXPathCompLocationPath(ctxt);
                   10744:     } else {
                   10745:        xmlXPathCompFilterExpr(ctxt);
                   10746:        CHECK_ERROR;
                   10747:        if ((CUR == '/') && (NXT(1) == '/')) {
                   10748:            SKIP(2);
                   10749:            SKIP_BLANKS;
                   10750: 
                   10751:            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   10752:                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   10753:            PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
                   10754: 
                   10755:            xmlXPathCompRelativeLocationPath(ctxt);
                   10756:        } else if (CUR == '/') {
                   10757:            xmlXPathCompRelativeLocationPath(ctxt);
                   10758:        }
                   10759:     }
                   10760:     SKIP_BLANKS;
                   10761: }
                   10762: 
                   10763: /**
                   10764:  * xmlXPathCompUnionExpr:
                   10765:  * @ctxt:  the XPath Parser context
                   10766:  *
                   10767:  *  [18]   UnionExpr ::=   PathExpr
                   10768:  *               | UnionExpr '|' PathExpr
                   10769:  *
                   10770:  * Compile an union expression.
                   10771:  */
                   10772: 
                   10773: static void
                   10774: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
                   10775:     xmlXPathCompPathExpr(ctxt);
                   10776:     CHECK_ERROR;
                   10777:     SKIP_BLANKS;
                   10778:     while (CUR == '|') {
                   10779:        int op1 = ctxt->comp->last;
                   10780:        PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
                   10781: 
                   10782:        NEXT;
                   10783:        SKIP_BLANKS;
                   10784:        xmlXPathCompPathExpr(ctxt);
                   10785: 
                   10786:        PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
                   10787: 
                   10788:        SKIP_BLANKS;
                   10789:     }
                   10790: }
                   10791: 
                   10792: /**
                   10793:  * xmlXPathCompUnaryExpr:
                   10794:  * @ctxt:  the XPath Parser context
                   10795:  *
                   10796:  *  [27]   UnaryExpr ::=   UnionExpr
                   10797:  *                   | '-' UnaryExpr
                   10798:  *
                   10799:  * Compile an unary expression.
                   10800:  */
                   10801: 
                   10802: static void
                   10803: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
                   10804:     int minus = 0;
                   10805:     int found = 0;
                   10806: 
                   10807:     SKIP_BLANKS;
                   10808:     while (CUR == '-') {
                   10809:         minus = 1 - minus;
                   10810:        found = 1;
                   10811:        NEXT;
                   10812:        SKIP_BLANKS;
                   10813:     }
                   10814: 
                   10815:     xmlXPathCompUnionExpr(ctxt);
                   10816:     CHECK_ERROR;
                   10817:     if (found) {
                   10818:        if (minus)
                   10819:            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
                   10820:        else
                   10821:            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
                   10822:     }
                   10823: }
                   10824: 
                   10825: /**
                   10826:  * xmlXPathCompMultiplicativeExpr:
                   10827:  * @ctxt:  the XPath Parser context
                   10828:  *
                   10829:  *  [26]   MultiplicativeExpr ::=   UnaryExpr
                   10830:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
                   10831:  *                   | MultiplicativeExpr 'div' UnaryExpr
                   10832:  *                   | MultiplicativeExpr 'mod' UnaryExpr
                   10833:  *  [34]   MultiplyOperator ::=   '*'
                   10834:  *
                   10835:  * Compile an Additive expression.
                   10836:  */
                   10837: 
                   10838: static void
                   10839: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
                   10840:     xmlXPathCompUnaryExpr(ctxt);
                   10841:     CHECK_ERROR;
                   10842:     SKIP_BLANKS;
                   10843:     while ((CUR == '*') ||
                   10844:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
                   10845:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
                   10846:        int op = -1;
                   10847:        int op1 = ctxt->comp->last;
                   10848: 
                   10849:         if (CUR == '*') {
                   10850:            op = 0;
                   10851:            NEXT;
                   10852:        } else if (CUR == 'd') {
                   10853:            op = 1;
                   10854:            SKIP(3);
                   10855:        } else if (CUR == 'm') {
                   10856:            op = 2;
                   10857:            SKIP(3);
                   10858:        }
                   10859:        SKIP_BLANKS;
                   10860:         xmlXPathCompUnaryExpr(ctxt);
                   10861:        CHECK_ERROR;
                   10862:        PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
                   10863:        SKIP_BLANKS;
                   10864:     }
                   10865: }
                   10866: 
                   10867: /**
                   10868:  * xmlXPathCompAdditiveExpr:
                   10869:  * @ctxt:  the XPath Parser context
                   10870:  *
                   10871:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
                   10872:  *                   | AdditiveExpr '+' MultiplicativeExpr
                   10873:  *                   | AdditiveExpr '-' MultiplicativeExpr
                   10874:  *
                   10875:  * Compile an Additive expression.
                   10876:  */
                   10877: 
                   10878: static void
                   10879: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
                   10880: 
                   10881:     xmlXPathCompMultiplicativeExpr(ctxt);
                   10882:     CHECK_ERROR;
                   10883:     SKIP_BLANKS;
                   10884:     while ((CUR == '+') || (CUR == '-')) {
                   10885:        int plus;
                   10886:        int op1 = ctxt->comp->last;
                   10887: 
                   10888:         if (CUR == '+') plus = 1;
                   10889:        else plus = 0;
                   10890:        NEXT;
                   10891:        SKIP_BLANKS;
                   10892:         xmlXPathCompMultiplicativeExpr(ctxt);
                   10893:        CHECK_ERROR;
                   10894:        PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
                   10895:        SKIP_BLANKS;
                   10896:     }
                   10897: }
                   10898: 
                   10899: /**
                   10900:  * xmlXPathCompRelationalExpr:
                   10901:  * @ctxt:  the XPath Parser context
                   10902:  *
                   10903:  *  [24]   RelationalExpr ::=   AdditiveExpr
                   10904:  *                 | RelationalExpr '<' AdditiveExpr
                   10905:  *                 | RelationalExpr '>' AdditiveExpr
                   10906:  *                 | RelationalExpr '<=' AdditiveExpr
                   10907:  *                 | RelationalExpr '>=' AdditiveExpr
                   10908:  *
                   10909:  *  A <= B > C is allowed ? Answer from James, yes with
                   10910:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
                   10911:  *  which is basically what got implemented.
                   10912:  *
                   10913:  * Compile a Relational expression, then push the result
                   10914:  * on the stack
                   10915:  */
                   10916: 
                   10917: static void
                   10918: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
                   10919:     xmlXPathCompAdditiveExpr(ctxt);
                   10920:     CHECK_ERROR;
                   10921:     SKIP_BLANKS;
                   10922:     while ((CUR == '<') ||
                   10923:            (CUR == '>') ||
                   10924:            ((CUR == '<') && (NXT(1) == '=')) ||
                   10925:            ((CUR == '>') && (NXT(1) == '='))) {
                   10926:        int inf, strict;
                   10927:        int op1 = ctxt->comp->last;
                   10928: 
                   10929:         if (CUR == '<') inf = 1;
                   10930:        else inf = 0;
                   10931:        if (NXT(1) == '=') strict = 0;
                   10932:        else strict = 1;
                   10933:        NEXT;
                   10934:        if (!strict) NEXT;
                   10935:        SKIP_BLANKS;
                   10936:         xmlXPathCompAdditiveExpr(ctxt);
                   10937:        CHECK_ERROR;
                   10938:        PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
                   10939:        SKIP_BLANKS;
                   10940:     }
                   10941: }
                   10942: 
                   10943: /**
                   10944:  * xmlXPathCompEqualityExpr:
                   10945:  * @ctxt:  the XPath Parser context
                   10946:  *
                   10947:  *  [23]   EqualityExpr ::=   RelationalExpr
                   10948:  *                 | EqualityExpr '=' RelationalExpr
                   10949:  *                 | EqualityExpr '!=' RelationalExpr
                   10950:  *
                   10951:  *  A != B != C is allowed ? Answer from James, yes with
                   10952:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
                   10953:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
                   10954:  *  which is basically what got implemented.
                   10955:  *
                   10956:  * Compile an Equality expression.
                   10957:  *
                   10958:  */
                   10959: static void
                   10960: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
                   10961:     xmlXPathCompRelationalExpr(ctxt);
                   10962:     CHECK_ERROR;
                   10963:     SKIP_BLANKS;
                   10964:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
                   10965:        int eq;
                   10966:        int op1 = ctxt->comp->last;
                   10967: 
                   10968:         if (CUR == '=') eq = 1;
                   10969:        else eq = 0;
                   10970:        NEXT;
                   10971:        if (!eq) NEXT;
                   10972:        SKIP_BLANKS;
                   10973:         xmlXPathCompRelationalExpr(ctxt);
                   10974:        CHECK_ERROR;
                   10975:        PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
                   10976:        SKIP_BLANKS;
                   10977:     }
                   10978: }
                   10979: 
                   10980: /**
                   10981:  * xmlXPathCompAndExpr:
                   10982:  * @ctxt:  the XPath Parser context
                   10983:  *
                   10984:  *  [22]   AndExpr ::=   EqualityExpr
                   10985:  *                 | AndExpr 'and' EqualityExpr
                   10986:  *
                   10987:  * Compile an AND expression.
                   10988:  *
                   10989:  */
                   10990: static void
                   10991: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
                   10992:     xmlXPathCompEqualityExpr(ctxt);
                   10993:     CHECK_ERROR;
                   10994:     SKIP_BLANKS;
                   10995:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
                   10996:        int op1 = ctxt->comp->last;
                   10997:         SKIP(3);
                   10998:        SKIP_BLANKS;
                   10999:         xmlXPathCompEqualityExpr(ctxt);
                   11000:        CHECK_ERROR;
                   11001:        PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
                   11002:        SKIP_BLANKS;
                   11003:     }
                   11004: }
                   11005: 
                   11006: /**
                   11007:  * xmlXPathCompileExpr:
                   11008:  * @ctxt:  the XPath Parser context
                   11009:  *
                   11010:  *  [14]   Expr ::=   OrExpr
                   11011:  *  [21]   OrExpr ::=   AndExpr
                   11012:  *                 | OrExpr 'or' AndExpr
                   11013:  *
                   11014:  * Parse and compile an expression
                   11015:  */
                   11016: static void
                   11017: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
                   11018:     xmlXPathCompAndExpr(ctxt);
                   11019:     CHECK_ERROR;
                   11020:     SKIP_BLANKS;
                   11021:     while ((CUR == 'o') && (NXT(1) == 'r')) {
                   11022:        int op1 = ctxt->comp->last;
                   11023:         SKIP(2);
                   11024:        SKIP_BLANKS;
                   11025:         xmlXPathCompAndExpr(ctxt);
                   11026:        CHECK_ERROR;
                   11027:        PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
                   11028:        SKIP_BLANKS;
                   11029:     }
                   11030:     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
                   11031:        /* more ops could be optimized too */
                   11032:        /*
                   11033:        * This is the main place to eliminate sorting for
                   11034:        * operations which don't require a sorted node-set.
                   11035:        * E.g. count().
                   11036:        */
                   11037:        PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
                   11038:     }
                   11039: }
                   11040: 
                   11041: /**
                   11042:  * xmlXPathCompPredicate:
                   11043:  * @ctxt:  the XPath Parser context
                   11044:  * @filter:  act as a filter
                   11045:  *
                   11046:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
                   11047:  *  [9]   PredicateExpr ::=   Expr
                   11048:  *
                   11049:  * Compile a predicate expression
                   11050:  */
                   11051: static void
                   11052: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
                   11053:     int op1 = ctxt->comp->last;
                   11054: 
                   11055:     SKIP_BLANKS;
                   11056:     if (CUR != '[') {
                   11057:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
                   11058:     }
                   11059:     NEXT;
                   11060:     SKIP_BLANKS;
                   11061: 
                   11062:     ctxt->comp->last = -1;
                   11063:     /*
                   11064:     * This call to xmlXPathCompileExpr() will deactivate sorting
                   11065:     * of the predicate result.
                   11066:     * TODO: Sorting is still activated for filters, since I'm not
                   11067:     *  sure if needed. Normally sorting should not be needed, since
                   11068:     *  a filter can only diminish the number of items in a sequence,
                   11069:     *  but won't change its order; so if the initial sequence is sorted,
                   11070:     *  subsequent sorting is not needed.
                   11071:     */
                   11072:     if (! filter)
                   11073:        xmlXPathCompileExpr(ctxt, 0);
                   11074:     else
                   11075:        xmlXPathCompileExpr(ctxt, 1);
                   11076:     CHECK_ERROR;
                   11077: 
                   11078:     if (CUR != ']') {
                   11079:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
                   11080:     }
                   11081: 
                   11082:     if (filter)
                   11083:        PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
                   11084:     else
                   11085:        PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
                   11086: 
                   11087:     NEXT;
                   11088:     SKIP_BLANKS;
                   11089: }
                   11090: 
                   11091: /**
                   11092:  * xmlXPathCompNodeTest:
                   11093:  * @ctxt:  the XPath Parser context
                   11094:  * @test:  pointer to a xmlXPathTestVal
                   11095:  * @type:  pointer to a xmlXPathTypeVal
                   11096:  * @prefix:  placeholder for a possible name prefix
                   11097:  *
                   11098:  * [7] NodeTest ::=   NameTest
                   11099:  *                 | NodeType '(' ')'
                   11100:  *                 | 'processing-instruction' '(' Literal ')'
                   11101:  *
                   11102:  * [37] NameTest ::=  '*'
                   11103:  *                 | NCName ':' '*'
                   11104:  *                 | QName
                   11105:  * [38] NodeType ::= 'comment'
                   11106:  *                | 'text'
                   11107:  *                | 'processing-instruction'
                   11108:  *                | 'node'
                   11109:  *
                   11110:  * Returns the name found and updates @test, @type and @prefix appropriately
                   11111:  */
                   11112: static xmlChar *
                   11113: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
                   11114:                     xmlXPathTypeVal *type, const xmlChar **prefix,
                   11115:                     xmlChar *name) {
                   11116:     int blanks;
                   11117: 
                   11118:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
                   11119:        STRANGE;
                   11120:        return(NULL);
                   11121:     }
                   11122:     *type = (xmlXPathTypeVal) 0;
                   11123:     *test = (xmlXPathTestVal) 0;
                   11124:     *prefix = NULL;
                   11125:     SKIP_BLANKS;
                   11126: 
                   11127:     if ((name == NULL) && (CUR == '*')) {
                   11128:        /*
                   11129:         * All elements
                   11130:         */
                   11131:        NEXT;
                   11132:        *test = NODE_TEST_ALL;
                   11133:        return(NULL);
                   11134:     }
                   11135: 
                   11136:     if (name == NULL)
                   11137:        name = xmlXPathParseNCName(ctxt);
                   11138:     if (name == NULL) {
                   11139:        XP_ERRORNULL(XPATH_EXPR_ERROR);
                   11140:     }
                   11141: 
                   11142:     blanks = IS_BLANK_CH(CUR);
                   11143:     SKIP_BLANKS;
                   11144:     if (CUR == '(') {
                   11145:        NEXT;
                   11146:        /*
                   11147:         * NodeType or PI search
                   11148:         */
                   11149:        if (xmlStrEqual(name, BAD_CAST "comment"))
                   11150:            *type = NODE_TYPE_COMMENT;
                   11151:        else if (xmlStrEqual(name, BAD_CAST "node"))
                   11152:            *type = NODE_TYPE_NODE;
                   11153:        else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
                   11154:            *type = NODE_TYPE_PI;
                   11155:        else if (xmlStrEqual(name, BAD_CAST "text"))
                   11156:            *type = NODE_TYPE_TEXT;
                   11157:        else {
                   11158:            if (name != NULL)
                   11159:                xmlFree(name);
                   11160:            XP_ERRORNULL(XPATH_EXPR_ERROR);
                   11161:        }
                   11162: 
                   11163:        *test = NODE_TEST_TYPE;
                   11164: 
                   11165:        SKIP_BLANKS;
                   11166:        if (*type == NODE_TYPE_PI) {
                   11167:            /*
                   11168:             * Specific case: search a PI by name.
                   11169:             */
                   11170:            if (name != NULL)
                   11171:                xmlFree(name);
                   11172:            name = NULL;
                   11173:            if (CUR != ')') {
                   11174:                name = xmlXPathParseLiteral(ctxt);
                   11175:                CHECK_ERROR NULL;
                   11176:                *test = NODE_TEST_PI;
                   11177:                SKIP_BLANKS;
                   11178:            }
                   11179:        }
                   11180:        if (CUR != ')') {
                   11181:            if (name != NULL)
                   11182:                xmlFree(name);
                   11183:            XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
                   11184:        }
                   11185:        NEXT;
                   11186:        return(name);
                   11187:     }
                   11188:     *test = NODE_TEST_NAME;
                   11189:     if ((!blanks) && (CUR == ':')) {
                   11190:        NEXT;
                   11191: 
                   11192:        /*
                   11193:         * Since currently the parser context don't have a
                   11194:         * namespace list associated:
                   11195:         * The namespace name for this prefix can be computed
                   11196:         * only at evaluation time. The compilation is done
                   11197:         * outside of any context.
                   11198:         */
                   11199: #if 0
                   11200:        *prefix = xmlXPathNsLookup(ctxt->context, name);
                   11201:        if (name != NULL)
                   11202:            xmlFree(name);
                   11203:        if (*prefix == NULL) {
                   11204:            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
                   11205:        }
                   11206: #else
                   11207:        *prefix = name;
                   11208: #endif
                   11209: 
                   11210:        if (CUR == '*') {
                   11211:            /*
                   11212:             * All elements
                   11213:             */
                   11214:            NEXT;
                   11215:            *test = NODE_TEST_ALL;
                   11216:            return(NULL);
                   11217:        }
                   11218: 
                   11219:        name = xmlXPathParseNCName(ctxt);
                   11220:        if (name == NULL) {
                   11221:            XP_ERRORNULL(XPATH_EXPR_ERROR);
                   11222:        }
                   11223:     }
                   11224:     return(name);
                   11225: }
                   11226: 
                   11227: /**
                   11228:  * xmlXPathIsAxisName:
                   11229:  * @name:  a preparsed name token
                   11230:  *
                   11231:  * [6] AxisName ::=   'ancestor'
                   11232:  *                  | 'ancestor-or-self'
                   11233:  *                  | 'attribute'
                   11234:  *                  | 'child'
                   11235:  *                  | 'descendant'
                   11236:  *                  | 'descendant-or-self'
                   11237:  *                  | 'following'
                   11238:  *                  | 'following-sibling'
                   11239:  *                  | 'namespace'
                   11240:  *                  | 'parent'
                   11241:  *                  | 'preceding'
                   11242:  *                  | 'preceding-sibling'
                   11243:  *                  | 'self'
                   11244:  *
                   11245:  * Returns the axis or 0
                   11246:  */
                   11247: static xmlXPathAxisVal
                   11248: xmlXPathIsAxisName(const xmlChar *name) {
                   11249:     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
                   11250:     switch (name[0]) {
                   11251:        case 'a':
                   11252:            if (xmlStrEqual(name, BAD_CAST "ancestor"))
                   11253:                ret = AXIS_ANCESTOR;
                   11254:            if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
                   11255:                ret = AXIS_ANCESTOR_OR_SELF;
                   11256:            if (xmlStrEqual(name, BAD_CAST "attribute"))
                   11257:                ret = AXIS_ATTRIBUTE;
                   11258:            break;
                   11259:        case 'c':
                   11260:            if (xmlStrEqual(name, BAD_CAST "child"))
                   11261:                ret = AXIS_CHILD;
                   11262:            break;
                   11263:        case 'd':
                   11264:            if (xmlStrEqual(name, BAD_CAST "descendant"))
                   11265:                ret = AXIS_DESCENDANT;
                   11266:            if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
                   11267:                ret = AXIS_DESCENDANT_OR_SELF;
                   11268:            break;
                   11269:        case 'f':
                   11270:            if (xmlStrEqual(name, BAD_CAST "following"))
                   11271:                ret = AXIS_FOLLOWING;
                   11272:            if (xmlStrEqual(name, BAD_CAST "following-sibling"))
                   11273:                ret = AXIS_FOLLOWING_SIBLING;
                   11274:            break;
                   11275:        case 'n':
                   11276:            if (xmlStrEqual(name, BAD_CAST "namespace"))
                   11277:                ret = AXIS_NAMESPACE;
                   11278:            break;
                   11279:        case 'p':
                   11280:            if (xmlStrEqual(name, BAD_CAST "parent"))
                   11281:                ret = AXIS_PARENT;
                   11282:            if (xmlStrEqual(name, BAD_CAST "preceding"))
                   11283:                ret = AXIS_PRECEDING;
                   11284:            if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
                   11285:                ret = AXIS_PRECEDING_SIBLING;
                   11286:            break;
                   11287:        case 's':
                   11288:            if (xmlStrEqual(name, BAD_CAST "self"))
                   11289:                ret = AXIS_SELF;
                   11290:            break;
                   11291:     }
                   11292:     return(ret);
                   11293: }
                   11294: 
                   11295: /**
                   11296:  * xmlXPathCompStep:
                   11297:  * @ctxt:  the XPath Parser context
                   11298:  *
                   11299:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
                   11300:  *                  | AbbreviatedStep
                   11301:  *
                   11302:  * [12] AbbreviatedStep ::=   '.' | '..'
                   11303:  *
                   11304:  * [5] AxisSpecifier ::= AxisName '::'
                   11305:  *                  | AbbreviatedAxisSpecifier
                   11306:  *
                   11307:  * [13] AbbreviatedAxisSpecifier ::= '@'?
                   11308:  *
                   11309:  * Modified for XPtr range support as:
                   11310:  *
                   11311:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
                   11312:  *                     | AbbreviatedStep
                   11313:  *                     | 'range-to' '(' Expr ')' Predicate*
                   11314:  *
                   11315:  * Compile one step in a Location Path
                   11316:  * A location step of . is short for self::node(). This is
                   11317:  * particularly useful in conjunction with //. For example, the
                   11318:  * location path .//para is short for
                   11319:  * self::node()/descendant-or-self::node()/child::para
                   11320:  * and so will select all para descendant elements of the context
                   11321:  * node.
                   11322:  * Similarly, a location step of .. is short for parent::node().
                   11323:  * For example, ../title is short for parent::node()/child::title
                   11324:  * and so will select the title children of the parent of the context
                   11325:  * node.
                   11326:  */
                   11327: static void
                   11328: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
                   11329: #ifdef LIBXML_XPTR_ENABLED
                   11330:     int rangeto = 0;
                   11331:     int op2 = -1;
                   11332: #endif
                   11333: 
                   11334:     SKIP_BLANKS;
                   11335:     if ((CUR == '.') && (NXT(1) == '.')) {
                   11336:        SKIP(2);
                   11337:        SKIP_BLANKS;
                   11338:        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
                   11339:                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11340:     } else if (CUR == '.') {
                   11341:        NEXT;
                   11342:        SKIP_BLANKS;
                   11343:     } else {
                   11344:        xmlChar *name = NULL;
                   11345:        const xmlChar *prefix = NULL;
                   11346:        xmlXPathTestVal test = (xmlXPathTestVal) 0;
                   11347:        xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
                   11348:        xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
                   11349:        int op1;
                   11350: 
                   11351:        /*
                   11352:         * The modification needed for XPointer change to the production
                   11353:         */
                   11354: #ifdef LIBXML_XPTR_ENABLED
                   11355:        if (ctxt->xptr) {
                   11356:            name = xmlXPathParseNCName(ctxt);
                   11357:            if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
                   11358:                 op2 = ctxt->comp->last;
                   11359:                xmlFree(name);
                   11360:                SKIP_BLANKS;
                   11361:                if (CUR != '(') {
                   11362:                    XP_ERROR(XPATH_EXPR_ERROR);
                   11363:                }
                   11364:                NEXT;
                   11365:                SKIP_BLANKS;
                   11366: 
                   11367:                xmlXPathCompileExpr(ctxt, 1);
                   11368:                /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
                   11369:                CHECK_ERROR;
                   11370: 
                   11371:                SKIP_BLANKS;
                   11372:                if (CUR != ')') {
                   11373:                    XP_ERROR(XPATH_EXPR_ERROR);
                   11374:                }
                   11375:                NEXT;
                   11376:                rangeto = 1;
                   11377:                goto eval_predicates;
                   11378:            }
                   11379:        }
                   11380: #endif
                   11381:        if (CUR == '*') {
                   11382:            axis = AXIS_CHILD;
                   11383:        } else {
                   11384:            if (name == NULL)
                   11385:                name = xmlXPathParseNCName(ctxt);
                   11386:            if (name != NULL) {
                   11387:                axis = xmlXPathIsAxisName(name);
                   11388:                if (axis != 0) {
                   11389:                    SKIP_BLANKS;
                   11390:                    if ((CUR == ':') && (NXT(1) == ':')) {
                   11391:                        SKIP(2);
                   11392:                        xmlFree(name);
                   11393:                        name = NULL;
                   11394:                    } else {
                   11395:                        /* an element name can conflict with an axis one :-\ */
                   11396:                        axis = AXIS_CHILD;
                   11397:                    }
                   11398:                } else {
                   11399:                    axis = AXIS_CHILD;
                   11400:                }
                   11401:            } else if (CUR == '@') {
                   11402:                NEXT;
                   11403:                axis = AXIS_ATTRIBUTE;
                   11404:            } else {
                   11405:                axis = AXIS_CHILD;
                   11406:            }
                   11407:        }
                   11408: 
                   11409:         if (ctxt->error != XPATH_EXPRESSION_OK) {
                   11410:             xmlFree(name);
                   11411:             return;
                   11412:         }
                   11413: 
                   11414:        name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
                   11415:        if (test == 0)
                   11416:            return;
                   11417: 
                   11418:         if ((prefix != NULL) && (ctxt->context != NULL) &&
                   11419:            (ctxt->context->flags & XML_XPATH_CHECKNS)) {
                   11420:            if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
                   11421:                xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
                   11422:            }
                   11423:        }
                   11424: #ifdef DEBUG_STEP
                   11425:        xmlGenericError(xmlGenericErrorContext,
                   11426:                "Basis : computing new set\n");
                   11427: #endif
                   11428: 
                   11429: #ifdef DEBUG_STEP
                   11430:        xmlGenericError(xmlGenericErrorContext, "Basis : ");
                   11431:        if (ctxt->value == NULL)
                   11432:            xmlGenericError(xmlGenericErrorContext, "no value\n");
                   11433:        else if (ctxt->value->nodesetval == NULL)
                   11434:            xmlGenericError(xmlGenericErrorContext, "Empty\n");
                   11435:        else
                   11436:            xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
                   11437: #endif
                   11438: 
                   11439: #ifdef LIBXML_XPTR_ENABLED
                   11440: eval_predicates:
                   11441: #endif
                   11442:        op1 = ctxt->comp->last;
                   11443:        ctxt->comp->last = -1;
                   11444: 
                   11445:        SKIP_BLANKS;
                   11446:        while (CUR == '[') {
                   11447:            xmlXPathCompPredicate(ctxt, 0);
                   11448:        }
                   11449: 
                   11450: #ifdef LIBXML_XPTR_ENABLED
                   11451:        if (rangeto) {
                   11452:            PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
                   11453:        } else
                   11454: #endif
                   11455:            PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
                   11456:                           test, type, (void *)prefix, (void *)name);
                   11457: 
                   11458:     }
                   11459: #ifdef DEBUG_STEP
                   11460:     xmlGenericError(xmlGenericErrorContext, "Step : ");
                   11461:     if (ctxt->value == NULL)
                   11462:        xmlGenericError(xmlGenericErrorContext, "no value\n");
                   11463:     else if (ctxt->value->nodesetval == NULL)
                   11464:        xmlGenericError(xmlGenericErrorContext, "Empty\n");
                   11465:     else
                   11466:        xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
                   11467:                ctxt->value->nodesetval);
                   11468: #endif
                   11469: }
                   11470: 
                   11471: /**
                   11472:  * xmlXPathCompRelativeLocationPath:
                   11473:  * @ctxt:  the XPath Parser context
                   11474:  *
                   11475:  *  [3]   RelativeLocationPath ::=   Step
                   11476:  *                     | RelativeLocationPath '/' Step
                   11477:  *                     | AbbreviatedRelativeLocationPath
                   11478:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
                   11479:  *
                   11480:  * Compile a relative location path.
                   11481:  */
                   11482: static void
                   11483: xmlXPathCompRelativeLocationPath
                   11484: (xmlXPathParserContextPtr ctxt) {
                   11485:     SKIP_BLANKS;
                   11486:     if ((CUR == '/') && (NXT(1) == '/')) {
                   11487:        SKIP(2);
                   11488:        SKIP_BLANKS;
                   11489:        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   11490:                         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11491:     } else if (CUR == '/') {
                   11492:            NEXT;
                   11493:        SKIP_BLANKS;
                   11494:     }
                   11495:     xmlXPathCompStep(ctxt);
                   11496:     CHECK_ERROR;
                   11497:     SKIP_BLANKS;
                   11498:     while (CUR == '/') {
                   11499:        if ((CUR == '/') && (NXT(1) == '/')) {
                   11500:            SKIP(2);
                   11501:            SKIP_BLANKS;
                   11502:            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   11503:                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11504:            xmlXPathCompStep(ctxt);
                   11505:        } else if (CUR == '/') {
                   11506:            NEXT;
                   11507:            SKIP_BLANKS;
                   11508:            xmlXPathCompStep(ctxt);
                   11509:        }
                   11510:        SKIP_BLANKS;
                   11511:     }
                   11512: }
                   11513: 
                   11514: /**
                   11515:  * xmlXPathCompLocationPath:
                   11516:  * @ctxt:  the XPath Parser context
                   11517:  *
                   11518:  *  [1]   LocationPath ::=   RelativeLocationPath
                   11519:  *                     | AbsoluteLocationPath
                   11520:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
                   11521:  *                     | AbbreviatedAbsoluteLocationPath
                   11522:  *  [10]   AbbreviatedAbsoluteLocationPath ::=
                   11523:  *                           '//' RelativeLocationPath
                   11524:  *
                   11525:  * Compile a location path
                   11526:  *
                   11527:  * // is short for /descendant-or-self::node()/. For example,
                   11528:  * //para is short for /descendant-or-self::node()/child::para and
                   11529:  * so will select any para element in the document (even a para element
                   11530:  * that is a document element will be selected by //para since the
                   11531:  * document element node is a child of the root node); div//para is
                   11532:  * short for div/descendant-or-self::node()/child::para and so will
                   11533:  * select all para descendants of div children.
                   11534:  */
                   11535: static void
                   11536: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
                   11537:     SKIP_BLANKS;
                   11538:     if (CUR != '/') {
                   11539:         xmlXPathCompRelativeLocationPath(ctxt);
                   11540:     } else {
                   11541:        while (CUR == '/') {
                   11542:            if ((CUR == '/') && (NXT(1) == '/')) {
                   11543:                SKIP(2);
                   11544:                SKIP_BLANKS;
                   11545:                PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
                   11546:                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
                   11547:                xmlXPathCompRelativeLocationPath(ctxt);
                   11548:            } else if (CUR == '/') {
                   11549:                NEXT;
                   11550:                SKIP_BLANKS;
                   11551:                if ((CUR != 0 ) &&
                   11552:                    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
                   11553:                     (CUR == '@') || (CUR == '*')))
                   11554:                    xmlXPathCompRelativeLocationPath(ctxt);
                   11555:            }
                   11556:            CHECK_ERROR;
                   11557:        }
                   11558:     }
                   11559: }
                   11560: 
                   11561: /************************************************************************
                   11562:  *                                                                     *
                   11563:  *             XPath precompiled expression evaluation                 *
                   11564:  *                                                                     *
                   11565:  ************************************************************************/
                   11566: 
                   11567: static int
                   11568: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
                   11569: 
                   11570: #ifdef DEBUG_STEP
                   11571: static void
                   11572: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
                   11573:                          int nbNodes)
                   11574: {
                   11575:     xmlGenericError(xmlGenericErrorContext, "new step : ");
                   11576:     switch (op->value) {
                   11577:         case AXIS_ANCESTOR:
                   11578:             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
                   11579:             break;
                   11580:         case AXIS_ANCESTOR_OR_SELF:
                   11581:             xmlGenericError(xmlGenericErrorContext,
                   11582:                             "axis 'ancestors-or-self' ");
                   11583:             break;
                   11584:         case AXIS_ATTRIBUTE:
                   11585:             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
                   11586:             break;
                   11587:         case AXIS_CHILD:
                   11588:             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
                   11589:             break;
                   11590:         case AXIS_DESCENDANT:
                   11591:             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
                   11592:             break;
                   11593:         case AXIS_DESCENDANT_OR_SELF:
                   11594:             xmlGenericError(xmlGenericErrorContext,
                   11595:                             "axis 'descendant-or-self' ");
                   11596:             break;
                   11597:         case AXIS_FOLLOWING:
                   11598:             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
                   11599:             break;
                   11600:         case AXIS_FOLLOWING_SIBLING:
                   11601:             xmlGenericError(xmlGenericErrorContext,
                   11602:                             "axis 'following-siblings' ");
                   11603:             break;
                   11604:         case AXIS_NAMESPACE:
                   11605:             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
                   11606:             break;
                   11607:         case AXIS_PARENT:
                   11608:             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
                   11609:             break;
                   11610:         case AXIS_PRECEDING:
                   11611:             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
                   11612:             break;
                   11613:         case AXIS_PRECEDING_SIBLING:
                   11614:             xmlGenericError(xmlGenericErrorContext,
                   11615:                             "axis 'preceding-sibling' ");
                   11616:             break;
                   11617:         case AXIS_SELF:
                   11618:             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
                   11619:             break;
                   11620:     }
                   11621:     xmlGenericError(xmlGenericErrorContext,
                   11622:        " context contains %d nodes\n", nbNodes);
                   11623:     switch (op->value2) {
                   11624:         case NODE_TEST_NONE:
                   11625:             xmlGenericError(xmlGenericErrorContext,
                   11626:                             "           searching for none !!!\n");
                   11627:             break;
                   11628:         case NODE_TEST_TYPE:
                   11629:             xmlGenericError(xmlGenericErrorContext,
                   11630:                             "           searching for type %d\n", op->value3);
                   11631:             break;
                   11632:         case NODE_TEST_PI:
                   11633:             xmlGenericError(xmlGenericErrorContext,
                   11634:                             "           searching for PI !!!\n");
                   11635:             break;
                   11636:         case NODE_TEST_ALL:
                   11637:             xmlGenericError(xmlGenericErrorContext,
                   11638:                             "           searching for *\n");
                   11639:             break;
                   11640:         case NODE_TEST_NS:
                   11641:             xmlGenericError(xmlGenericErrorContext,
                   11642:                             "           searching for namespace %s\n",
                   11643:                             op->value5);
                   11644:             break;
                   11645:         case NODE_TEST_NAME:
                   11646:             xmlGenericError(xmlGenericErrorContext,
                   11647:                             "           searching for name %s\n", op->value5);
                   11648:             if (op->value4)
                   11649:                 xmlGenericError(xmlGenericErrorContext,
                   11650:                                 "           with namespace %s\n", op->value4);
                   11651:             break;
                   11652:     }
                   11653:     xmlGenericError(xmlGenericErrorContext, "Testing : ");
                   11654: }
                   11655: #endif /* DEBUG_STEP */
                   11656: 
                   11657: static int
                   11658: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
                   11659:                            xmlXPathStepOpPtr op,
                   11660:                            xmlNodeSetPtr set,
                   11661:                            int contextSize,
                   11662:                            int hasNsNodes)
                   11663: {
                   11664:     if (op->ch1 != -1) {
                   11665:        xmlXPathCompExprPtr comp = ctxt->comp;
                   11666:        /*
                   11667:        * Process inner predicates first.
                   11668:        */
                   11669:        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
                   11670:            /*
                   11671:            * TODO: raise an internal error.
                   11672:            */
                   11673:        }
                   11674:        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
                   11675:            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
                   11676:        CHECK_ERROR0;
                   11677:        if (contextSize <= 0)
                   11678:            return(0);
                   11679:     }
                   11680:     if (op->ch2 != -1) {
                   11681:        xmlXPathContextPtr xpctxt = ctxt->context;
                   11682:        xmlNodePtr contextNode, oldContextNode;
                   11683:        xmlDocPtr oldContextDoc;
                   11684:        int i, res, contextPos = 0, newContextSize;
                   11685:        xmlXPathStepOpPtr exprOp;
                   11686:        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
                   11687: 
                   11688: #ifdef LIBXML_XPTR_ENABLED
                   11689:        /*
                   11690:        * URGENT TODO: Check the following:
                   11691:        *  We don't expect location sets if evaluating prediates, right?
                   11692:        *  Only filters should expect location sets, right?
                   11693:        */
                   11694: #endif
                   11695:        /*
                   11696:        * SPEC XPath 1.0:
                   11697:        *  "For each node in the node-set to be filtered, the
                   11698:        *  PredicateExpr is evaluated with that node as the
                   11699:        *  context node, with the number of nodes in the
                   11700:        *  node-set as the context size, and with the proximity
                   11701:        *  position of the node in the node-set with respect to
                   11702:        *  the axis as the context position;"
                   11703:        * @oldset is the node-set" to be filtered.
                   11704:        *
                   11705:        * SPEC XPath 1.0:
                   11706:        *  "only predicates change the context position and
                   11707:        *  context size (see [2.4 Predicates])."
                   11708:        * Example:
                   11709:        *   node-set  context pos
                   11710:        *    nA         1
                   11711:        *    nB         2
                   11712:        *    nC         3
                   11713:        *   After applying predicate [position() > 1] :
                   11714:        *   node-set  context pos
                   11715:        *    nB         1
                   11716:        *    nC         2
                   11717:        */
                   11718:        oldContextNode = xpctxt->node;
                   11719:        oldContextDoc = xpctxt->doc;
                   11720:        /*
                   11721:        * Get the expression of this predicate.
                   11722:        */
                   11723:        exprOp = &ctxt->comp->steps[op->ch2];
                   11724:        newContextSize = 0;
                   11725:        for (i = 0; i < set->nodeNr; i++) {
                   11726:            if (set->nodeTab[i] == NULL)
                   11727:                continue;
                   11728: 
                   11729:            contextNode = set->nodeTab[i];
                   11730:            xpctxt->node = contextNode;
                   11731:            xpctxt->contextSize = contextSize;
                   11732:            xpctxt->proximityPosition = ++contextPos;
                   11733: 
                   11734:            /*
                   11735:            * Also set the xpath document in case things like
                   11736:            * key() are evaluated in the predicate.
                   11737:            */
                   11738:            if ((contextNode->type != XML_NAMESPACE_DECL) &&
                   11739:                (contextNode->doc != NULL))
                   11740:                xpctxt->doc = contextNode->doc;
                   11741:            /*
                   11742:            * Evaluate the predicate expression with 1 context node
                   11743:            * at a time; this node is packaged into a node set; this
                   11744:            * node set is handed over to the evaluation mechanism.
                   11745:            */
                   11746:            if (contextObj == NULL)
                   11747:                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
1.1.1.3 ! misho    11748:            else {
        !          11749:                if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
        !          11750:                    contextNode) < 0) {
        !          11751:                    ctxt->error = XPATH_MEMORY_ERROR;
        !          11752:                    goto evaluation_exit;
        !          11753:                }
        !          11754:            }
1.1       misho    11755: 
                   11756:            valuePush(ctxt, contextObj);
                   11757: 
                   11758:            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
                   11759: 
                   11760:            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
                   11761:                xmlXPathNodeSetClear(set, hasNsNodes);
                   11762:                newContextSize = 0;
                   11763:                goto evaluation_exit;
                   11764:            }
                   11765: 
                   11766:            if (res != 0) {
                   11767:                newContextSize++;
                   11768:            } else {
                   11769:                /*
                   11770:                * Remove the entry from the initial node set.
                   11771:                */
                   11772:                set->nodeTab[i] = NULL;
                   11773:                if (contextNode->type == XML_NAMESPACE_DECL)
                   11774:                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
                   11775:            }
                   11776:            if (ctxt->value == contextObj) {
                   11777:                /*
                   11778:                * Don't free the temporary XPath object holding the
                   11779:                * context node, in order to avoid massive recreation
                   11780:                * inside this loop.
                   11781:                */
                   11782:                valuePop(ctxt);
                   11783:                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
                   11784:            } else {
                   11785:                /*
                   11786:                * TODO: The object was lost in the evaluation machinery.
                   11787:                *  Can this happen? Maybe in internal-error cases.
                   11788:                */
                   11789:                contextObj = NULL;
                   11790:            }
                   11791:        }
                   11792: 
                   11793:        if (contextObj != NULL) {
                   11794:            if (ctxt->value == contextObj)
                   11795:                valuePop(ctxt);
                   11796:            xmlXPathReleaseObject(xpctxt, contextObj);
                   11797:        }
                   11798: evaluation_exit:
                   11799:        if (exprRes != NULL)
                   11800:            xmlXPathReleaseObject(ctxt->context, exprRes);
                   11801:        /*
                   11802:        * Reset/invalidate the context.
                   11803:        */
                   11804:        xpctxt->node = oldContextNode;
                   11805:        xpctxt->doc = oldContextDoc;
                   11806:        xpctxt->contextSize = -1;
                   11807:        xpctxt->proximityPosition = -1;
                   11808:        return(newContextSize);
                   11809:     }
                   11810:     return(contextSize);
                   11811: }
                   11812: 
                   11813: static int
                   11814: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
                   11815:                                      xmlXPathStepOpPtr op,
                   11816:                                      xmlNodeSetPtr set,
                   11817:                                      int contextSize,
                   11818:                                      int minPos,
                   11819:                                      int maxPos,
                   11820:                                      int hasNsNodes)
                   11821: {
                   11822:     if (op->ch1 != -1) {
                   11823:        xmlXPathCompExprPtr comp = ctxt->comp;
                   11824:        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
                   11825:            /*
                   11826:            * TODO: raise an internal error.
                   11827:            */
                   11828:        }
                   11829:        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
                   11830:            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
                   11831:        CHECK_ERROR0;
                   11832:        if (contextSize <= 0)
                   11833:            return(0);
                   11834:     }
                   11835:     /*
                   11836:     * Check if the node set contains a sufficient number of nodes for
                   11837:     * the requested range.
                   11838:     */
                   11839:     if (contextSize < minPos) {
                   11840:        xmlXPathNodeSetClear(set, hasNsNodes);
                   11841:        return(0);
                   11842:     }
                   11843:     if (op->ch2 == -1) {
                   11844:        /*
                   11845:        * TODO: Can this ever happen?
                   11846:        */
                   11847:        return (contextSize);
                   11848:     } else {
                   11849:        xmlDocPtr oldContextDoc;
                   11850:        int i, pos = 0, newContextSize = 0, contextPos = 0, res;
                   11851:        xmlXPathStepOpPtr exprOp;
                   11852:        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
                   11853:        xmlNodePtr oldContextNode, contextNode = NULL;
                   11854:        xmlXPathContextPtr xpctxt = ctxt->context;
1.1.1.2   misho    11855:         int frame;
1.1       misho    11856: 
                   11857: #ifdef LIBXML_XPTR_ENABLED
                   11858:            /*
                   11859:            * URGENT TODO: Check the following:
                   11860:            *  We don't expect location sets if evaluating prediates, right?
                   11861:            *  Only filters should expect location sets, right?
                   11862:        */
                   11863: #endif /* LIBXML_XPTR_ENABLED */
                   11864: 
                   11865:        /*
                   11866:        * Save old context.
                   11867:        */
                   11868:        oldContextNode = xpctxt->node;
                   11869:        oldContextDoc = xpctxt->doc;
                   11870:        /*
                   11871:        * Get the expression of this predicate.
                   11872:        */
                   11873:        exprOp = &ctxt->comp->steps[op->ch2];
                   11874:        for (i = 0; i < set->nodeNr; i++) {
1.1.1.2   misho    11875:             xmlXPathObjectPtr tmp;
                   11876: 
1.1       misho    11877:            if (set->nodeTab[i] == NULL)
                   11878:                continue;
                   11879: 
                   11880:            contextNode = set->nodeTab[i];
                   11881:            xpctxt->node = contextNode;
                   11882:            xpctxt->contextSize = contextSize;
                   11883:            xpctxt->proximityPosition = ++contextPos;
                   11884: 
                   11885:            /*
                   11886:            * Initialize the new set.
                   11887:            * Also set the xpath document in case things like
                   11888:            * key() evaluation are attempted on the predicate
                   11889:            */
                   11890:            if ((contextNode->type != XML_NAMESPACE_DECL) &&
                   11891:                (contextNode->doc != NULL))
                   11892:                xpctxt->doc = contextNode->doc;
                   11893:            /*
                   11894:            * Evaluate the predicate expression with 1 context node
                   11895:            * at a time; this node is packaged into a node set; this
                   11896:            * node set is handed over to the evaluation mechanism.
                   11897:            */
                   11898:            if (contextObj == NULL)
                   11899:                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
1.1.1.3 ! misho    11900:            else {
        !          11901:                if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
        !          11902:                    contextNode) < 0) {
        !          11903:                    ctxt->error = XPATH_MEMORY_ERROR;
        !          11904:                    goto evaluation_exit;
        !          11905:                }
        !          11906:            }
1.1       misho    11907: 
1.1.1.2   misho    11908:             frame = xmlXPathSetFrame(ctxt);
1.1       misho    11909:            valuePush(ctxt, contextObj);
                   11910:            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
1.1.1.2   misho    11911:             tmp = valuePop(ctxt);
                   11912:             xmlXPathPopFrame(ctxt, frame);
1.1       misho    11913: 
                   11914:            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
1.1.1.2   misho    11915:                 while (tmp != contextObj) {
                   11916:                     /*
                   11917:                      * Free up the result
                   11918:                      * then pop off contextObj, which will be freed later
                   11919:                      */
                   11920:                     xmlXPathReleaseObject(xpctxt, tmp);
                   11921:                     tmp = valuePop(ctxt);
                   11922:                 }
1.1       misho    11923:                goto evaluation_error;
                   11924:            }
1.1.1.2   misho    11925:             /* push the result back onto the stack */
                   11926:             valuePush(ctxt, tmp);
1.1       misho    11927: 
                   11928:            if (res)
                   11929:                pos++;
                   11930: 
                   11931:            if (res && (pos >= minPos) && (pos <= maxPos)) {
                   11932:                /*
                   11933:                * Fits in the requested range.
                   11934:                */
                   11935:                newContextSize++;
                   11936:                if (minPos == maxPos) {
                   11937:                    /*
                   11938:                    * Only 1 node was requested.
                   11939:                    */
                   11940:                    if (contextNode->type == XML_NAMESPACE_DECL) {
                   11941:                        /*
                   11942:                        * As always: take care of those nasty
                   11943:                        * namespace nodes.
                   11944:                        */
                   11945:                        set->nodeTab[i] = NULL;
                   11946:                    }
                   11947:                    xmlXPathNodeSetClear(set, hasNsNodes);
                   11948:                    set->nodeNr = 1;
                   11949:                    set->nodeTab[0] = contextNode;
                   11950:                    goto evaluation_exit;
                   11951:                }
                   11952:                if (pos == maxPos) {
                   11953:                    /*
                   11954:                    * We are done.
                   11955:                    */
                   11956:                    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
                   11957:                    goto evaluation_exit;
                   11958:                }
                   11959:            } else {
                   11960:                /*
                   11961:                * Remove the entry from the initial node set.
                   11962:                */
                   11963:                set->nodeTab[i] = NULL;
                   11964:                if (contextNode->type == XML_NAMESPACE_DECL)
                   11965:                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
                   11966:            }
                   11967:            if (exprRes != NULL) {
                   11968:                xmlXPathReleaseObject(ctxt->context, exprRes);
                   11969:                exprRes = NULL;
                   11970:            }
                   11971:            if (ctxt->value == contextObj) {
                   11972:                /*
                   11973:                * Don't free the temporary XPath object holding the
                   11974:                * context node, in order to avoid massive recreation
                   11975:                * inside this loop.
                   11976:                */
                   11977:                valuePop(ctxt);
                   11978:                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
                   11979:            } else {
                   11980:                /*
                   11981:                * The object was lost in the evaluation machinery.
                   11982:                * Can this happen? Maybe in case of internal-errors.
                   11983:                */
                   11984:                contextObj = NULL;
                   11985:            }
                   11986:        }
                   11987:        goto evaluation_exit;
                   11988: 
                   11989: evaluation_error:
                   11990:        xmlXPathNodeSetClear(set, hasNsNodes);
                   11991:        newContextSize = 0;
                   11992: 
                   11993: evaluation_exit:
                   11994:        if (contextObj != NULL) {
                   11995:            if (ctxt->value == contextObj)
                   11996:                valuePop(ctxt);
                   11997:            xmlXPathReleaseObject(xpctxt, contextObj);
                   11998:        }
                   11999:        if (exprRes != NULL)
                   12000:            xmlXPathReleaseObject(ctxt->context, exprRes);
                   12001:        /*
                   12002:        * Reset/invalidate the context.
                   12003:        */
                   12004:        xpctxt->node = oldContextNode;
                   12005:        xpctxt->doc = oldContextDoc;
                   12006:        xpctxt->contextSize = -1;
                   12007:        xpctxt->proximityPosition = -1;
                   12008:        return(newContextSize);
                   12009:     }
                   12010:     return(contextSize);
                   12011: }
                   12012: 
                   12013: static int
                   12014: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
                   12015:                            xmlXPathStepOpPtr op,
                   12016:                            int *maxPos)
                   12017: {
                   12018: 
                   12019:     xmlXPathStepOpPtr exprOp;
                   12020: 
                   12021:     /*
                   12022:     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
                   12023:     */
                   12024: 
                   12025:     /*
                   12026:     * If not -1, then ch1 will point to:
                   12027:     * 1) For predicates (XPATH_OP_PREDICATE):
                   12028:     *    - an inner predicate operator
                   12029:     * 2) For filters (XPATH_OP_FILTER):
                   12030:     *    - an inner filter operater OR
                   12031:     *    - an expression selecting the node set.
                   12032:     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
                   12033:     */
                   12034:     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
                   12035:        return(0);
                   12036: 
                   12037:     if (op->ch2 != -1) {
                   12038:        exprOp = &ctxt->comp->steps[op->ch2];
                   12039:     } else
                   12040:        return(0);
                   12041: 
                   12042:     if ((exprOp != NULL) &&
                   12043:        (exprOp->op == XPATH_OP_VALUE) &&
                   12044:        (exprOp->value4 != NULL) &&
                   12045:        (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
                   12046:     {
                   12047:        /*
                   12048:        * We have a "[n]" predicate here.
                   12049:        * TODO: Unfortunately this simplistic test here is not
                   12050:        * able to detect a position() predicate in compound
                   12051:        * expressions like "[@attr = 'a" and position() = 1],
                   12052:        * and even not the usage of position() in
                   12053:        * "[position() = 1]"; thus - obviously - a position-range,
                   12054:        * like it "[position() < 5]", is also not detected.
                   12055:        * Maybe we could rewrite the AST to ease the optimization.
                   12056:        */
                   12057:        *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
                   12058: 
                   12059:        if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
                   12060:            (float) *maxPos)
                   12061:        {
                   12062:            return(1);
                   12063:        }
                   12064:     }
                   12065:     return(0);
                   12066: }
                   12067: 
                   12068: static int
                   12069: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
                   12070:                            xmlXPathStepOpPtr op,
                   12071:                           xmlNodePtr * first, xmlNodePtr * last,
                   12072:                           int toBool)
                   12073: {
                   12074: 
                   12075: #define XP_TEST_HIT \
                   12076:     if (hasAxisRange != 0) { \
                   12077:        if (++pos == maxPos) { \
1.1.1.3 ! misho    12078:            if (addNode(seq, cur) < 0) \
        !          12079:                ctxt->error = XPATH_MEMORY_ERROR; \
        !          12080:            goto axis_range_end; } \
1.1       misho    12081:     } else { \
1.1.1.3 ! misho    12082:        if (addNode(seq, cur) < 0) \
        !          12083:            ctxt->error = XPATH_MEMORY_ERROR; \
1.1       misho    12084:        if (breakOnFirstHit) goto first_hit; }
                   12085: 
                   12086: #define XP_TEST_HIT_NS \
                   12087:     if (hasAxisRange != 0) { \
                   12088:        if (++pos == maxPos) { \
                   12089:            hasNsNodes = 1; \
1.1.1.3 ! misho    12090:            if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
        !          12091:                ctxt->error = XPATH_MEMORY_ERROR; \
1.1       misho    12092:        goto axis_range_end; } \
                   12093:     } else { \
                   12094:        hasNsNodes = 1; \
1.1.1.3 ! misho    12095:        if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
        !          12096:            ctxt->error = XPATH_MEMORY_ERROR; \
1.1       misho    12097:        if (breakOnFirstHit) goto first_hit; }
                   12098: 
                   12099:     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
                   12100:     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
                   12101:     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
                   12102:     const xmlChar *prefix = op->value4;
                   12103:     const xmlChar *name = op->value5;
                   12104:     const xmlChar *URI = NULL;
                   12105: 
                   12106: #ifdef DEBUG_STEP
                   12107:     int nbMatches = 0, prevMatches = 0;
                   12108: #endif
                   12109:     int total = 0, hasNsNodes = 0;
                   12110:     /* The popped object holding the context nodes */
                   12111:     xmlXPathObjectPtr obj;
                   12112:     /* The set of context nodes for the node tests */
                   12113:     xmlNodeSetPtr contextSeq;
                   12114:     int contextIdx;
                   12115:     xmlNodePtr contextNode;
                   12116:     /* The final resulting node set wrt to all context nodes */
                   12117:     xmlNodeSetPtr outSeq;
                   12118:     /*
                   12119:     * The temporary resulting node set wrt 1 context node.
                   12120:     * Used to feed predicate evaluation.
                   12121:     */
                   12122:     xmlNodeSetPtr seq;
                   12123:     xmlNodePtr cur;
                   12124:     /* First predicate operator */
                   12125:     xmlXPathStepOpPtr predOp;
                   12126:     int maxPos; /* The requested position() (when a "[n]" predicate) */
                   12127:     int hasPredicateRange, hasAxisRange, pos, size, newSize;
                   12128:     int breakOnFirstHit;
                   12129: 
                   12130:     xmlXPathTraversalFunction next = NULL;
1.1.1.3 ! misho    12131:     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
1.1       misho    12132:     xmlXPathNodeSetMergeFunction mergeAndClear;
                   12133:     xmlNodePtr oldContextNode;
                   12134:     xmlXPathContextPtr xpctxt = ctxt->context;
                   12135: 
                   12136: 
                   12137:     CHECK_TYPE0(XPATH_NODESET);
                   12138:     obj = valuePop(ctxt);
                   12139:     /*
                   12140:     * Setup namespaces.
                   12141:     */
                   12142:     if (prefix != NULL) {
                   12143:         URI = xmlXPathNsLookup(xpctxt, prefix);
                   12144:         if (URI == NULL) {
                   12145:            xmlXPathReleaseObject(xpctxt, obj);
                   12146:             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
                   12147:        }
                   12148:     }
                   12149:     /*
                   12150:     * Setup axis.
                   12151:     *
                   12152:     * MAYBE FUTURE TODO: merging optimizations:
                   12153:     * - If the nodes to be traversed wrt to the initial nodes and
                   12154:     *   the current axis cannot overlap, then we could avoid searching
                   12155:     *   for duplicates during the merge.
                   12156:     *   But the question is how/when to evaluate if they cannot overlap.
                   12157:     *   Example: if we know that for two initial nodes, the one is
                   12158:     *   not in the ancestor-or-self axis of the other, then we could safely
                   12159:     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
                   12160:     *   the descendant-or-self axis.
                   12161:     */
                   12162:     mergeAndClear = xmlXPathNodeSetMergeAndClear;
                   12163:     switch (axis) {
                   12164:         case AXIS_ANCESTOR:
                   12165:             first = NULL;
                   12166:             next = xmlXPathNextAncestor;
                   12167:             break;
                   12168:         case AXIS_ANCESTOR_OR_SELF:
                   12169:             first = NULL;
                   12170:             next = xmlXPathNextAncestorOrSelf;
                   12171:             break;
                   12172:         case AXIS_ATTRIBUTE:
                   12173:             first = NULL;
                   12174:            last = NULL;
                   12175:             next = xmlXPathNextAttribute;
                   12176:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12177:             break;
                   12178:         case AXIS_CHILD:
                   12179:            last = NULL;
                   12180:            if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
                   12181:                (type == NODE_TYPE_NODE))
                   12182:            {
                   12183:                /*
                   12184:                * Optimization if an element node type is 'element'.
                   12185:                */
                   12186:                next = xmlXPathNextChildElement;
                   12187:            } else
                   12188:                next = xmlXPathNextChild;
                   12189:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12190:             break;
                   12191:         case AXIS_DESCENDANT:
                   12192:            last = NULL;
                   12193:             next = xmlXPathNextDescendant;
                   12194:             break;
                   12195:         case AXIS_DESCENDANT_OR_SELF:
                   12196:            last = NULL;
                   12197:             next = xmlXPathNextDescendantOrSelf;
                   12198:             break;
                   12199:         case AXIS_FOLLOWING:
                   12200:            last = NULL;
                   12201:             next = xmlXPathNextFollowing;
                   12202:             break;
                   12203:         case AXIS_FOLLOWING_SIBLING:
                   12204:            last = NULL;
                   12205:             next = xmlXPathNextFollowingSibling;
                   12206:             break;
                   12207:         case AXIS_NAMESPACE:
                   12208:             first = NULL;
                   12209:            last = NULL;
                   12210:             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
                   12211:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12212:             break;
                   12213:         case AXIS_PARENT:
                   12214:             first = NULL;
                   12215:             next = xmlXPathNextParent;
                   12216:             break;
                   12217:         case AXIS_PRECEDING:
                   12218:             first = NULL;
                   12219:             next = xmlXPathNextPrecedingInternal;
                   12220:             break;
                   12221:         case AXIS_PRECEDING_SIBLING:
                   12222:             first = NULL;
                   12223:             next = xmlXPathNextPrecedingSibling;
                   12224:             break;
                   12225:         case AXIS_SELF:
                   12226:             first = NULL;
                   12227:            last = NULL;
                   12228:             next = xmlXPathNextSelf;
                   12229:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
                   12230:             break;
                   12231:     }
                   12232: 
                   12233: #ifdef DEBUG_STEP
                   12234:     xmlXPathDebugDumpStepAxis(op,
                   12235:        (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
                   12236: #endif
                   12237: 
                   12238:     if (next == NULL) {
                   12239:        xmlXPathReleaseObject(xpctxt, obj);
                   12240:         return(0);
                   12241:     }
                   12242:     contextSeq = obj->nodesetval;
                   12243:     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
                   12244:        xmlXPathReleaseObject(xpctxt, obj);
                   12245:         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
                   12246:         return(0);
                   12247:     }
                   12248:     /*
                   12249:     * Predicate optimization ---------------------------------------------
                   12250:     * If this step has a last predicate, which contains a position(),
                   12251:     * then we'll optimize (although not exactly "position()", but only
                   12252:     * the  short-hand form, i.e., "[n]".
                   12253:     *
                   12254:     * Example - expression "/foo[parent::bar][1]":
                   12255:     *
                   12256:     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
                   12257:     *   ROOT                               -- op->ch1
                   12258:     *   PREDICATE                          -- op->ch2 (predOp)
                   12259:     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
                   12260:     *       SORT
                   12261:     *         COLLECT  'parent' 'name' 'node' bar
                   12262:     *           NODE
                   12263:     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
                   12264:     *
                   12265:     */
                   12266:     maxPos = 0;
                   12267:     predOp = NULL;
                   12268:     hasPredicateRange = 0;
                   12269:     hasAxisRange = 0;
                   12270:     if (op->ch2 != -1) {
                   12271:        /*
                   12272:        * There's at least one predicate. 16 == XPATH_OP_PREDICATE
                   12273:        */
                   12274:        predOp = &ctxt->comp->steps[op->ch2];
                   12275:        if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
                   12276:            if (predOp->ch1 != -1) {
                   12277:                /*
                   12278:                * Use the next inner predicate operator.
                   12279:                */
                   12280:                predOp = &ctxt->comp->steps[predOp->ch1];
                   12281:                hasPredicateRange = 1;
                   12282:            } else {
                   12283:                /*
                   12284:                * There's no other predicate than the [n] predicate.
                   12285:                */
                   12286:                predOp = NULL;
                   12287:                hasAxisRange = 1;
                   12288:            }
                   12289:        }
                   12290:     }
                   12291:     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
                   12292:     /*
                   12293:     * Axis traversal -----------------------------------------------------
                   12294:     */
                   12295:     /*
                   12296:      * 2.3 Node Tests
                   12297:      *  - For the attribute axis, the principal node type is attribute.
                   12298:      *  - For the namespace axis, the principal node type is namespace.
                   12299:      *  - For other axes, the principal node type is element.
                   12300:      *
                   12301:      * A node test * is true for any node of the
                   12302:      * principal node type. For example, child::* will
                   12303:      * select all element children of the context node
                   12304:      */
                   12305:     oldContextNode = xpctxt->node;
                   12306:     addNode = xmlXPathNodeSetAddUnique;
                   12307:     outSeq = NULL;
                   12308:     seq = NULL;
                   12309:     contextNode = NULL;
                   12310:     contextIdx = 0;
                   12311: 
                   12312: 
1.1.1.3 ! misho    12313:     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
        !          12314:            (ctxt->error == XPATH_EXPRESSION_OK)) {
        !          12315:        xpctxt->node = contextSeq->nodeTab[contextIdx++];
1.1       misho    12316: 
                   12317:        if (seq == NULL) {
                   12318:            seq = xmlXPathNodeSetCreate(NULL);
                   12319:            if (seq == NULL) {
                   12320:                total = 0;
                   12321:                goto error;
                   12322:            }
                   12323:        }
                   12324:        /*
                   12325:        * Traverse the axis and test the nodes.
                   12326:        */
                   12327:        pos = 0;
                   12328:        cur = NULL;
                   12329:        hasNsNodes = 0;
                   12330:         do {
                   12331:             cur = next(ctxt, cur);
                   12332:             if (cur == NULL)
                   12333:                 break;
                   12334: 
                   12335:            /*
                   12336:            * QUESTION TODO: What does the "first" and "last" stuff do?
                   12337:            */
                   12338:             if ((first != NULL) && (*first != NULL)) {
                   12339:                if (*first == cur)
                   12340:                    break;
                   12341:                if (((total % 256) == 0) &&
                   12342: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   12343:                    (xmlXPathCmpNodesExt(*first, cur) >= 0))
                   12344: #else
                   12345:                    (xmlXPathCmpNodes(*first, cur) >= 0))
                   12346: #endif
                   12347:                {
                   12348:                    break;
                   12349:                }
                   12350:            }
                   12351:            if ((last != NULL) && (*last != NULL)) {
                   12352:                if (*last == cur)
                   12353:                    break;
                   12354:                if (((total % 256) == 0) &&
                   12355: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
                   12356:                    (xmlXPathCmpNodesExt(cur, *last) >= 0))
                   12357: #else
                   12358:                    (xmlXPathCmpNodes(cur, *last) >= 0))
                   12359: #endif
                   12360:                {
                   12361:                    break;
                   12362:                }
                   12363:            }
                   12364: 
                   12365:             total++;
                   12366: 
                   12367: #ifdef DEBUG_STEP
                   12368:             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
                   12369: #endif
                   12370: 
                   12371:            switch (test) {
                   12372:                 case NODE_TEST_NONE:
                   12373:                    total = 0;
                   12374:                     STRANGE
                   12375:                    goto error;
                   12376:                 case NODE_TEST_TYPE:
                   12377:                    /*
                   12378:                    * TODO: Don't we need to use
                   12379:                    *  xmlXPathNodeSetAddNs() for namespace nodes here?
                   12380:                    *  Surprisingly, some c14n tests fail, if we do this.
                   12381:                    */
                   12382:                    if (type == NODE_TYPE_NODE) {
                   12383:                        switch (cur->type) {
                   12384:                            case XML_DOCUMENT_NODE:
                   12385:                            case XML_HTML_DOCUMENT_NODE:
                   12386: #ifdef LIBXML_DOCB_ENABLED
                   12387:                            case XML_DOCB_DOCUMENT_NODE:
                   12388: #endif
                   12389:                            case XML_ELEMENT_NODE:
                   12390:                            case XML_ATTRIBUTE_NODE:
                   12391:                            case XML_PI_NODE:
                   12392:                            case XML_COMMENT_NODE:
                   12393:                            case XML_CDATA_SECTION_NODE:
                   12394:                            case XML_TEXT_NODE:
                   12395:                            case XML_NAMESPACE_DECL:
                   12396:                                XP_TEST_HIT
                   12397:                                break;
                   12398:                            default:
                   12399:                                break;
                   12400:                        }
                   12401:                    } else if (cur->type == type) {
1.1.1.3 ! misho    12402:                        if (cur->type == XML_NAMESPACE_DECL)
1.1       misho    12403:                            XP_TEST_HIT_NS
                   12404:                        else
                   12405:                            XP_TEST_HIT
                   12406:                    } else if ((type == NODE_TYPE_TEXT) &&
                   12407:                         (cur->type == XML_CDATA_SECTION_NODE))
                   12408:                    {
                   12409:                        XP_TEST_HIT
                   12410:                    }
                   12411:                    break;
                   12412:                 case NODE_TEST_PI:
                   12413:                     if ((cur->type == XML_PI_NODE) &&
                   12414:                         ((name == NULL) || xmlStrEqual(name, cur->name)))
                   12415:                    {
                   12416:                        XP_TEST_HIT
                   12417:                     }
                   12418:                     break;
                   12419:                 case NODE_TEST_ALL:
                   12420:                     if (axis == AXIS_ATTRIBUTE) {
                   12421:                         if (cur->type == XML_ATTRIBUTE_NODE)
                   12422:                        {
                   12423:                            XP_TEST_HIT
                   12424:                         }
                   12425:                     } else if (axis == AXIS_NAMESPACE) {
                   12426:                         if (cur->type == XML_NAMESPACE_DECL)
                   12427:                        {
                   12428:                            XP_TEST_HIT_NS
                   12429:                         }
                   12430:                     } else {
                   12431:                         if (cur->type == XML_ELEMENT_NODE) {
                   12432:                             if (prefix == NULL)
                   12433:                            {
                   12434:                                XP_TEST_HIT
                   12435: 
                   12436:                             } else if ((cur->ns != NULL) &&
                   12437:                                (xmlStrEqual(URI, cur->ns->href)))
                   12438:                            {
                   12439:                                XP_TEST_HIT
                   12440:                             }
                   12441:                         }
                   12442:                     }
                   12443:                     break;
                   12444:                 case NODE_TEST_NS:{
                   12445:                         TODO;
                   12446:                         break;
                   12447:                     }
                   12448:                 case NODE_TEST_NAME:
                   12449:                     if (axis == AXIS_ATTRIBUTE) {
                   12450:                         if (cur->type != XML_ATTRIBUTE_NODE)
                   12451:                            break;
                   12452:                    } else if (axis == AXIS_NAMESPACE) {
                   12453:                         if (cur->type != XML_NAMESPACE_DECL)
                   12454:                            break;
                   12455:                    } else {
                   12456:                        if (cur->type != XML_ELEMENT_NODE)
                   12457:                            break;
                   12458:                    }
                   12459:                     switch (cur->type) {
                   12460:                         case XML_ELEMENT_NODE:
                   12461:                             if (xmlStrEqual(name, cur->name)) {
                   12462:                                 if (prefix == NULL) {
                   12463:                                     if (cur->ns == NULL)
                   12464:                                    {
                   12465:                                        XP_TEST_HIT
                   12466:                                     }
                   12467:                                 } else {
                   12468:                                     if ((cur->ns != NULL) &&
                   12469:                                         (xmlStrEqual(URI, cur->ns->href)))
                   12470:                                    {
                   12471:                                        XP_TEST_HIT
                   12472:                                     }
                   12473:                                 }
                   12474:                             }
                   12475:                             break;
                   12476:                         case XML_ATTRIBUTE_NODE:{
                   12477:                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
                   12478: 
                   12479:                                 if (xmlStrEqual(name, attr->name)) {
                   12480:                                     if (prefix == NULL) {
                   12481:                                         if ((attr->ns == NULL) ||
                   12482:                                             (attr->ns->prefix == NULL))
                   12483:                                        {
                   12484:                                            XP_TEST_HIT
                   12485:                                         }
                   12486:                                     } else {
                   12487:                                         if ((attr->ns != NULL) &&
                   12488:                                             (xmlStrEqual(URI,
                   12489:                                              attr->ns->href)))
                   12490:                                        {
                   12491:                                            XP_TEST_HIT
                   12492:                                         }
                   12493:                                     }
                   12494:                                 }
                   12495:                                 break;
                   12496:                             }
                   12497:                         case XML_NAMESPACE_DECL:
                   12498:                             if (cur->type == XML_NAMESPACE_DECL) {
                   12499:                                 xmlNsPtr ns = (xmlNsPtr) cur;
                   12500: 
                   12501:                                 if ((ns->prefix != NULL) && (name != NULL)
                   12502:                                     && (xmlStrEqual(ns->prefix, name)))
                   12503:                                {
                   12504:                                    XP_TEST_HIT_NS
                   12505:                                 }
                   12506:                             }
                   12507:                             break;
                   12508:                         default:
                   12509:                             break;
                   12510:                     }
                   12511:                     break;
                   12512:            } /* switch(test) */
1.1.1.3 ! misho    12513:         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
1.1       misho    12514: 
                   12515:        goto apply_predicates;
                   12516: 
                   12517: axis_range_end: /* ----------------------------------------------------- */
                   12518:        /*
                   12519:        * We have a "/foo[n]", and position() = n was reached.
                   12520:        * Note that we can have as well "/foo/::parent::foo[1]", so
                   12521:        * a duplicate-aware merge is still needed.
                   12522:        * Merge with the result.
                   12523:        */
                   12524:        if (outSeq == NULL) {
                   12525:            outSeq = seq;
                   12526:            seq = NULL;
                   12527:        } else
                   12528:            outSeq = mergeAndClear(outSeq, seq, 0);
                   12529:        /*
                   12530:        * Break if only a true/false result was requested.
                   12531:        */
                   12532:        if (toBool)
                   12533:            break;
                   12534:        continue;
                   12535: 
                   12536: first_hit: /* ---------------------------------------------------------- */
                   12537:        /*
                   12538:        * Break if only a true/false result was requested and
                   12539:        * no predicates existed and a node test succeeded.
                   12540:        */
                   12541:        if (outSeq == NULL) {
                   12542:            outSeq = seq;
                   12543:            seq = NULL;
                   12544:        } else
                   12545:            outSeq = mergeAndClear(outSeq, seq, 0);
                   12546:        break;
                   12547: 
                   12548: #ifdef DEBUG_STEP
                   12549:        if (seq != NULL)
                   12550:            nbMatches += seq->nodeNr;
                   12551: #endif
                   12552: 
                   12553: apply_predicates: /* --------------------------------------------------- */
1.1.1.3 ! misho    12554:         if (ctxt->error != XPATH_EXPRESSION_OK)
        !          12555:            goto error;
        !          12556: 
1.1       misho    12557:         /*
                   12558:        * Apply predicates.
                   12559:        */
                   12560:         if ((predOp != NULL) && (seq->nodeNr > 0)) {
                   12561:            /*
                   12562:            * E.g. when we have a "/foo[some expression][n]".
1.1.1.3 ! misho    12563:            */
1.1       misho    12564:            /*
                   12565:            * QUESTION TODO: The old predicate evaluation took into
                   12566:            *  account location-sets.
                   12567:            *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
                   12568:            *  Do we expect such a set here?
                   12569:            *  All what I learned now from the evaluation semantics
                   12570:            *  does not indicate that a location-set will be processed
                   12571:            *  here, so this looks OK.
1.1.1.3 ! misho    12572:            */
1.1       misho    12573:            /*
                   12574:            * Iterate over all predicates, starting with the outermost
                   12575:            * predicate.
                   12576:            * TODO: Problem: we cannot execute the inner predicates first
                   12577:            *  since we cannot go back *up* the operator tree!
                   12578:            *  Options we have:
                   12579:            *  1) Use of recursive functions (like is it currently done
                   12580:            *     via xmlXPathCompOpEval())
                   12581:            *  2) Add a predicate evaluation information stack to the
                   12582:            *     context struct
                   12583:            *  3) Change the way the operators are linked; we need a
                   12584:            *     "parent" field on xmlXPathStepOp
                   12585:            *
                   12586:            * For the moment, I'll try to solve this with a recursive
                   12587:            * function: xmlXPathCompOpEvalPredicate().
                   12588:            */
                   12589:            size = seq->nodeNr;
                   12590:            if (hasPredicateRange != 0)
                   12591:                newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
                   12592:                    predOp, seq, size, maxPos, maxPos, hasNsNodes);
                   12593:            else
                   12594:                newSize = xmlXPathCompOpEvalPredicate(ctxt,
                   12595:                    predOp, seq, size, hasNsNodes);
                   12596: 
                   12597:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   12598:                total = 0;
                   12599:                goto error;
                   12600:            }
                   12601:            /*
                   12602:            * Add the filtered set of nodes to the result node set.
                   12603:            */
                   12604:            if (newSize == 0) {
                   12605:                /*
                   12606:                * The predicates filtered all nodes out.
                   12607:                */
                   12608:                xmlXPathNodeSetClear(seq, hasNsNodes);
                   12609:            } else if (seq->nodeNr > 0) {
                   12610:                /*
                   12611:                * Add to result set.
                   12612:                */
                   12613:                if (outSeq == NULL) {
                   12614:                    if (size != newSize) {
                   12615:                        /*
                   12616:                        * We need to merge and clear here, since
                   12617:                        * the sequence will contained NULLed entries.
                   12618:                        */
                   12619:                        outSeq = mergeAndClear(NULL, seq, 1);
                   12620:                    } else {
                   12621:                        outSeq = seq;
                   12622:                        seq = NULL;
                   12623:                    }
                   12624:                } else
                   12625:                    outSeq = mergeAndClear(outSeq, seq,
                   12626:                        (size != newSize) ? 1: 0);
                   12627:                /*
                   12628:                * Break if only a true/false result was requested.
                   12629:                */
                   12630:                if (toBool)
                   12631:                    break;
                   12632:            }
                   12633:         } else if (seq->nodeNr > 0) {
                   12634:            /*
                   12635:            * Add to result set.
                   12636:            */
                   12637:            if (outSeq == NULL) {
                   12638:                outSeq = seq;
                   12639:                seq = NULL;
                   12640:            } else {
                   12641:                outSeq = mergeAndClear(outSeq, seq, 0);
                   12642:            }
                   12643:        }
                   12644:     }
                   12645: 
                   12646: error:
                   12647:     if ((obj->boolval) && (obj->user != NULL)) {
                   12648:        /*
                   12649:        * QUESTION TODO: What does this do and why?
                   12650:        * TODO: Do we have to do this also for the "error"
                   12651:        * cleanup further down?
                   12652:        */
                   12653:        ctxt->value->boolval = 1;
                   12654:        ctxt->value->user = obj->user;
                   12655:        obj->user = NULL;
                   12656:        obj->boolval = 0;
                   12657:     }
                   12658:     xmlXPathReleaseObject(xpctxt, obj);
                   12659: 
                   12660:     /*
                   12661:     * Ensure we return at least an emtpy set.
                   12662:     */
                   12663:     if (outSeq == NULL) {
                   12664:        if ((seq != NULL) && (seq->nodeNr == 0))
                   12665:            outSeq = seq;
                   12666:        else
                   12667:            outSeq = xmlXPathNodeSetCreate(NULL);
                   12668:         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
                   12669:     }
                   12670:     if ((seq != NULL) && (seq != outSeq)) {
                   12671:         xmlXPathFreeNodeSet(seq);
                   12672:     }
                   12673:     /*
                   12674:     * Hand over the result. Better to push the set also in
                   12675:     * case of errors.
                   12676:     */
                   12677:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
                   12678:     /*
                   12679:     * Reset the context node.
                   12680:     */
                   12681:     xpctxt->node = oldContextNode;
                   12682: 
                   12683: #ifdef DEBUG_STEP
                   12684:     xmlGenericError(xmlGenericErrorContext,
                   12685:        "\nExamined %d nodes, found %d nodes at that step\n",
                   12686:        total, nbMatches);
                   12687: #endif
                   12688: 
                   12689:     return(total);
                   12690: }
                   12691: 
                   12692: static int
                   12693: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
                   12694:                              xmlXPathStepOpPtr op, xmlNodePtr * first);
                   12695: 
                   12696: /**
                   12697:  * xmlXPathCompOpEvalFirst:
                   12698:  * @ctxt:  the XPath parser context with the compiled expression
                   12699:  * @op:  an XPath compiled operation
                   12700:  * @first:  the first elem found so far
                   12701:  *
                   12702:  * Evaluate the Precompiled XPath operation searching only the first
                   12703:  * element in document order
                   12704:  *
                   12705:  * Returns the number of examined objects.
                   12706:  */
                   12707: static int
                   12708: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
                   12709:                         xmlXPathStepOpPtr op, xmlNodePtr * first)
                   12710: {
                   12711:     int total = 0, cur;
                   12712:     xmlXPathCompExprPtr comp;
                   12713:     xmlXPathObjectPtr arg1, arg2;
                   12714: 
                   12715:     CHECK_ERROR0;
                   12716:     comp = ctxt->comp;
                   12717:     switch (op->op) {
                   12718:         case XPATH_OP_END:
                   12719:             return (0);
                   12720:         case XPATH_OP_UNION:
                   12721:             total =
                   12722:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
                   12723:                                         first);
                   12724:            CHECK_ERROR0;
                   12725:             if ((ctxt->value != NULL)
                   12726:                 && (ctxt->value->type == XPATH_NODESET)
                   12727:                 && (ctxt->value->nodesetval != NULL)
                   12728:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
                   12729:                 /*
                   12730:                  * limit tree traversing to first node in the result
                   12731:                  */
                   12732:                /*
                   12733:                * OPTIMIZE TODO: This implicitely sorts
                   12734:                *  the result, even if not needed. E.g. if the argument
                   12735:                *  of the count() function, no sorting is needed.
                   12736:                * OPTIMIZE TODO: How do we know if the node-list wasn't
                   12737:                *  aready sorted?
                   12738:                */
                   12739:                if (ctxt->value->nodesetval->nodeNr > 1)
                   12740:                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12741:                 *first = ctxt->value->nodesetval->nodeTab[0];
                   12742:             }
                   12743:             cur =
                   12744:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
                   12745:                                         first);
                   12746:            CHECK_ERROR0;
                   12747:             CHECK_TYPE0(XPATH_NODESET);
                   12748:             arg2 = valuePop(ctxt);
                   12749: 
                   12750:             CHECK_TYPE0(XPATH_NODESET);
                   12751:             arg1 = valuePop(ctxt);
                   12752: 
                   12753:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                   12754:                                                     arg2->nodesetval);
                   12755:             valuePush(ctxt, arg1);
                   12756:            xmlXPathReleaseObject(ctxt->context, arg2);
                   12757:             /* optimizer */
                   12758:            if (total > cur)
                   12759:                xmlXPathCompSwap(op);
                   12760:             return (total + cur);
                   12761:         case XPATH_OP_ROOT:
                   12762:             xmlXPathRoot(ctxt);
                   12763:             return (0);
                   12764:         case XPATH_OP_NODE:
                   12765:             if (op->ch1 != -1)
                   12766:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12767:            CHECK_ERROR0;
                   12768:             if (op->ch2 != -1)
                   12769:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12770:            CHECK_ERROR0;
                   12771:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   12772:                ctxt->context->node));
                   12773:             return (total);
                   12774:         case XPATH_OP_RESET:
                   12775:             if (op->ch1 != -1)
                   12776:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12777:            CHECK_ERROR0;
                   12778:             if (op->ch2 != -1)
                   12779:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12780:            CHECK_ERROR0;
                   12781:             ctxt->context->node = NULL;
                   12782:             return (total);
                   12783:         case XPATH_OP_COLLECT:{
                   12784:                 if (op->ch1 == -1)
                   12785:                     return (total);
                   12786: 
                   12787:                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12788:                CHECK_ERROR0;
                   12789: 
                   12790:                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
                   12791:                 return (total);
                   12792:             }
                   12793:         case XPATH_OP_VALUE:
                   12794:             valuePush(ctxt,
                   12795:                       xmlXPathCacheObjectCopy(ctxt->context,
                   12796:                        (xmlXPathObjectPtr) op->value4));
                   12797:             return (0);
                   12798:         case XPATH_OP_SORT:
                   12799:             if (op->ch1 != -1)
                   12800:                 total +=
                   12801:                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
                   12802:                                             first);
                   12803:            CHECK_ERROR0;
                   12804:             if ((ctxt->value != NULL)
                   12805:                 && (ctxt->value->type == XPATH_NODESET)
                   12806:                 && (ctxt->value->nodesetval != NULL)
                   12807:                && (ctxt->value->nodesetval->nodeNr > 1))
                   12808:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12809:             return (total);
                   12810: #ifdef XP_OPTIMIZED_FILTER_FIRST
                   12811:        case XPATH_OP_FILTER:
                   12812:                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
                   12813:             return (total);
                   12814: #endif
                   12815:         default:
                   12816:             return (xmlXPathCompOpEval(ctxt, op));
                   12817:     }
                   12818: }
                   12819: 
                   12820: /**
                   12821:  * xmlXPathCompOpEvalLast:
                   12822:  * @ctxt:  the XPath parser context with the compiled expression
                   12823:  * @op:  an XPath compiled operation
                   12824:  * @last:  the last elem found so far
                   12825:  *
                   12826:  * Evaluate the Precompiled XPath operation searching only the last
                   12827:  * element in document order
                   12828:  *
                   12829:  * Returns the number of nodes traversed
                   12830:  */
                   12831: static int
                   12832: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
                   12833:                        xmlNodePtr * last)
                   12834: {
                   12835:     int total = 0, cur;
                   12836:     xmlXPathCompExprPtr comp;
                   12837:     xmlXPathObjectPtr arg1, arg2;
                   12838:     xmlNodePtr bak;
                   12839:     xmlDocPtr bakd;
                   12840:     int pp;
                   12841:     int cs;
                   12842: 
                   12843:     CHECK_ERROR0;
                   12844:     comp = ctxt->comp;
                   12845:     switch (op->op) {
                   12846:         case XPATH_OP_END:
                   12847:             return (0);
                   12848:         case XPATH_OP_UNION:
                   12849:            bakd = ctxt->context->doc;
                   12850:            bak = ctxt->context->node;
                   12851:            pp = ctxt->context->proximityPosition;
                   12852:            cs = ctxt->context->contextSize;
                   12853:             total =
                   12854:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
                   12855:            CHECK_ERROR0;
                   12856:             if ((ctxt->value != NULL)
                   12857:                 && (ctxt->value->type == XPATH_NODESET)
                   12858:                 && (ctxt->value->nodesetval != NULL)
                   12859:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
                   12860:                 /*
                   12861:                  * limit tree traversing to first node in the result
                   12862:                  */
                   12863:                if (ctxt->value->nodesetval->nodeNr > 1)
                   12864:                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12865:                 *last =
                   12866:                     ctxt->value->nodesetval->nodeTab[ctxt->value->
                   12867:                                                      nodesetval->nodeNr -
                   12868:                                                      1];
                   12869:             }
                   12870:            ctxt->context->doc = bakd;
                   12871:            ctxt->context->node = bak;
                   12872:            ctxt->context->proximityPosition = pp;
                   12873:            ctxt->context->contextSize = cs;
                   12874:             cur =
                   12875:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
                   12876:            CHECK_ERROR0;
                   12877:             if ((ctxt->value != NULL)
                   12878:                 && (ctxt->value->type == XPATH_NODESET)
                   12879:                 && (ctxt->value->nodesetval != NULL)
                   12880:                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
                   12881:             }
                   12882:             CHECK_TYPE0(XPATH_NODESET);
                   12883:             arg2 = valuePop(ctxt);
                   12884: 
                   12885:             CHECK_TYPE0(XPATH_NODESET);
                   12886:             arg1 = valuePop(ctxt);
                   12887: 
                   12888:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                   12889:                                                     arg2->nodesetval);
                   12890:             valuePush(ctxt, arg1);
                   12891:            xmlXPathReleaseObject(ctxt->context, arg2);
                   12892:             /* optimizer */
                   12893:            if (total > cur)
                   12894:                xmlXPathCompSwap(op);
                   12895:             return (total + cur);
                   12896:         case XPATH_OP_ROOT:
                   12897:             xmlXPathRoot(ctxt);
                   12898:             return (0);
                   12899:         case XPATH_OP_NODE:
                   12900:             if (op->ch1 != -1)
                   12901:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12902:            CHECK_ERROR0;
                   12903:             if (op->ch2 != -1)
                   12904:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12905:            CHECK_ERROR0;
                   12906:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   12907:                ctxt->context->node));
                   12908:             return (total);
                   12909:         case XPATH_OP_RESET:
                   12910:             if (op->ch1 != -1)
                   12911:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12912:            CHECK_ERROR0;
                   12913:             if (op->ch2 != -1)
                   12914:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   12915:            CHECK_ERROR0;
                   12916:             ctxt->context->node = NULL;
                   12917:             return (total);
                   12918:         case XPATH_OP_COLLECT:{
                   12919:                 if (op->ch1 == -1)
                   12920:                     return (0);
                   12921: 
                   12922:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   12923:                CHECK_ERROR0;
                   12924: 
                   12925:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
                   12926:                 return (total);
                   12927:             }
                   12928:         case XPATH_OP_VALUE:
                   12929:             valuePush(ctxt,
                   12930:                       xmlXPathCacheObjectCopy(ctxt->context,
                   12931:                        (xmlXPathObjectPtr) op->value4));
                   12932:             return (0);
                   12933:         case XPATH_OP_SORT:
                   12934:             if (op->ch1 != -1)
                   12935:                 total +=
                   12936:                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
                   12937:                                            last);
                   12938:            CHECK_ERROR0;
                   12939:             if ((ctxt->value != NULL)
                   12940:                 && (ctxt->value->type == XPATH_NODESET)
                   12941:                 && (ctxt->value->nodesetval != NULL)
                   12942:                && (ctxt->value->nodesetval->nodeNr > 1))
                   12943:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   12944:             return (total);
                   12945:         default:
                   12946:             return (xmlXPathCompOpEval(ctxt, op));
                   12947:     }
                   12948: }
                   12949: 
                   12950: #ifdef XP_OPTIMIZED_FILTER_FIRST
                   12951: static int
                   12952: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
                   12953:                              xmlXPathStepOpPtr op, xmlNodePtr * first)
                   12954: {
                   12955:     int total = 0;
                   12956:     xmlXPathCompExprPtr comp;
                   12957:     xmlXPathObjectPtr res;
                   12958:     xmlXPathObjectPtr obj;
                   12959:     xmlNodeSetPtr oldset;
                   12960:     xmlNodePtr oldnode;
                   12961:     xmlDocPtr oldDoc;
                   12962:     int i;
                   12963: 
                   12964:     CHECK_ERROR0;
                   12965:     comp = ctxt->comp;
                   12966:     /*
                   12967:     * Optimization for ()[last()] selection i.e. the last elem
                   12968:     */
                   12969:     if ((op->ch1 != -1) && (op->ch2 != -1) &&
                   12970:        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
                   12971:        (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
                   12972:        int f = comp->steps[op->ch2].ch1;
                   12973: 
                   12974:        if ((f != -1) &&
                   12975:            (comp->steps[f].op == XPATH_OP_FUNCTION) &&
                   12976:            (comp->steps[f].value5 == NULL) &&
                   12977:            (comp->steps[f].value == 0) &&
                   12978:            (comp->steps[f].value4 != NULL) &&
                   12979:            (xmlStrEqual
                   12980:            (comp->steps[f].value4, BAD_CAST "last"))) {
                   12981:            xmlNodePtr last = NULL;
                   12982: 
                   12983:            total +=
                   12984:                xmlXPathCompOpEvalLast(ctxt,
                   12985:                    &comp->steps[op->ch1],
                   12986:                    &last);
                   12987:            CHECK_ERROR0;
                   12988:            /*
                   12989:            * The nodeset should be in document order,
                   12990:            * Keep only the last value
                   12991:            */
                   12992:            if ((ctxt->value != NULL) &&
                   12993:                (ctxt->value->type == XPATH_NODESET) &&
                   12994:                (ctxt->value->nodesetval != NULL) &&
                   12995:                (ctxt->value->nodesetval->nodeTab != NULL) &&
                   12996:                (ctxt->value->nodesetval->nodeNr > 1)) {
                   12997:                ctxt->value->nodesetval->nodeTab[0] =
                   12998:                    ctxt->value->nodesetval->nodeTab[ctxt->
                   12999:                    value->
                   13000:                    nodesetval->
                   13001:                    nodeNr -
                   13002:                    1];
                   13003:                ctxt->value->nodesetval->nodeNr = 1;
                   13004:                *first = *(ctxt->value->nodesetval->nodeTab);
                   13005:            }
                   13006:            return (total);
                   13007:        }
                   13008:     }
                   13009: 
                   13010:     if (op->ch1 != -1)
                   13011:        total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13012:     CHECK_ERROR0;
                   13013:     if (op->ch2 == -1)
                   13014:        return (total);
                   13015:     if (ctxt->value == NULL)
                   13016:        return (total);
                   13017: 
                   13018: #ifdef LIBXML_XPTR_ENABLED
                   13019:     oldnode = ctxt->context->node;
                   13020:     /*
                   13021:     * Hum are we filtering the result of an XPointer expression
                   13022:     */
                   13023:     if (ctxt->value->type == XPATH_LOCATIONSET) {
                   13024:        xmlXPathObjectPtr tmp = NULL;
                   13025:        xmlLocationSetPtr newlocset = NULL;
                   13026:        xmlLocationSetPtr oldlocset;
                   13027: 
                   13028:        /*
                   13029:        * Extract the old locset, and then evaluate the result of the
                   13030:        * expression for all the element in the locset. use it to grow
                   13031:        * up a new locset.
                   13032:        */
                   13033:        CHECK_TYPE0(XPATH_LOCATIONSET);
                   13034:        obj = valuePop(ctxt);
                   13035:        oldlocset = obj->user;
                   13036:        ctxt->context->node = NULL;
                   13037: 
                   13038:        if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
                   13039:            ctxt->context->contextSize = 0;
                   13040:            ctxt->context->proximityPosition = 0;
                   13041:            if (op->ch2 != -1)
                   13042:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13043:            res = valuePop(ctxt);
                   13044:            if (res != NULL) {
                   13045:                xmlXPathReleaseObject(ctxt->context, res);
                   13046:            }
                   13047:            valuePush(ctxt, obj);
                   13048:            CHECK_ERROR0;
                   13049:            return (total);
                   13050:        }
                   13051:        newlocset = xmlXPtrLocationSetCreate(NULL);
                   13052: 
                   13053:        for (i = 0; i < oldlocset->locNr; i++) {
                   13054:            /*
                   13055:            * Run the evaluation with a node list made of a
                   13056:            * single item in the nodelocset.
                   13057:            */
                   13058:            ctxt->context->node = oldlocset->locTab[i]->user;
                   13059:            ctxt->context->contextSize = oldlocset->locNr;
                   13060:            ctxt->context->proximityPosition = i + 1;
                   13061:            if (tmp == NULL) {
                   13062:                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13063:                    ctxt->context->node);
                   13064:            } else {
1.1.1.3 ! misho    13065:                if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
        !          13066:                                             ctxt->context->node) < 0) {
        !          13067:                    ctxt->error = XPATH_MEMORY_ERROR;
        !          13068:                }
1.1       misho    13069:            }
                   13070:            valuePush(ctxt, tmp);
                   13071:            if (op->ch2 != -1)
                   13072:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13073:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13074:                xmlXPathFreeObject(obj);
                   13075:                return(0);
                   13076:            }
                   13077:            /*
                   13078:            * The result of the evaluation need to be tested to
                   13079:            * decided whether the filter succeeded or not
                   13080:            */
                   13081:            res = valuePop(ctxt);
                   13082:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   13083:                xmlXPtrLocationSetAdd(newlocset,
                   13084:                    xmlXPathCacheObjectCopy(ctxt->context,
                   13085:                        oldlocset->locTab[i]));
                   13086:            }
                   13087:            /*
                   13088:            * Cleanup
                   13089:            */
                   13090:            if (res != NULL) {
                   13091:                xmlXPathReleaseObject(ctxt->context, res);
                   13092:            }
                   13093:            if (ctxt->value == tmp) {
                   13094:                valuePop(ctxt);
                   13095:                xmlXPathNodeSetClear(tmp->nodesetval, 1);
                   13096:                /*
                   13097:                * REVISIT TODO: Don't create a temporary nodeset
                   13098:                * for everly iteration.
                   13099:                */
                   13100:                /* OLD: xmlXPathFreeObject(res); */
                   13101:            } else
                   13102:                tmp = NULL;
                   13103:            ctxt->context->node = NULL;
                   13104:            /*
                   13105:            * Only put the first node in the result, then leave.
                   13106:            */
                   13107:            if (newlocset->locNr > 0) {
                   13108:                *first = (xmlNodePtr) oldlocset->locTab[i]->user;
                   13109:                break;
                   13110:            }
                   13111:        }
                   13112:        if (tmp != NULL) {
                   13113:            xmlXPathReleaseObject(ctxt->context, tmp);
                   13114:        }
                   13115:        /*
                   13116:        * The result is used as the new evaluation locset.
                   13117:        */
                   13118:        xmlXPathReleaseObject(ctxt->context, obj);
                   13119:        ctxt->context->node = NULL;
                   13120:        ctxt->context->contextSize = -1;
                   13121:        ctxt->context->proximityPosition = -1;
                   13122:        valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
                   13123:        ctxt->context->node = oldnode;
                   13124:        return (total);
                   13125:     }
                   13126: #endif /* LIBXML_XPTR_ENABLED */
                   13127: 
                   13128:     /*
                   13129:     * Extract the old set, and then evaluate the result of the
                   13130:     * expression for all the element in the set. use it to grow
                   13131:     * up a new set.
                   13132:     */
                   13133:     CHECK_TYPE0(XPATH_NODESET);
                   13134:     obj = valuePop(ctxt);
                   13135:     oldset = obj->nodesetval;
                   13136: 
                   13137:     oldnode = ctxt->context->node;
                   13138:     oldDoc = ctxt->context->doc;
                   13139:     ctxt->context->node = NULL;
                   13140: 
                   13141:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
                   13142:        ctxt->context->contextSize = 0;
                   13143:        ctxt->context->proximityPosition = 0;
                   13144:        /* QUESTION TODO: Why was this code commented out?
                   13145:            if (op->ch2 != -1)
                   13146:                total +=
                   13147:                    xmlXPathCompOpEval(ctxt,
                   13148:                        &comp->steps[op->ch2]);
                   13149:            CHECK_ERROR0;
                   13150:            res = valuePop(ctxt);
                   13151:            if (res != NULL)
                   13152:                xmlXPathFreeObject(res);
                   13153:        */
                   13154:        valuePush(ctxt, obj);
                   13155:        ctxt->context->node = oldnode;
                   13156:        CHECK_ERROR0;
                   13157:     } else {
                   13158:        xmlNodeSetPtr newset;
                   13159:        xmlXPathObjectPtr tmp = NULL;
                   13160:        /*
                   13161:        * Initialize the new set.
                   13162:        * Also set the xpath document in case things like
                   13163:        * key() evaluation are attempted on the predicate
                   13164:        */
                   13165:        newset = xmlXPathNodeSetCreate(NULL);
                   13166:         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
                   13167: 
                   13168:        for (i = 0; i < oldset->nodeNr; i++) {
                   13169:            /*
                   13170:            * Run the evaluation with a node list made of
                   13171:            * a single item in the nodeset.
                   13172:            */
                   13173:            ctxt->context->node = oldset->nodeTab[i];
                   13174:            if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
                   13175:                (oldset->nodeTab[i]->doc != NULL))
                   13176:                ctxt->context->doc = oldset->nodeTab[i]->doc;
                   13177:            if (tmp == NULL) {
                   13178:                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13179:                    ctxt->context->node);
                   13180:            } else {
1.1.1.3 ! misho    13181:                if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
        !          13182:                                             ctxt->context->node) < 0) {
        !          13183:                    ctxt->error = XPATH_MEMORY_ERROR;
        !          13184:                }
1.1       misho    13185:            }
                   13186:            valuePush(ctxt, tmp);
                   13187:            ctxt->context->contextSize = oldset->nodeNr;
                   13188:            ctxt->context->proximityPosition = i + 1;
                   13189:            if (op->ch2 != -1)
                   13190:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13191:            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13192:                xmlXPathFreeNodeSet(newset);
                   13193:                xmlXPathFreeObject(obj);
                   13194:                return(0);
                   13195:            }
                   13196:            /*
                   13197:            * The result of the evaluation needs to be tested to
                   13198:            * decide whether the filter succeeded or not
                   13199:            */
                   13200:            res = valuePop(ctxt);
                   13201:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
1.1.1.3 ! misho    13202:                if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
        !          13203:                    ctxt->error = XPATH_MEMORY_ERROR;
1.1       misho    13204:            }
                   13205:            /*
                   13206:            * Cleanup
                   13207:            */
                   13208:            if (res != NULL) {
                   13209:                xmlXPathReleaseObject(ctxt->context, res);
                   13210:            }
                   13211:            if (ctxt->value == tmp) {
                   13212:                valuePop(ctxt);
                   13213:                /*
                   13214:                * Don't free the temporary nodeset
                   13215:                * in order to avoid massive recreation inside this
                   13216:                * loop.
                   13217:                */
                   13218:                xmlXPathNodeSetClear(tmp->nodesetval, 1);
                   13219:            } else
                   13220:                tmp = NULL;
                   13221:            ctxt->context->node = NULL;
                   13222:            /*
                   13223:            * Only put the first node in the result, then leave.
                   13224:            */
                   13225:            if (newset->nodeNr > 0) {
                   13226:                *first = *(newset->nodeTab);
                   13227:                break;
                   13228:            }
                   13229:        }
                   13230:        if (tmp != NULL) {
                   13231:            xmlXPathReleaseObject(ctxt->context, tmp);
                   13232:        }
                   13233:        /*
                   13234:        * The result is used as the new evaluation set.
                   13235:        */
                   13236:        xmlXPathReleaseObject(ctxt->context, obj);
                   13237:        ctxt->context->node = NULL;
                   13238:        ctxt->context->contextSize = -1;
                   13239:        ctxt->context->proximityPosition = -1;
                   13240:        /* may want to move this past the '}' later */
                   13241:        ctxt->context->doc = oldDoc;
                   13242:        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
                   13243:     }
                   13244:     ctxt->context->node = oldnode;
                   13245:     return(total);
                   13246: }
                   13247: #endif /* XP_OPTIMIZED_FILTER_FIRST */
                   13248: 
                   13249: /**
                   13250:  * xmlXPathCompOpEval:
                   13251:  * @ctxt:  the XPath parser context with the compiled expression
                   13252:  * @op:  an XPath compiled operation
                   13253:  *
                   13254:  * Evaluate the Precompiled XPath operation
                   13255:  * Returns the number of nodes traversed
                   13256:  */
                   13257: static int
                   13258: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
                   13259: {
                   13260:     int total = 0;
                   13261:     int equal, ret;
                   13262:     xmlXPathCompExprPtr comp;
                   13263:     xmlXPathObjectPtr arg1, arg2;
                   13264:     xmlNodePtr bak;
                   13265:     xmlDocPtr bakd;
                   13266:     int pp;
                   13267:     int cs;
                   13268: 
                   13269:     CHECK_ERROR0;
                   13270:     comp = ctxt->comp;
                   13271:     switch (op->op) {
                   13272:         case XPATH_OP_END:
                   13273:             return (0);
                   13274:         case XPATH_OP_AND:
                   13275:            bakd = ctxt->context->doc;
                   13276:            bak = ctxt->context->node;
                   13277:            pp = ctxt->context->proximityPosition;
                   13278:            cs = ctxt->context->contextSize;
                   13279:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13280:            CHECK_ERROR0;
                   13281:             xmlXPathBooleanFunction(ctxt, 1);
                   13282:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
                   13283:                 return (total);
                   13284:             arg2 = valuePop(ctxt);
                   13285:            ctxt->context->doc = bakd;
                   13286:            ctxt->context->node = bak;
                   13287:            ctxt->context->proximityPosition = pp;
                   13288:            ctxt->context->contextSize = cs;
                   13289:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13290:            if (ctxt->error) {
                   13291:                xmlXPathFreeObject(arg2);
                   13292:                return(0);
                   13293:            }
                   13294:             xmlXPathBooleanFunction(ctxt, 1);
                   13295:             arg1 = valuePop(ctxt);
                   13296:             arg1->boolval &= arg2->boolval;
                   13297:             valuePush(ctxt, arg1);
                   13298:            xmlXPathReleaseObject(ctxt->context, arg2);
                   13299:             return (total);
                   13300:         case XPATH_OP_OR:
                   13301:            bakd = ctxt->context->doc;
                   13302:            bak = ctxt->context->node;
                   13303:            pp = ctxt->context->proximityPosition;
                   13304:            cs = ctxt->context->contextSize;
                   13305:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13306:            CHECK_ERROR0;
                   13307:             xmlXPathBooleanFunction(ctxt, 1);
                   13308:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
                   13309:                 return (total);
                   13310:             arg2 = valuePop(ctxt);
                   13311:            ctxt->context->doc = bakd;
                   13312:            ctxt->context->node = bak;
                   13313:            ctxt->context->proximityPosition = pp;
                   13314:            ctxt->context->contextSize = cs;
                   13315:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13316:            if (ctxt->error) {
                   13317:                xmlXPathFreeObject(arg2);
                   13318:                return(0);
                   13319:            }
                   13320:             xmlXPathBooleanFunction(ctxt, 1);
                   13321:             arg1 = valuePop(ctxt);
                   13322:             arg1->boolval |= arg2->boolval;
                   13323:             valuePush(ctxt, arg1);
                   13324:            xmlXPathReleaseObject(ctxt->context, arg2);
                   13325:             return (total);
                   13326:         case XPATH_OP_EQUAL:
                   13327:            bakd = ctxt->context->doc;
                   13328:            bak = ctxt->context->node;
                   13329:            pp = ctxt->context->proximityPosition;
                   13330:            cs = ctxt->context->contextSize;
                   13331:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13332:            CHECK_ERROR0;
                   13333:            ctxt->context->doc = bakd;
                   13334:            ctxt->context->node = bak;
                   13335:            ctxt->context->proximityPosition = pp;
                   13336:            ctxt->context->contextSize = cs;
                   13337:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13338:            CHECK_ERROR0;
                   13339:            if (op->value)
                   13340:                equal = xmlXPathEqualValues(ctxt);
                   13341:            else
                   13342:                equal = xmlXPathNotEqualValues(ctxt);
                   13343:            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
                   13344:             return (total);
                   13345:         case XPATH_OP_CMP:
                   13346:            bakd = ctxt->context->doc;
                   13347:            bak = ctxt->context->node;
                   13348:            pp = ctxt->context->proximityPosition;
                   13349:            cs = ctxt->context->contextSize;
                   13350:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13351:            CHECK_ERROR0;
                   13352:            ctxt->context->doc = bakd;
                   13353:            ctxt->context->node = bak;
                   13354:            ctxt->context->proximityPosition = pp;
                   13355:            ctxt->context->contextSize = cs;
                   13356:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13357:            CHECK_ERROR0;
                   13358:             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
                   13359:            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
                   13360:             return (total);
                   13361:         case XPATH_OP_PLUS:
                   13362:            bakd = ctxt->context->doc;
                   13363:            bak = ctxt->context->node;
                   13364:            pp = ctxt->context->proximityPosition;
                   13365:            cs = ctxt->context->contextSize;
                   13366:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13367:            CHECK_ERROR0;
                   13368:             if (op->ch2 != -1) {
                   13369:                ctxt->context->doc = bakd;
                   13370:                ctxt->context->node = bak;
                   13371:                ctxt->context->proximityPosition = pp;
                   13372:                ctxt->context->contextSize = cs;
                   13373:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13374:            }
                   13375:            CHECK_ERROR0;
                   13376:             if (op->value == 0)
                   13377:                 xmlXPathSubValues(ctxt);
                   13378:             else if (op->value == 1)
                   13379:                 xmlXPathAddValues(ctxt);
                   13380:             else if (op->value == 2)
                   13381:                 xmlXPathValueFlipSign(ctxt);
                   13382:             else if (op->value == 3) {
                   13383:                 CAST_TO_NUMBER;
                   13384:                 CHECK_TYPE0(XPATH_NUMBER);
                   13385:             }
                   13386:             return (total);
                   13387:         case XPATH_OP_MULT:
                   13388:            bakd = ctxt->context->doc;
                   13389:            bak = ctxt->context->node;
                   13390:            pp = ctxt->context->proximityPosition;
                   13391:            cs = ctxt->context->contextSize;
                   13392:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13393:            CHECK_ERROR0;
                   13394:            ctxt->context->doc = bakd;
                   13395:            ctxt->context->node = bak;
                   13396:            ctxt->context->proximityPosition = pp;
                   13397:            ctxt->context->contextSize = cs;
                   13398:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13399:            CHECK_ERROR0;
                   13400:             if (op->value == 0)
                   13401:                 xmlXPathMultValues(ctxt);
                   13402:             else if (op->value == 1)
                   13403:                 xmlXPathDivValues(ctxt);
                   13404:             else if (op->value == 2)
                   13405:                 xmlXPathModValues(ctxt);
                   13406:             return (total);
                   13407:         case XPATH_OP_UNION:
                   13408:            bakd = ctxt->context->doc;
                   13409:            bak = ctxt->context->node;
                   13410:            pp = ctxt->context->proximityPosition;
                   13411:            cs = ctxt->context->contextSize;
                   13412:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13413:            CHECK_ERROR0;
                   13414:            ctxt->context->doc = bakd;
                   13415:            ctxt->context->node = bak;
                   13416:            ctxt->context->proximityPosition = pp;
                   13417:            ctxt->context->contextSize = cs;
                   13418:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13419:            CHECK_ERROR0;
                   13420:             CHECK_TYPE0(XPATH_NODESET);
                   13421:             arg2 = valuePop(ctxt);
                   13422: 
                   13423:             CHECK_TYPE0(XPATH_NODESET);
                   13424:             arg1 = valuePop(ctxt);
                   13425: 
                   13426:            if ((arg1->nodesetval == NULL) ||
                   13427:                ((arg2->nodesetval != NULL) &&
                   13428:                 (arg2->nodesetval->nodeNr != 0)))
                   13429:            {
                   13430:                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                   13431:                                                        arg2->nodesetval);
                   13432:            }
                   13433: 
                   13434:             valuePush(ctxt, arg1);
                   13435:            xmlXPathReleaseObject(ctxt->context, arg2);
                   13436:             return (total);
                   13437:         case XPATH_OP_ROOT:
                   13438:             xmlXPathRoot(ctxt);
                   13439:             return (total);
                   13440:         case XPATH_OP_NODE:
                   13441:             if (op->ch1 != -1)
                   13442:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13443:            CHECK_ERROR0;
                   13444:             if (op->ch2 != -1)
                   13445:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13446:            CHECK_ERROR0;
                   13447:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
                   13448:                ctxt->context->node));
                   13449:             return (total);
                   13450:         case XPATH_OP_RESET:
                   13451:             if (op->ch1 != -1)
                   13452:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13453:            CHECK_ERROR0;
                   13454:             if (op->ch2 != -1)
                   13455:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13456:            CHECK_ERROR0;
                   13457:             ctxt->context->node = NULL;
                   13458:             return (total);
                   13459:         case XPATH_OP_COLLECT:{
                   13460:                 if (op->ch1 == -1)
                   13461:                     return (total);
                   13462: 
                   13463:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13464:                CHECK_ERROR0;
                   13465: 
                   13466:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
                   13467:                 return (total);
                   13468:             }
                   13469:         case XPATH_OP_VALUE:
                   13470:             valuePush(ctxt,
                   13471:                       xmlXPathCacheObjectCopy(ctxt->context,
                   13472:                        (xmlXPathObjectPtr) op->value4));
                   13473:             return (total);
                   13474:         case XPATH_OP_VARIABLE:{
                   13475:                xmlXPathObjectPtr val;
                   13476: 
                   13477:                 if (op->ch1 != -1)
                   13478:                     total +=
                   13479:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13480:                 if (op->value5 == NULL) {
                   13481:                    val = xmlXPathVariableLookup(ctxt->context, op->value4);
                   13482:                    if (val == NULL) {
                   13483:                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
                   13484:                        return(0);
                   13485:                    }
                   13486:                     valuePush(ctxt, val);
                   13487:                } else {
                   13488:                     const xmlChar *URI;
                   13489: 
                   13490:                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
                   13491:                     if (URI == NULL) {
                   13492:                         xmlGenericError(xmlGenericErrorContext,
                   13493:             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
                   13494:                                     (char *) op->value4, (char *)op->value5);
1.1.1.2   misho    13495:                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
1.1       misho    13496:                         return (total);
                   13497:                     }
                   13498:                    val = xmlXPathVariableLookupNS(ctxt->context,
                   13499:                                                        op->value4, URI);
                   13500:                    if (val == NULL) {
                   13501:                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
                   13502:                        return(0);
                   13503:                    }
                   13504:                     valuePush(ctxt, val);
                   13505:                 }
                   13506:                 return (total);
                   13507:             }
                   13508:         case XPATH_OP_FUNCTION:{
                   13509:                 xmlXPathFunction func;
                   13510:                 const xmlChar *oldFunc, *oldFuncURI;
                   13511:                int i;
1.1.1.2   misho    13512:                 int frame;
1.1       misho    13513: 
1.1.1.2   misho    13514:                 frame = xmlXPathSetFrame(ctxt);
1.1       misho    13515:                 if (op->ch1 != -1)
                   13516:                     total +=
                   13517:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13518:                if (ctxt->valueNr < op->value) {
                   13519:                    xmlGenericError(xmlGenericErrorContext,
                   13520:                            "xmlXPathCompOpEval: parameter error\n");
                   13521:                    ctxt->error = XPATH_INVALID_OPERAND;
1.1.1.2   misho    13522:                     xmlXPathPopFrame(ctxt, frame);
1.1       misho    13523:                    return (total);
                   13524:                }
1.1.1.2   misho    13525:                for (i = 0; i < op->value; i++) {
1.1       misho    13526:                    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
                   13527:                        xmlGenericError(xmlGenericErrorContext,
                   13528:                                "xmlXPathCompOpEval: parameter error\n");
                   13529:                        ctxt->error = XPATH_INVALID_OPERAND;
1.1.1.2   misho    13530:                         xmlXPathPopFrame(ctxt, frame);
1.1       misho    13531:                        return (total);
                   13532:                    }
1.1.1.2   misho    13533:                 }
1.1       misho    13534:                 if (op->cache != NULL)
                   13535:                     XML_CAST_FPTR(func) = op->cache;
                   13536:                 else {
                   13537:                     const xmlChar *URI = NULL;
                   13538: 
                   13539:                     if (op->value5 == NULL)
                   13540:                         func =
                   13541:                             xmlXPathFunctionLookup(ctxt->context,
                   13542:                                                    op->value4);
                   13543:                     else {
                   13544:                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
                   13545:                         if (URI == NULL) {
                   13546:                             xmlGenericError(xmlGenericErrorContext,
                   13547:             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
                   13548:                                     (char *)op->value4, (char *)op->value5);
1.1.1.2   misho    13549:                             xmlXPathPopFrame(ctxt, frame);
                   13550:                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
1.1       misho    13551:                             return (total);
                   13552:                         }
                   13553:                         func = xmlXPathFunctionLookupNS(ctxt->context,
                   13554:                                                         op->value4, URI);
                   13555:                     }
                   13556:                     if (func == NULL) {
                   13557:                         xmlGenericError(xmlGenericErrorContext,
                   13558:                                 "xmlXPathCompOpEval: function %s not found\n",
                   13559:                                         (char *)op->value4);
                   13560:                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
                   13561:                     }
                   13562:                     op->cache = XML_CAST_FPTR(func);
                   13563:                     op->cacheURI = (void *) URI;
                   13564:                 }
                   13565:                 oldFunc = ctxt->context->function;
                   13566:                 oldFuncURI = ctxt->context->functionURI;
                   13567:                 ctxt->context->function = op->value4;
                   13568:                 ctxt->context->functionURI = op->cacheURI;
                   13569:                 func(ctxt, op->value);
                   13570:                 ctxt->context->function = oldFunc;
                   13571:                 ctxt->context->functionURI = oldFuncURI;
1.1.1.2   misho    13572:                 xmlXPathPopFrame(ctxt, frame);
1.1       misho    13573:                 return (total);
                   13574:             }
                   13575:         case XPATH_OP_ARG:
                   13576:            bakd = ctxt->context->doc;
                   13577:            bak = ctxt->context->node;
                   13578:            pp = ctxt->context->proximityPosition;
                   13579:            cs = ctxt->context->contextSize;
                   13580:             if (op->ch1 != -1)
                   13581:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13582:            ctxt->context->contextSize = cs;
                   13583:            ctxt->context->proximityPosition = pp;
                   13584:            ctxt->context->node = bak;
                   13585:            ctxt->context->doc = bakd;
                   13586:            CHECK_ERROR0;
                   13587:             if (op->ch2 != -1) {
                   13588:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
                   13589:                ctxt->context->doc = bakd;
                   13590:                ctxt->context->node = bak;
                   13591:                CHECK_ERROR0;
                   13592:            }
                   13593:             return (total);
                   13594:         case XPATH_OP_PREDICATE:
                   13595:         case XPATH_OP_FILTER:{
                   13596:                 xmlXPathObjectPtr res;
                   13597:                 xmlXPathObjectPtr obj, tmp;
                   13598:                 xmlNodeSetPtr newset = NULL;
                   13599:                 xmlNodeSetPtr oldset;
                   13600:                 xmlNodePtr oldnode;
                   13601:                xmlDocPtr oldDoc;
                   13602:                 int i;
                   13603: 
                   13604:                 /*
                   13605:                  * Optimization for ()[1] selection i.e. the first elem
                   13606:                  */
                   13607:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
                   13608: #ifdef XP_OPTIMIZED_FILTER_FIRST
                   13609:                    /*
                   13610:                    * FILTER TODO: Can we assume that the inner processing
                   13611:                    *  will result in an ordered list if we have an
                   13612:                    *  XPATH_OP_FILTER?
                   13613:                    *  What about an additional field or flag on
                   13614:                    *  xmlXPathObject like @sorted ? This way we wouln'd need
                   13615:                    *  to assume anything, so it would be more robust and
                   13616:                    *  easier to optimize.
                   13617:                    */
                   13618:                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
                   13619:                     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
                   13620: #else
                   13621:                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
                   13622: #endif
                   13623:                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
                   13624:                     xmlXPathObjectPtr val;
                   13625: 
                   13626:                     val = comp->steps[op->ch2].value4;
                   13627:                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
                   13628:                         (val->floatval == 1.0)) {
                   13629:                         xmlNodePtr first = NULL;
                   13630: 
                   13631:                         total +=
                   13632:                             xmlXPathCompOpEvalFirst(ctxt,
                   13633:                                                     &comp->steps[op->ch1],
                   13634:                                                     &first);
                   13635:                        CHECK_ERROR0;
                   13636:                         /*
                   13637:                          * The nodeset should be in document order,
                   13638:                          * Keep only the first value
                   13639:                          */
                   13640:                         if ((ctxt->value != NULL) &&
                   13641:                             (ctxt->value->type == XPATH_NODESET) &&
                   13642:                             (ctxt->value->nodesetval != NULL) &&
                   13643:                             (ctxt->value->nodesetval->nodeNr > 1))
                   13644:                             ctxt->value->nodesetval->nodeNr = 1;
                   13645:                         return (total);
                   13646:                     }
                   13647:                 }
                   13648:                 /*
                   13649:                  * Optimization for ()[last()] selection i.e. the last elem
                   13650:                  */
                   13651:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
                   13652:                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
                   13653:                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
                   13654:                     int f = comp->steps[op->ch2].ch1;
                   13655: 
                   13656:                     if ((f != -1) &&
                   13657:                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
                   13658:                         (comp->steps[f].value5 == NULL) &&
                   13659:                         (comp->steps[f].value == 0) &&
                   13660:                         (comp->steps[f].value4 != NULL) &&
                   13661:                         (xmlStrEqual
                   13662:                          (comp->steps[f].value4, BAD_CAST "last"))) {
                   13663:                         xmlNodePtr last = NULL;
                   13664: 
                   13665:                         total +=
                   13666:                             xmlXPathCompOpEvalLast(ctxt,
                   13667:                                                    &comp->steps[op->ch1],
                   13668:                                                    &last);
                   13669:                        CHECK_ERROR0;
                   13670:                         /*
                   13671:                          * The nodeset should be in document order,
                   13672:                          * Keep only the last value
                   13673:                          */
                   13674:                         if ((ctxt->value != NULL) &&
                   13675:                             (ctxt->value->type == XPATH_NODESET) &&
                   13676:                             (ctxt->value->nodesetval != NULL) &&
                   13677:                             (ctxt->value->nodesetval->nodeTab != NULL) &&
                   13678:                             (ctxt->value->nodesetval->nodeNr > 1)) {
                   13679:                             ctxt->value->nodesetval->nodeTab[0] =
                   13680:                                 ctxt->value->nodesetval->nodeTab[ctxt->
                   13681:                                                                  value->
                   13682:                                                                  nodesetval->
                   13683:                                                                  nodeNr -
                   13684:                                                                  1];
                   13685:                             ctxt->value->nodesetval->nodeNr = 1;
                   13686:                         }
                   13687:                         return (total);
                   13688:                     }
                   13689:                 }
                   13690:                /*
                   13691:                * Process inner predicates first.
                   13692:                * Example "index[parent::book][1]":
                   13693:                * ...
                   13694:                *   PREDICATE   <-- we are here "[1]"
                   13695:                *     PREDICATE <-- process "[parent::book]" first
                   13696:                *       SORT
                   13697:                *         COLLECT  'parent' 'name' 'node' book
                   13698:                *           NODE
                   13699:                *     ELEM Object is a number : 1
                   13700:                */
                   13701:                 if (op->ch1 != -1)
                   13702:                     total +=
                   13703:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13704:                CHECK_ERROR0;
                   13705:                 if (op->ch2 == -1)
                   13706:                     return (total);
                   13707:                 if (ctxt->value == NULL)
                   13708:                     return (total);
                   13709: 
                   13710:                 oldnode = ctxt->context->node;
                   13711: 
                   13712: #ifdef LIBXML_XPTR_ENABLED
                   13713:                 /*
                   13714:                  * Hum are we filtering the result of an XPointer expression
                   13715:                  */
                   13716:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
                   13717:                     xmlLocationSetPtr newlocset = NULL;
                   13718:                     xmlLocationSetPtr oldlocset;
                   13719: 
                   13720:                     /*
                   13721:                      * Extract the old locset, and then evaluate the result of the
                   13722:                      * expression for all the element in the locset. use it to grow
                   13723:                      * up a new locset.
                   13724:                      */
                   13725:                     CHECK_TYPE0(XPATH_LOCATIONSET);
                   13726:                     obj = valuePop(ctxt);
                   13727:                     oldlocset = obj->user;
                   13728:                     ctxt->context->node = NULL;
                   13729: 
                   13730:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
                   13731:                         ctxt->context->contextSize = 0;
                   13732:                         ctxt->context->proximityPosition = 0;
                   13733:                         if (op->ch2 != -1)
                   13734:                             total +=
                   13735:                                 xmlXPathCompOpEval(ctxt,
                   13736:                                                    &comp->steps[op->ch2]);
                   13737:                         res = valuePop(ctxt);
                   13738:                         if (res != NULL) {
                   13739:                            xmlXPathReleaseObject(ctxt->context, res);
                   13740:                        }
                   13741:                         valuePush(ctxt, obj);
                   13742:                         CHECK_ERROR0;
                   13743:                         return (total);
                   13744:                     }
                   13745:                     newlocset = xmlXPtrLocationSetCreate(NULL);
                   13746: 
                   13747:                     for (i = 0; i < oldlocset->locNr; i++) {
                   13748:                         /*
                   13749:                          * Run the evaluation with a node list made of a
                   13750:                          * single item in the nodelocset.
                   13751:                          */
                   13752:                         ctxt->context->node = oldlocset->locTab[i]->user;
                   13753:                         ctxt->context->contextSize = oldlocset->locNr;
                   13754:                         ctxt->context->proximityPosition = i + 1;
                   13755:                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13756:                            ctxt->context->node);
                   13757:                         valuePush(ctxt, tmp);
                   13758: 
                   13759:                         if (op->ch2 != -1)
                   13760:                             total +=
                   13761:                                 xmlXPathCompOpEval(ctxt,
                   13762:                                                    &comp->steps[op->ch2]);
                   13763:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13764:                            xmlXPathFreeObject(obj);
                   13765:                            return(0);
                   13766:                        }
                   13767: 
                   13768:                         /*
                   13769:                          * The result of the evaluation need to be tested to
                   13770:                          * decided whether the filter succeeded or not
                   13771:                          */
                   13772:                         res = valuePop(ctxt);
                   13773:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   13774:                             xmlXPtrLocationSetAdd(newlocset,
                   13775:                                                   xmlXPathObjectCopy
                   13776:                                                   (oldlocset->locTab[i]));
                   13777:                         }
                   13778: 
                   13779:                         /*
                   13780:                          * Cleanup
                   13781:                          */
                   13782:                         if (res != NULL) {
                   13783:                            xmlXPathReleaseObject(ctxt->context, res);
                   13784:                        }
                   13785:                         if (ctxt->value == tmp) {
                   13786:                             res = valuePop(ctxt);
                   13787:                            xmlXPathReleaseObject(ctxt->context, res);
                   13788:                         }
                   13789: 
                   13790:                         ctxt->context->node = NULL;
                   13791:                     }
                   13792: 
                   13793:                     /*
                   13794:                      * The result is used as the new evaluation locset.
                   13795:                      */
                   13796:                    xmlXPathReleaseObject(ctxt->context, obj);
                   13797:                     ctxt->context->node = NULL;
                   13798:                     ctxt->context->contextSize = -1;
                   13799:                     ctxt->context->proximityPosition = -1;
                   13800:                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
                   13801:                     ctxt->context->node = oldnode;
                   13802:                     return (total);
                   13803:                 }
                   13804: #endif /* LIBXML_XPTR_ENABLED */
                   13805: 
                   13806:                 /*
                   13807:                  * Extract the old set, and then evaluate the result of the
                   13808:                  * expression for all the element in the set. use it to grow
                   13809:                  * up a new set.
                   13810:                  */
                   13811:                 CHECK_TYPE0(XPATH_NODESET);
                   13812:                 obj = valuePop(ctxt);
                   13813:                 oldset = obj->nodesetval;
                   13814: 
                   13815:                 oldnode = ctxt->context->node;
                   13816:                oldDoc = ctxt->context->doc;
                   13817:                 ctxt->context->node = NULL;
                   13818: 
                   13819:                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
                   13820:                     ctxt->context->contextSize = 0;
                   13821:                     ctxt->context->proximityPosition = 0;
                   13822: /*
                   13823:                     if (op->ch2 != -1)
                   13824:                         total +=
                   13825:                             xmlXPathCompOpEval(ctxt,
                   13826:                                                &comp->steps[op->ch2]);
                   13827:                    CHECK_ERROR0;
                   13828:                     res = valuePop(ctxt);
                   13829:                     if (res != NULL)
                   13830:                         xmlXPathFreeObject(res);
                   13831: */
                   13832:                     valuePush(ctxt, obj);
                   13833:                     ctxt->context->node = oldnode;
                   13834:                     CHECK_ERROR0;
                   13835:                 } else {
                   13836:                    tmp = NULL;
                   13837:                     /*
                   13838:                      * Initialize the new set.
                   13839:                     * Also set the xpath document in case things like
                   13840:                     * key() evaluation are attempted on the predicate
                   13841:                      */
                   13842:                     newset = xmlXPathNodeSetCreate(NULL);
                   13843:                    /*
                   13844:                    * SPEC XPath 1.0:
                   13845:                    *  "For each node in the node-set to be filtered, the
                   13846:                    *  PredicateExpr is evaluated with that node as the
                   13847:                    *  context node, with the number of nodes in the
                   13848:                    *  node-set as the context size, and with the proximity
                   13849:                    *  position of the node in the node-set with respect to
                   13850:                    *  the axis as the context position;"
                   13851:                    * @oldset is the node-set" to be filtered.
                   13852:                    *
                   13853:                    * SPEC XPath 1.0:
                   13854:                    *  "only predicates change the context position and
                   13855:                    *  context size (see [2.4 Predicates])."
                   13856:                    * Example:
                   13857:                    *   node-set  context pos
                   13858:                    *    nA         1
                   13859:                    *    nB         2
                   13860:                    *    nC         3
                   13861:                    *   After applying predicate [position() > 1] :
                   13862:                    *   node-set  context pos
                   13863:                    *    nB         1
                   13864:                    *    nC         2
                   13865:                    *
                   13866:                    * removed the first node in the node-set, then
                   13867:                    * the context position of the
                   13868:                    */
                   13869:                     for (i = 0; i < oldset->nodeNr; i++) {
                   13870:                         /*
                   13871:                          * Run the evaluation with a node list made of
                   13872:                          * a single item in the nodeset.
                   13873:                          */
                   13874:                         ctxt->context->node = oldset->nodeTab[i];
                   13875:                        if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
                   13876:                            (oldset->nodeTab[i]->doc != NULL))
                   13877:                            ctxt->context->doc = oldset->nodeTab[i]->doc;
                   13878:                        if (tmp == NULL) {
                   13879:                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   13880:                                ctxt->context->node);
                   13881:                        } else {
1.1.1.3 ! misho    13882:                            if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
        !          13883:                                               ctxt->context->node) < 0) {
        !          13884:                                ctxt->error = XPATH_MEMORY_ERROR;
        !          13885:                            }
1.1       misho    13886:                        }
                   13887:                         valuePush(ctxt, tmp);
                   13888:                         ctxt->context->contextSize = oldset->nodeNr;
                   13889:                         ctxt->context->proximityPosition = i + 1;
                   13890:                        /*
                   13891:                        * Evaluate the predicate against the context node.
                   13892:                        * Can/should we optimize position() predicates
                   13893:                        * here (e.g. "[1]")?
                   13894:                        */
                   13895:                         if (op->ch2 != -1)
                   13896:                             total +=
                   13897:                                 xmlXPathCompOpEval(ctxt,
                   13898:                                                    &comp->steps[op->ch2]);
                   13899:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
                   13900:                            xmlXPathFreeNodeSet(newset);
                   13901:                            xmlXPathFreeObject(obj);
                   13902:                            return(0);
                   13903:                        }
                   13904: 
                   13905:                         /*
                   13906:                          * The result of the evaluation needs to be tested to
                   13907:                          * decide whether the filter succeeded or not
                   13908:                          */
                   13909:                        /*
                   13910:                        * OPTIMIZE TODO: Can we use
                   13911:                        * xmlXPathNodeSetAdd*Unique()* instead?
                   13912:                        */
                   13913:                         res = valuePop(ctxt);
                   13914:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
1.1.1.3 ! misho    13915:                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
        !          13916:                                < 0)
        !          13917:                                ctxt->error = XPATH_MEMORY_ERROR;
1.1       misho    13918:                         }
                   13919: 
                   13920:                         /*
                   13921:                          * Cleanup
                   13922:                          */
                   13923:                         if (res != NULL) {
                   13924:                            xmlXPathReleaseObject(ctxt->context, res);
                   13925:                        }
                   13926:                         if (ctxt->value == tmp) {
                   13927:                             valuePop(ctxt);
                   13928:                            xmlXPathNodeSetClear(tmp->nodesetval, 1);
                   13929:                            /*
                   13930:                            * Don't free the temporary nodeset
                   13931:                            * in order to avoid massive recreation inside this
                   13932:                            * loop.
                   13933:                            */
                   13934:                         } else
                   13935:                            tmp = NULL;
                   13936:                         ctxt->context->node = NULL;
                   13937:                     }
                   13938:                    if (tmp != NULL)
                   13939:                        xmlXPathReleaseObject(ctxt->context, tmp);
                   13940:                     /*
                   13941:                      * The result is used as the new evaluation set.
                   13942:                      */
                   13943:                    xmlXPathReleaseObject(ctxt->context, obj);
                   13944:                     ctxt->context->node = NULL;
                   13945:                     ctxt->context->contextSize = -1;
                   13946:                     ctxt->context->proximityPosition = -1;
                   13947:                    /* may want to move this past the '}' later */
                   13948:                    ctxt->context->doc = oldDoc;
                   13949:                    valuePush(ctxt,
                   13950:                        xmlXPathCacheWrapNodeSet(ctxt->context, newset));
                   13951:                 }
                   13952:                 ctxt->context->node = oldnode;
                   13953:                 return (total);
                   13954:             }
                   13955:         case XPATH_OP_SORT:
                   13956:             if (op->ch1 != -1)
                   13957:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13958:            CHECK_ERROR0;
                   13959:             if ((ctxt->value != NULL) &&
                   13960:                 (ctxt->value->type == XPATH_NODESET) &&
                   13961:                 (ctxt->value->nodesetval != NULL) &&
                   13962:                (ctxt->value->nodesetval->nodeNr > 1))
                   13963:            {
                   13964:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
                   13965:            }
                   13966:             return (total);
                   13967: #ifdef LIBXML_XPTR_ENABLED
                   13968:         case XPATH_OP_RANGETO:{
                   13969:                 xmlXPathObjectPtr range;
                   13970:                 xmlXPathObjectPtr res, obj;
                   13971:                 xmlXPathObjectPtr tmp;
                   13972:                 xmlLocationSetPtr newlocset = NULL;
                   13973:                    xmlLocationSetPtr oldlocset;
                   13974:                 xmlNodeSetPtr oldset;
                   13975:                 int i, j;
                   13976: 
                   13977:                 if (op->ch1 != -1)
                   13978:                     total +=
                   13979:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                   13980:                 if (op->ch2 == -1)
                   13981:                     return (total);
                   13982: 
                   13983:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
                   13984:                     /*
                   13985:                      * Extract the old locset, and then evaluate the result of the
                   13986:                      * expression for all the element in the locset. use it to grow
                   13987:                      * up a new locset.
                   13988:                      */
                   13989:                     CHECK_TYPE0(XPATH_LOCATIONSET);
                   13990:                     obj = valuePop(ctxt);
                   13991:                     oldlocset = obj->user;
                   13992: 
                   13993:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
                   13994:                        ctxt->context->node = NULL;
                   13995:                         ctxt->context->contextSize = 0;
                   13996:                         ctxt->context->proximityPosition = 0;
                   13997:                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
                   13998:                         res = valuePop(ctxt);
                   13999:                         if (res != NULL) {
                   14000:                            xmlXPathReleaseObject(ctxt->context, res);
                   14001:                        }
                   14002:                         valuePush(ctxt, obj);
                   14003:                         CHECK_ERROR0;
                   14004:                         return (total);
                   14005:                     }
                   14006:                     newlocset = xmlXPtrLocationSetCreate(NULL);
                   14007: 
                   14008:                     for (i = 0; i < oldlocset->locNr; i++) {
                   14009:                         /*
                   14010:                          * Run the evaluation with a node list made of a
                   14011:                          * single item in the nodelocset.
                   14012:                          */
                   14013:                         ctxt->context->node = oldlocset->locTab[i]->user;
                   14014:                         ctxt->context->contextSize = oldlocset->locNr;
                   14015:                         ctxt->context->proximityPosition = i + 1;
                   14016:                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   14017:                            ctxt->context->node);
                   14018:                         valuePush(ctxt, tmp);
                   14019: 
                   14020:                         if (op->ch2 != -1)
                   14021:                             total +=
                   14022:                                 xmlXPathCompOpEval(ctxt,
                   14023:                                                    &comp->steps[op->ch2]);
                   14024:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
                   14025:                            xmlXPathFreeObject(obj);
                   14026:                            return(0);
                   14027:                        }
                   14028: 
                   14029:                         res = valuePop(ctxt);
                   14030:                        if (res->type == XPATH_LOCATIONSET) {
                   14031:                            xmlLocationSetPtr rloc =
                   14032:                                (xmlLocationSetPtr)res->user;
                   14033:                            for (j=0; j<rloc->locNr; j++) {
                   14034:                                range = xmlXPtrNewRange(
                   14035:                                  oldlocset->locTab[i]->user,
                   14036:                                  oldlocset->locTab[i]->index,
                   14037:                                  rloc->locTab[j]->user2,
                   14038:                                  rloc->locTab[j]->index2);
                   14039:                                if (range != NULL) {
                   14040:                                    xmlXPtrLocationSetAdd(newlocset, range);
                   14041:                                }
                   14042:                            }
                   14043:                        } else {
                   14044:                            range = xmlXPtrNewRangeNodeObject(
                   14045:                                (xmlNodePtr)oldlocset->locTab[i]->user, res);
                   14046:                             if (range != NULL) {
                   14047:                                 xmlXPtrLocationSetAdd(newlocset,range);
                   14048:                            }
                   14049:                         }
                   14050: 
                   14051:                         /*
                   14052:                          * Cleanup
                   14053:                          */
                   14054:                         if (res != NULL) {
                   14055:                            xmlXPathReleaseObject(ctxt->context, res);
                   14056:                        }
                   14057:                         if (ctxt->value == tmp) {
                   14058:                             res = valuePop(ctxt);
                   14059:                            xmlXPathReleaseObject(ctxt->context, res);
                   14060:                         }
                   14061: 
                   14062:                         ctxt->context->node = NULL;
                   14063:                     }
                   14064:                } else {        /* Not a location set */
                   14065:                     CHECK_TYPE0(XPATH_NODESET);
                   14066:                     obj = valuePop(ctxt);
                   14067:                     oldset = obj->nodesetval;
                   14068:                     ctxt->context->node = NULL;
                   14069: 
                   14070:                     newlocset = xmlXPtrLocationSetCreate(NULL);
                   14071: 
                   14072:                     if (oldset != NULL) {
                   14073:                         for (i = 0; i < oldset->nodeNr; i++) {
                   14074:                             /*
                   14075:                              * Run the evaluation with a node list made of a single item
                   14076:                              * in the nodeset.
                   14077:                              */
                   14078:                             ctxt->context->node = oldset->nodeTab[i];
                   14079:                            /*
                   14080:                            * OPTIMIZE TODO: Avoid recreation for every iteration.
                   14081:                            */
                   14082:                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
                   14083:                                ctxt->context->node);
                   14084:                             valuePush(ctxt, tmp);
                   14085: 
                   14086:                             if (op->ch2 != -1)
                   14087:                                 total +=
                   14088:                                     xmlXPathCompOpEval(ctxt,
                   14089:                                                    &comp->steps[op->ch2]);
                   14090:                            if (ctxt->error != XPATH_EXPRESSION_OK) {
                   14091:                                xmlXPathFreeObject(obj);
                   14092:                                return(0);
                   14093:                            }
                   14094: 
                   14095:                             res = valuePop(ctxt);
                   14096:                             range =
                   14097:                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
                   14098:                                                       res);
                   14099:                             if (range != NULL) {
                   14100:                                 xmlXPtrLocationSetAdd(newlocset, range);
                   14101:                             }
                   14102: 
                   14103:                             /*
                   14104:                              * Cleanup
                   14105:                              */
                   14106:                             if (res != NULL) {
                   14107:                                xmlXPathReleaseObject(ctxt->context, res);
                   14108:                            }
                   14109:                             if (ctxt->value == tmp) {
                   14110:                                 res = valuePop(ctxt);
                   14111:                                xmlXPathReleaseObject(ctxt->context, res);
                   14112:                             }
                   14113: 
                   14114:                             ctxt->context->node = NULL;
                   14115:                         }
                   14116:                     }
                   14117:                 }
                   14118: 
                   14119:                 /*
                   14120:                  * The result is used as the new evaluation set.
                   14121:                  */
                   14122:                xmlXPathReleaseObject(ctxt->context, obj);
                   14123:                 ctxt->context->node = NULL;
                   14124:                 ctxt->context->contextSize = -1;
                   14125:                 ctxt->context->proximityPosition = -1;
                   14126:                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
                   14127:                 return (total);
                   14128:             }
                   14129: #endif /* LIBXML_XPTR_ENABLED */
                   14130:     }
                   14131:     xmlGenericError(xmlGenericErrorContext,
                   14132:                     "XPath: unknown precompiled operation %d\n", op->op);
1.1.1.2   misho    14133:     ctxt->error = XPATH_INVALID_OPERAND;
1.1       misho    14134:     return (total);
                   14135: }
                   14136: 
                   14137: /**
                   14138:  * xmlXPathCompOpEvalToBoolean:
                   14139:  * @ctxt:  the XPath parser context
                   14140:  *
                   14141:  * Evaluates if the expression evaluates to true.
                   14142:  *
                   14143:  * Returns 1 if true, 0 if false and -1 on API or internal errors.
                   14144:  */
                   14145: static int
                   14146: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
                   14147:                            xmlXPathStepOpPtr op,
                   14148:                            int isPredicate)
                   14149: {
                   14150:     xmlXPathObjectPtr resObj = NULL;
                   14151: 
                   14152: start:
                   14153:     /* comp = ctxt->comp; */
                   14154:     switch (op->op) {
                   14155:         case XPATH_OP_END:
                   14156:             return (0);
                   14157:        case XPATH_OP_VALUE:
                   14158:            resObj = (xmlXPathObjectPtr) op->value4;
                   14159:            if (isPredicate)
                   14160:                return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
                   14161:            return(xmlXPathCastToBoolean(resObj));
                   14162:        case XPATH_OP_SORT:
                   14163:            /*
                   14164:            * We don't need sorting for boolean results. Skip this one.
                   14165:            */
                   14166:             if (op->ch1 != -1) {
                   14167:                op = &ctxt->comp->steps[op->ch1];
                   14168:                goto start;
                   14169:            }
                   14170:            return(0);
                   14171:        case XPATH_OP_COLLECT:
                   14172:            if (op->ch1 == -1)
                   14173:                return(0);
                   14174: 
                   14175:             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
                   14176:            if (ctxt->error != XPATH_EXPRESSION_OK)
                   14177:                return(-1);
                   14178: 
                   14179:             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
                   14180:            if (ctxt->error != XPATH_EXPRESSION_OK)
                   14181:                return(-1);
                   14182: 
                   14183:            resObj = valuePop(ctxt);
                   14184:            if (resObj == NULL)
                   14185:                return(-1);
                   14186:            break;
                   14187:        default:
                   14188:            /*
                   14189:            * Fallback to call xmlXPathCompOpEval().
                   14190:            */
                   14191:            xmlXPathCompOpEval(ctxt, op);
                   14192:            if (ctxt->error != XPATH_EXPRESSION_OK)
                   14193:                return(-1);
                   14194: 
                   14195:            resObj = valuePop(ctxt);
                   14196:            if (resObj == NULL)
                   14197:                return(-1);
                   14198:            break;
                   14199:     }
                   14200: 
                   14201:     if (resObj) {
                   14202:        int res;
                   14203: 
                   14204:        if (resObj->type == XPATH_BOOLEAN) {
                   14205:            res = resObj->boolval;
                   14206:        } else if (isPredicate) {
                   14207:            /*
                   14208:            * For predicates a result of type "number" is handled
                   14209:            * differently:
                   14210:            * SPEC XPath 1.0:
                   14211:            * "If the result is a number, the result will be converted
                   14212:            *  to true if the number is equal to the context position
                   14213:            *  and will be converted to false otherwise;"
                   14214:            */
                   14215:            res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
                   14216:        } else {
                   14217:            res = xmlXPathCastToBoolean(resObj);
                   14218:        }
                   14219:        xmlXPathReleaseObject(ctxt->context, resObj);
                   14220:        return(res);
                   14221:     }
                   14222: 
                   14223:     return(0);
                   14224: }
                   14225: 
                   14226: #ifdef XPATH_STREAMING
                   14227: /**
                   14228:  * xmlXPathRunStreamEval:
                   14229:  * @ctxt:  the XPath parser context with the compiled expression
                   14230:  *
                   14231:  * Evaluate the Precompiled Streamable XPath expression in the given context.
                   14232:  */
                   14233: static int
                   14234: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
                   14235:                      xmlXPathObjectPtr *resultSeq, int toBool)
                   14236: {
                   14237:     int max_depth, min_depth;
                   14238:     int from_root;
                   14239:     int ret, depth;
                   14240:     int eval_all_nodes;
                   14241:     xmlNodePtr cur = NULL, limit = NULL;
                   14242:     xmlStreamCtxtPtr patstream = NULL;
                   14243: 
                   14244:     int nb_nodes = 0;
                   14245: 
                   14246:     if ((ctxt == NULL) || (comp == NULL))
                   14247:         return(-1);
                   14248:     max_depth = xmlPatternMaxDepth(comp);
                   14249:     if (max_depth == -1)
                   14250:         return(-1);
                   14251:     if (max_depth == -2)
                   14252:         max_depth = 10000;
                   14253:     min_depth = xmlPatternMinDepth(comp);
                   14254:     if (min_depth == -1)
                   14255:         return(-1);
                   14256:     from_root = xmlPatternFromRoot(comp);
                   14257:     if (from_root < 0)
                   14258:         return(-1);
                   14259: #if 0
                   14260:     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
                   14261: #endif
                   14262: 
                   14263:     if (! toBool) {
                   14264:        if (resultSeq == NULL)
                   14265:            return(-1);
                   14266:        *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
                   14267:        if (*resultSeq == NULL)
                   14268:            return(-1);
                   14269:     }
                   14270: 
                   14271:     /*
                   14272:      * handle the special cases of "/" amd "." being matched
                   14273:      */
                   14274:     if (min_depth == 0) {
                   14275:        if (from_root) {
                   14276:            /* Select "/" */
                   14277:            if (toBool)
                   14278:                return(1);
                   14279:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
1.1.1.3 ! misho    14280:                                     (xmlNodePtr) ctxt->doc);
1.1       misho    14281:        } else {
                   14282:            /* Select "self::node()" */
                   14283:            if (toBool)
                   14284:                return(1);
                   14285:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
                   14286:        }
                   14287:     }
                   14288:     if (max_depth == 0) {
                   14289:        return(0);
                   14290:     }
                   14291: 
                   14292:     if (from_root) {
                   14293:         cur = (xmlNodePtr)ctxt->doc;
                   14294:     } else if (ctxt->node != NULL) {
                   14295:         switch (ctxt->node->type) {
                   14296:             case XML_ELEMENT_NODE:
                   14297:             case XML_DOCUMENT_NODE:
                   14298:             case XML_DOCUMENT_FRAG_NODE:
                   14299:             case XML_HTML_DOCUMENT_NODE:
                   14300: #ifdef LIBXML_DOCB_ENABLED
                   14301:             case XML_DOCB_DOCUMENT_NODE:
                   14302: #endif
                   14303:                cur = ctxt->node;
                   14304:                break;
                   14305:             case XML_ATTRIBUTE_NODE:
                   14306:             case XML_TEXT_NODE:
                   14307:             case XML_CDATA_SECTION_NODE:
                   14308:             case XML_ENTITY_REF_NODE:
                   14309:             case XML_ENTITY_NODE:
                   14310:             case XML_PI_NODE:
                   14311:             case XML_COMMENT_NODE:
                   14312:             case XML_NOTATION_NODE:
                   14313:             case XML_DTD_NODE:
                   14314:             case XML_DOCUMENT_TYPE_NODE:
                   14315:             case XML_ELEMENT_DECL:
                   14316:             case XML_ATTRIBUTE_DECL:
                   14317:             case XML_ENTITY_DECL:
                   14318:             case XML_NAMESPACE_DECL:
                   14319:             case XML_XINCLUDE_START:
                   14320:             case XML_XINCLUDE_END:
                   14321:                break;
                   14322:        }
                   14323:        limit = cur;
                   14324:     }
                   14325:     if (cur == NULL) {
                   14326:         return(0);
                   14327:     }
                   14328: 
                   14329:     patstream = xmlPatternGetStreamCtxt(comp);
                   14330:     if (patstream == NULL) {
                   14331:        /*
                   14332:        * QUESTION TODO: Is this an error?
                   14333:        */
                   14334:        return(0);
                   14335:     }
                   14336: 
                   14337:     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
                   14338: 
                   14339:     if (from_root) {
                   14340:        ret = xmlStreamPush(patstream, NULL, NULL);
                   14341:        if (ret < 0) {
                   14342:        } else if (ret == 1) {
                   14343:            if (toBool)
                   14344:                goto return_1;
                   14345:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
                   14346:        }
                   14347:     }
                   14348:     depth = 0;
                   14349:     goto scan_children;
                   14350: next_node:
                   14351:     do {
                   14352:         nb_nodes++;
                   14353: 
                   14354:        switch (cur->type) {
                   14355:            case XML_ELEMENT_NODE:
                   14356:            case XML_TEXT_NODE:
                   14357:            case XML_CDATA_SECTION_NODE:
                   14358:            case XML_COMMENT_NODE:
                   14359:            case XML_PI_NODE:
                   14360:                if (cur->type == XML_ELEMENT_NODE) {
                   14361:                    ret = xmlStreamPush(patstream, cur->name,
                   14362:                                (cur->ns ? cur->ns->href : NULL));
                   14363:                } else if (eval_all_nodes)
                   14364:                    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
                   14365:                else
                   14366:                    break;
                   14367: 
                   14368:                if (ret < 0) {
                   14369:                    /* NOP. */
                   14370:                } else if (ret == 1) {
                   14371:                    if (toBool)
                   14372:                        goto return_1;
1.1.1.3 ! misho    14373:                    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
        !          14374:                        < 0) {
        !          14375:                        ctxt->lastError.domain = XML_FROM_XPATH;
        !          14376:                        ctxt->lastError.code = XML_ERR_NO_MEMORY;
        !          14377:                    }
1.1       misho    14378:                }
                   14379:                if ((cur->children == NULL) || (depth >= max_depth)) {
                   14380:                    ret = xmlStreamPop(patstream);
                   14381:                    while (cur->next != NULL) {
                   14382:                        cur = cur->next;
                   14383:                        if ((cur->type != XML_ENTITY_DECL) &&
                   14384:                            (cur->type != XML_DTD_NODE))
                   14385:                            goto next_node;
                   14386:                    }
                   14387:                }
                   14388:            default:
                   14389:                break;
                   14390:        }
                   14391: 
                   14392: scan_children:
1.1.1.3 ! misho    14393:        if (cur->type == XML_NAMESPACE_DECL) break;
1.1       misho    14394:        if ((cur->children != NULL) && (depth < max_depth)) {
                   14395:            /*
                   14396:             * Do not descend on entities declarations
                   14397:             */
                   14398:            if (cur->children->type != XML_ENTITY_DECL) {
                   14399:                cur = cur->children;
                   14400:                depth++;
                   14401:                /*
                   14402:                 * Skip DTDs
                   14403:                 */
                   14404:                if (cur->type != XML_DTD_NODE)
                   14405:                    continue;
                   14406:            }
                   14407:        }
                   14408: 
                   14409:        if (cur == limit)
                   14410:            break;
                   14411: 
                   14412:        while (cur->next != NULL) {
                   14413:            cur = cur->next;
                   14414:            if ((cur->type != XML_ENTITY_DECL) &&
                   14415:                (cur->type != XML_DTD_NODE))
                   14416:                goto next_node;
                   14417:        }
                   14418: 
                   14419:        do {
                   14420:            cur = cur->parent;
                   14421:            depth--;
                   14422:            if ((cur == NULL) || (cur == limit))
                   14423:                goto done;
                   14424:            if (cur->type == XML_ELEMENT_NODE) {
                   14425:                ret = xmlStreamPop(patstream);
                   14426:            } else if ((eval_all_nodes) &&
                   14427:                ((cur->type == XML_TEXT_NODE) ||
                   14428:                 (cur->type == XML_CDATA_SECTION_NODE) ||
                   14429:                 (cur->type == XML_COMMENT_NODE) ||
                   14430:                 (cur->type == XML_PI_NODE)))
                   14431:            {
                   14432:                ret = xmlStreamPop(patstream);
                   14433:            }
                   14434:            if (cur->next != NULL) {
                   14435:                cur = cur->next;
                   14436:                break;
                   14437:            }
                   14438:        } while (cur != NULL);
                   14439: 
                   14440:     } while ((cur != NULL) && (depth >= 0));
                   14441: 
                   14442: done:
                   14443: 
                   14444: #if 0
                   14445:     printf("stream eval: checked %d nodes selected %d\n",
                   14446:            nb_nodes, retObj->nodesetval->nodeNr);
                   14447: #endif
                   14448: 
                   14449:     if (patstream)
                   14450:        xmlFreeStreamCtxt(patstream);
                   14451:     return(0);
                   14452: 
                   14453: return_1:
                   14454:     if (patstream)
                   14455:        xmlFreeStreamCtxt(patstream);
                   14456:     return(1);
                   14457: }
                   14458: #endif /* XPATH_STREAMING */
                   14459: 
                   14460: /**
                   14461:  * xmlXPathRunEval:
                   14462:  * @ctxt:  the XPath parser context with the compiled expression
                   14463:  * @toBool:  evaluate to a boolean result
                   14464:  *
                   14465:  * Evaluate the Precompiled XPath expression in the given context.
                   14466:  */
                   14467: static int
                   14468: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
                   14469: {
                   14470:     xmlXPathCompExprPtr comp;
                   14471: 
                   14472:     if ((ctxt == NULL) || (ctxt->comp == NULL))
                   14473:        return(-1);
                   14474: 
                   14475:     if (ctxt->valueTab == NULL) {
                   14476:        /* Allocate the value stack */
                   14477:        ctxt->valueTab = (xmlXPathObjectPtr *)
                   14478:                         xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
                   14479:        if (ctxt->valueTab == NULL) {
                   14480:            xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
                   14481:            xmlFree(ctxt);
                   14482:        }
                   14483:        ctxt->valueNr = 0;
                   14484:        ctxt->valueMax = 10;
                   14485:        ctxt->value = NULL;
1.1.1.2   misho    14486:         ctxt->valueFrame = 0;
1.1       misho    14487:     }
                   14488: #ifdef XPATH_STREAMING
                   14489:     if (ctxt->comp->stream) {
                   14490:        int res;
                   14491: 
                   14492:        if (toBool) {
                   14493:            /*
                   14494:            * Evaluation to boolean result.
                   14495:            */
                   14496:            res = xmlXPathRunStreamEval(ctxt->context,
                   14497:                ctxt->comp->stream, NULL, 1);
                   14498:            if (res != -1)
                   14499:                return(res);
                   14500:        } else {
                   14501:            xmlXPathObjectPtr resObj = NULL;
                   14502: 
                   14503:            /*
                   14504:            * Evaluation to a sequence.
                   14505:            */
                   14506:            res = xmlXPathRunStreamEval(ctxt->context,
                   14507:                ctxt->comp->stream, &resObj, 0);
                   14508: 
                   14509:            if ((res != -1) && (resObj != NULL)) {
                   14510:                valuePush(ctxt, resObj);
                   14511:                return(0);
                   14512:            }
                   14513:            if (resObj != NULL)
                   14514:                xmlXPathReleaseObject(ctxt->context, resObj);
                   14515:        }
                   14516:        /*
                   14517:        * QUESTION TODO: This falls back to normal XPath evaluation
                   14518:        * if res == -1. Is this intended?
                   14519:        */
                   14520:     }
                   14521: #endif
                   14522:     comp = ctxt->comp;
                   14523:     if (comp->last < 0) {
                   14524:        xmlGenericError(xmlGenericErrorContext,
                   14525:            "xmlXPathRunEval: last is less than zero\n");
                   14526:        return(-1);
                   14527:     }
                   14528:     if (toBool)
                   14529:        return(xmlXPathCompOpEvalToBoolean(ctxt,
                   14530:            &comp->steps[comp->last], 0));
                   14531:     else
                   14532:        xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
                   14533: 
                   14534:     return(0);
                   14535: }
                   14536: 
                   14537: /************************************************************************
                   14538:  *                                                                     *
                   14539:  *                     Public interfaces                               *
                   14540:  *                                                                     *
                   14541:  ************************************************************************/
                   14542: 
                   14543: /**
                   14544:  * xmlXPathEvalPredicate:
                   14545:  * @ctxt:  the XPath context
                   14546:  * @res:  the Predicate Expression evaluation result
                   14547:  *
                   14548:  * Evaluate a predicate result for the current node.
                   14549:  * A PredicateExpr is evaluated by evaluating the Expr and converting
                   14550:  * the result to a boolean. If the result is a number, the result will
                   14551:  * be converted to true if the number is equal to the position of the
                   14552:  * context node in the context node list (as returned by the position
                   14553:  * function) and will be converted to false otherwise; if the result
                   14554:  * is not a number, then the result will be converted as if by a call
                   14555:  * to the boolean function.
                   14556:  *
                   14557:  * Returns 1 if predicate is true, 0 otherwise
                   14558:  */
                   14559: int
                   14560: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
                   14561:     if ((ctxt == NULL) || (res == NULL)) return(0);
                   14562:     switch (res->type) {
                   14563:         case XPATH_BOOLEAN:
                   14564:            return(res->boolval);
                   14565:         case XPATH_NUMBER:
                   14566:            return(res->floatval == ctxt->proximityPosition);
                   14567:         case XPATH_NODESET:
                   14568:         case XPATH_XSLT_TREE:
                   14569:            if (res->nodesetval == NULL)
                   14570:                return(0);
                   14571:            return(res->nodesetval->nodeNr != 0);
                   14572:         case XPATH_STRING:
                   14573:            return((res->stringval != NULL) &&
                   14574:                   (xmlStrlen(res->stringval) != 0));
                   14575:         default:
                   14576:            STRANGE
                   14577:     }
                   14578:     return(0);
                   14579: }
                   14580: 
                   14581: /**
                   14582:  * xmlXPathEvaluatePredicateResult:
                   14583:  * @ctxt:  the XPath Parser context
                   14584:  * @res:  the Predicate Expression evaluation result
                   14585:  *
                   14586:  * Evaluate a predicate result for the current node.
                   14587:  * A PredicateExpr is evaluated by evaluating the Expr and converting
                   14588:  * the result to a boolean. If the result is a number, the result will
                   14589:  * be converted to true if the number is equal to the position of the
                   14590:  * context node in the context node list (as returned by the position
                   14591:  * function) and will be converted to false otherwise; if the result
                   14592:  * is not a number, then the result will be converted as if by a call
                   14593:  * to the boolean function.
                   14594:  *
                   14595:  * Returns 1 if predicate is true, 0 otherwise
                   14596:  */
                   14597: int
                   14598: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
                   14599:                                 xmlXPathObjectPtr res) {
                   14600:     if ((ctxt == NULL) || (res == NULL)) return(0);
                   14601:     switch (res->type) {
                   14602:         case XPATH_BOOLEAN:
                   14603:            return(res->boolval);
                   14604:         case XPATH_NUMBER:
                   14605: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
                   14606:            return((res->floatval == ctxt->context->proximityPosition) &&
                   14607:                   (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
                   14608: #else
                   14609:            return(res->floatval == ctxt->context->proximityPosition);
                   14610: #endif
                   14611:         case XPATH_NODESET:
                   14612:         case XPATH_XSLT_TREE:
                   14613:            if (res->nodesetval == NULL)
                   14614:                return(0);
                   14615:            return(res->nodesetval->nodeNr != 0);
                   14616:         case XPATH_STRING:
                   14617:            return((res->stringval != NULL) && (res->stringval[0] != 0));
                   14618: #ifdef LIBXML_XPTR_ENABLED
                   14619:        case XPATH_LOCATIONSET:{
                   14620:            xmlLocationSetPtr ptr = res->user;
                   14621:            if (ptr == NULL)
                   14622:                return(0);
                   14623:            return (ptr->locNr != 0);
                   14624:            }
                   14625: #endif
                   14626:         default:
                   14627:            STRANGE
                   14628:     }
                   14629:     return(0);
                   14630: }
                   14631: 
                   14632: #ifdef XPATH_STREAMING
                   14633: /**
                   14634:  * xmlXPathTryStreamCompile:
                   14635:  * @ctxt: an XPath context
                   14636:  * @str:  the XPath expression
                   14637:  *
                   14638:  * Try to compile the XPath expression as a streamable subset.
                   14639:  *
                   14640:  * Returns the compiled expression or NULL if failed to compile.
                   14641:  */
                   14642: static xmlXPathCompExprPtr
                   14643: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
                   14644:     /*
                   14645:      * Optimization: use streaming patterns when the XPath expression can
                   14646:      * be compiled to a stream lookup
                   14647:      */
                   14648:     xmlPatternPtr stream;
                   14649:     xmlXPathCompExprPtr comp;
                   14650:     xmlDictPtr dict = NULL;
                   14651:     const xmlChar **namespaces = NULL;
                   14652:     xmlNsPtr ns;
                   14653:     int i, j;
                   14654: 
                   14655:     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
                   14656:         (!xmlStrchr(str, '@'))) {
                   14657:        const xmlChar *tmp;
                   14658: 
                   14659:        /*
                   14660:         * We don't try to handle expressions using the verbose axis
                   14661:         * specifiers ("::"), just the simplied form at this point.
                   14662:         * Additionally, if there is no list of namespaces available and
                   14663:         *  there's a ":" in the expression, indicating a prefixed QName,
                   14664:         *  then we won't try to compile either. xmlPatterncompile() needs
                   14665:         *  to have a list of namespaces at compilation time in order to
                   14666:         *  compile prefixed name tests.
                   14667:         */
                   14668:        tmp = xmlStrchr(str, ':');
                   14669:        if ((tmp != NULL) &&
                   14670:            ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
                   14671:            return(NULL);
                   14672: 
                   14673:        if (ctxt != NULL) {
                   14674:            dict = ctxt->dict;
                   14675:            if (ctxt->nsNr > 0) {
                   14676:                namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
                   14677:                if (namespaces == NULL) {
                   14678:                    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
                   14679:                    return(NULL);
                   14680:                }
                   14681:                for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
                   14682:                    ns = ctxt->namespaces[j];
                   14683:                    namespaces[i++] = ns->href;
                   14684:                    namespaces[i++] = ns->prefix;
                   14685:                }
                   14686:                namespaces[i++] = NULL;
                   14687:                namespaces[i] = NULL;
                   14688:            }
                   14689:        }
                   14690: 
                   14691:        stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
                   14692:                        &namespaces[0]);
                   14693:        if (namespaces != NULL) {
                   14694:            xmlFree((xmlChar **)namespaces);
                   14695:        }
                   14696:        if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
                   14697:            comp = xmlXPathNewCompExpr();
                   14698:            if (comp == NULL) {
                   14699:                xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
                   14700:                return(NULL);
                   14701:            }
                   14702:            comp->stream = stream;
                   14703:            comp->dict = dict;
                   14704:            if (comp->dict)
                   14705:                xmlDictReference(comp->dict);
                   14706:            return(comp);
                   14707:        }
                   14708:        xmlFreePattern(stream);
                   14709:     }
                   14710:     return(NULL);
                   14711: }
                   14712: #endif /* XPATH_STREAMING */
                   14713: 
                   14714: static void
1.1.1.3 ! misho    14715: xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
1.1       misho    14716: {
                   14717:     /*
                   14718:     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
                   14719:     * internal representation.
                   14720:     */
                   14721: 
1.1.1.3 ! misho    14722:     if ((op->ch1 != -1) &&
        !          14723:         (op->op == XPATH_OP_COLLECT /* 11 */))
        !          14724:     {
        !          14725:         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
        !          14726: 
        !          14727:         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
        !          14728:             ((xmlXPathAxisVal) prevop->value ==
        !          14729:                 AXIS_DESCENDANT_OR_SELF) &&
        !          14730:             (prevop->ch2 == -1) &&
        !          14731:             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
        !          14732:             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
        !          14733:         {
        !          14734:             /*
        !          14735:             * This is a "descendant-or-self::node()" without predicates.
        !          14736:             * Try to eliminate it.
        !          14737:             */
        !          14738: 
        !          14739:             switch ((xmlXPathAxisVal) op->value) {
        !          14740:                 case AXIS_CHILD:
        !          14741:                 case AXIS_DESCENDANT:
        !          14742:                     /*
        !          14743:                     * Convert "descendant-or-self::node()/child::" or
        !          14744:                     * "descendant-or-self::node()/descendant::" to
        !          14745:                     * "descendant::"
        !          14746:                     */
        !          14747:                     op->ch1   = prevop->ch1;
        !          14748:                     op->value = AXIS_DESCENDANT;
        !          14749:                     break;
        !          14750:                 case AXIS_SELF:
        !          14751:                 case AXIS_DESCENDANT_OR_SELF:
        !          14752:                     /*
        !          14753:                     * Convert "descendant-or-self::node()/self::" or
        !          14754:                     * "descendant-or-self::node()/descendant-or-self::" to
        !          14755:                     * to "descendant-or-self::"
        !          14756:                     */
        !          14757:                     op->ch1   = prevop->ch1;
        !          14758:                     op->value = AXIS_DESCENDANT_OR_SELF;
        !          14759:                     break;
        !          14760:                 default:
        !          14761:                     break;
        !          14762:             }
1.1       misho    14763:        }
                   14764:     }
1.1.1.3 ! misho    14765: 
        !          14766:     /* Recurse */
        !          14767:     if (op->ch1 != -1)
        !          14768:         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
1.1       misho    14769:     if (op->ch2 != -1)
1.1.1.3 ! misho    14770:        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
1.1       misho    14771: }
                   14772: 
                   14773: /**
                   14774:  * xmlXPathCtxtCompile:
                   14775:  * @ctxt: an XPath context
                   14776:  * @str:  the XPath expression
                   14777:  *
                   14778:  * Compile an XPath expression
                   14779:  *
                   14780:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
                   14781:  *         the caller has to free the object.
                   14782:  */
                   14783: xmlXPathCompExprPtr
                   14784: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
                   14785:     xmlXPathParserContextPtr pctxt;
                   14786:     xmlXPathCompExprPtr comp;
                   14787: 
                   14788: #ifdef XPATH_STREAMING
                   14789:     comp = xmlXPathTryStreamCompile(ctxt, str);
                   14790:     if (comp != NULL)
                   14791:         return(comp);
                   14792: #endif
                   14793: 
                   14794:     xmlXPathInit();
                   14795: 
                   14796:     pctxt = xmlXPathNewParserContext(str, ctxt);
                   14797:     if (pctxt == NULL)
                   14798:         return NULL;
                   14799:     xmlXPathCompileExpr(pctxt, 1);
                   14800: 
                   14801:     if( pctxt->error != XPATH_EXPRESSION_OK )
                   14802:     {
                   14803:         xmlXPathFreeParserContext(pctxt);
                   14804:         return(NULL);
                   14805:     }
                   14806: 
                   14807:     if (*pctxt->cur != 0) {
                   14808:        /*
                   14809:         * aleksey: in some cases this line prints *second* error message
                   14810:         * (see bug #78858) and probably this should be fixed.
                   14811:         * However, we are not sure that all error messages are printed
                   14812:         * out in other places. It's not critical so we leave it as-is for now
                   14813:         */
                   14814:        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
                   14815:        comp = NULL;
                   14816:     } else {
                   14817:        comp = pctxt->comp;
                   14818:        pctxt->comp = NULL;
                   14819:     }
                   14820:     xmlXPathFreeParserContext(pctxt);
                   14821: 
                   14822:     if (comp != NULL) {
                   14823:        comp->expr = xmlStrdup(str);
                   14824: #ifdef DEBUG_EVAL_COUNTS
                   14825:        comp->string = xmlStrdup(str);
                   14826:        comp->nb = 0;
                   14827: #endif
1.1.1.3 ! misho    14828:        if ((comp->nbStep > 1) && (comp->last >= 0)) {
        !          14829:            xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
1.1       misho    14830:        }
                   14831:     }
                   14832:     return(comp);
                   14833: }
                   14834: 
                   14835: /**
                   14836:  * xmlXPathCompile:
                   14837:  * @str:  the XPath expression
                   14838:  *
                   14839:  * Compile an XPath expression
                   14840:  *
                   14841:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
                   14842:  *         the caller has to free the object.
                   14843:  */
                   14844: xmlXPathCompExprPtr
                   14845: xmlXPathCompile(const xmlChar *str) {
                   14846:     return(xmlXPathCtxtCompile(NULL, str));
                   14847: }
                   14848: 
                   14849: /**
                   14850:  * xmlXPathCompiledEvalInternal:
                   14851:  * @comp:  the compiled XPath expression
                   14852:  * @ctxt:  the XPath context
                   14853:  * @resObj: the resulting XPath object or NULL
                   14854:  * @toBool: 1 if only a boolean result is requested
                   14855:  *
                   14856:  * Evaluate the Precompiled XPath expression in the given context.
                   14857:  * The caller has to free @resObj.
                   14858:  *
                   14859:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   14860:  *         the caller has to free the object.
                   14861:  */
                   14862: static int
                   14863: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
                   14864:                             xmlXPathContextPtr ctxt,
                   14865:                             xmlXPathObjectPtr *resObj,
                   14866:                             int toBool)
                   14867: {
                   14868:     xmlXPathParserContextPtr pctxt;
                   14869: #ifndef LIBXML_THREAD_ENABLED
                   14870:     static int reentance = 0;
                   14871: #endif
                   14872:     int res;
                   14873: 
                   14874:     CHECK_CTXT_NEG(ctxt)
                   14875: 
                   14876:     if (comp == NULL)
                   14877:        return(-1);
                   14878:     xmlXPathInit();
                   14879: 
                   14880: #ifndef LIBXML_THREAD_ENABLED
                   14881:     reentance++;
                   14882:     if (reentance > 1)
                   14883:        xmlXPathDisableOptimizer = 1;
                   14884: #endif
                   14885: 
                   14886: #ifdef DEBUG_EVAL_COUNTS
                   14887:     comp->nb++;
                   14888:     if ((comp->string != NULL) && (comp->nb > 100)) {
                   14889:        fprintf(stderr, "100 x %s\n", comp->string);
                   14890:        comp->nb = 0;
                   14891:     }
                   14892: #endif
                   14893:     pctxt = xmlXPathCompParserContext(comp, ctxt);
                   14894:     res = xmlXPathRunEval(pctxt, toBool);
                   14895: 
                   14896:     if (resObj) {
                   14897:        if (pctxt->value == NULL) {
                   14898:            xmlGenericError(xmlGenericErrorContext,
                   14899:                "xmlXPathCompiledEval: evaluation failed\n");
                   14900:            *resObj = NULL;
                   14901:        } else {
                   14902:            *resObj = valuePop(pctxt);
                   14903:        }
                   14904:     }
                   14905: 
                   14906:     /*
                   14907:     * Pop all remaining objects from the stack.
                   14908:     */
                   14909:     if (pctxt->valueNr > 0) {
                   14910:        xmlXPathObjectPtr tmp;
                   14911:        int stack = 0;
                   14912: 
                   14913:        do {
                   14914:            tmp = valuePop(pctxt);
                   14915:            if (tmp != NULL) {
                   14916:                stack++;
                   14917:                xmlXPathReleaseObject(ctxt, tmp);
                   14918:            }
                   14919:        } while (tmp != NULL);
                   14920:        if ((stack != 0) &&
                   14921:            ((toBool) || ((resObj) && (*resObj))))
                   14922:        {
                   14923:            xmlGenericError(xmlGenericErrorContext,
                   14924:                "xmlXPathCompiledEval: %d objects left on the stack.\n",
                   14925:                stack);
                   14926:        }
                   14927:     }
                   14928: 
                   14929:     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
                   14930:        xmlXPathFreeObject(*resObj);
                   14931:        *resObj = NULL;
                   14932:     }
                   14933:     pctxt->comp = NULL;
                   14934:     xmlXPathFreeParserContext(pctxt);
                   14935: #ifndef LIBXML_THREAD_ENABLED
                   14936:     reentance--;
                   14937: #endif
                   14938: 
                   14939:     return(res);
                   14940: }
                   14941: 
                   14942: /**
                   14943:  * xmlXPathCompiledEval:
                   14944:  * @comp:  the compiled XPath expression
                   14945:  * @ctx:  the XPath context
                   14946:  *
                   14947:  * Evaluate the Precompiled XPath expression in the given context.
                   14948:  *
                   14949:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   14950:  *         the caller has to free the object.
                   14951:  */
                   14952: xmlXPathObjectPtr
                   14953: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
                   14954: {
                   14955:     xmlXPathObjectPtr res = NULL;
                   14956: 
                   14957:     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
                   14958:     return(res);
                   14959: }
                   14960: 
                   14961: /**
                   14962:  * xmlXPathCompiledEvalToBoolean:
                   14963:  * @comp:  the compiled XPath expression
                   14964:  * @ctxt:  the XPath context
                   14965:  *
                   14966:  * Applies the XPath boolean() function on the result of the given
                   14967:  * compiled expression.
                   14968:  *
                   14969:  * Returns 1 if the expression evaluated to true, 0 if to false and
                   14970:  *         -1 in API and internal errors.
                   14971:  */
                   14972: int
                   14973: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
                   14974:                              xmlXPathContextPtr ctxt)
                   14975: {
                   14976:     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
                   14977: }
                   14978: 
                   14979: /**
                   14980:  * xmlXPathEvalExpr:
                   14981:  * @ctxt:  the XPath Parser context
                   14982:  *
                   14983:  * Parse and evaluate an XPath expression in the given context,
                   14984:  * then push the result on the context stack
                   14985:  */
                   14986: void
                   14987: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
                   14988: #ifdef XPATH_STREAMING
                   14989:     xmlXPathCompExprPtr comp;
                   14990: #endif
                   14991: 
                   14992:     if (ctxt == NULL) return;
                   14993: 
                   14994: #ifdef XPATH_STREAMING
                   14995:     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
                   14996:     if (comp != NULL) {
                   14997:         if (ctxt->comp != NULL)
                   14998:            xmlXPathFreeCompExpr(ctxt->comp);
                   14999:         ctxt->comp = comp;
                   15000:        if (ctxt->cur != NULL)
                   15001:            while (*ctxt->cur != 0) ctxt->cur++;
                   15002:     } else
                   15003: #endif
                   15004:     {
                   15005:        xmlXPathCompileExpr(ctxt, 1);
                   15006:        if ((ctxt->error == XPATH_EXPRESSION_OK) &&
                   15007:            (ctxt->comp != NULL) &&
1.1.1.3 ! misho    15008:            (ctxt->comp->nbStep > 1) &&
        !          15009:            (ctxt->comp->last >= 0))
1.1       misho    15010:        {
1.1.1.3 ! misho    15011:            xmlXPathOptimizeExpression(ctxt->comp,
1.1       misho    15012:                &ctxt->comp->steps[ctxt->comp->last]);
                   15013:        }
                   15014:     }
                   15015:     CHECK_ERROR;
                   15016:     xmlXPathRunEval(ctxt, 0);
                   15017: }
                   15018: 
                   15019: /**
                   15020:  * xmlXPathEval:
                   15021:  * @str:  the XPath expression
                   15022:  * @ctx:  the XPath context
                   15023:  *
                   15024:  * Evaluate the XPath Location Path in the given context.
                   15025:  *
                   15026:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   15027:  *         the caller has to free the object.
                   15028:  */
                   15029: xmlXPathObjectPtr
                   15030: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
                   15031:     xmlXPathParserContextPtr ctxt;
                   15032:     xmlXPathObjectPtr res, tmp, init = NULL;
                   15033:     int stack = 0;
                   15034: 
                   15035:     CHECK_CTXT(ctx)
                   15036: 
                   15037:     xmlXPathInit();
                   15038: 
                   15039:     ctxt = xmlXPathNewParserContext(str, ctx);
                   15040:     if (ctxt == NULL)
                   15041:         return NULL;
                   15042:     xmlXPathEvalExpr(ctxt);
                   15043: 
                   15044:     if (ctxt->value == NULL) {
                   15045:        xmlGenericError(xmlGenericErrorContext,
                   15046:                "xmlXPathEval: evaluation failed\n");
                   15047:        res = NULL;
                   15048:     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
                   15049: #ifdef XPATH_STREAMING
                   15050:             && (ctxt->comp->stream == NULL)
                   15051: #endif
                   15052:              ) {
                   15053:        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
                   15054:        res = NULL;
                   15055:     } else {
                   15056:        res = valuePop(ctxt);
                   15057:     }
                   15058: 
                   15059:     do {
                   15060:         tmp = valuePop(ctxt);
                   15061:        if (tmp != NULL) {
                   15062:            if (tmp != init)
                   15063:                stack++;
                   15064:            xmlXPathReleaseObject(ctx, tmp);
                   15065:         }
                   15066:     } while (tmp != NULL);
                   15067:     if ((stack != 0) && (res != NULL)) {
                   15068:        xmlGenericError(xmlGenericErrorContext,
                   15069:                "xmlXPathEval: %d object left on the stack\n",
                   15070:                stack);
                   15071:     }
                   15072:     if (ctxt->error != XPATH_EXPRESSION_OK) {
                   15073:        xmlXPathFreeObject(res);
                   15074:        res = NULL;
                   15075:     }
                   15076: 
                   15077:     xmlXPathFreeParserContext(ctxt);
                   15078:     return(res);
                   15079: }
                   15080: 
                   15081: /**
1.1.1.3 ! misho    15082:  * xmlXPathSetContextNode:
        !          15083:  * @node: the node to to use as the context node
        !          15084:  * @ctx:  the XPath context
        !          15085:  *
        !          15086:  * Sets 'node' as the context node. The node must be in the same
        !          15087:  * document as that associated with the context.
        !          15088:  *
        !          15089:  * Returns -1 in case of error or 0 if successful
        !          15090:  */
        !          15091: int
        !          15092: xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
        !          15093:     if ((node == NULL) || (ctx == NULL))
        !          15094:         return(-1);
        !          15095: 
        !          15096:     if (node->doc == ctx->doc) {
        !          15097:         ctx->node = node;
        !          15098:        return(0);
        !          15099:     }
        !          15100:     return(-1);
        !          15101: }
        !          15102: 
        !          15103: /**
        !          15104:  * xmlXPathNodeEval:
        !          15105:  * @node: the node to to use as the context node
        !          15106:  * @str:  the XPath expression
        !          15107:  * @ctx:  the XPath context
        !          15108:  *
        !          15109:  * Evaluate the XPath Location Path in the given context. The node 'node'
        !          15110:  * is set as the context node. The context node is not restored.
        !          15111:  *
        !          15112:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
        !          15113:  *         the caller has to free the object.
        !          15114:  */
        !          15115: xmlXPathObjectPtr
        !          15116: xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
        !          15117:     if (str == NULL)
        !          15118:         return(NULL);
        !          15119:     if (xmlXPathSetContextNode(node, ctx) < 0)
        !          15120:         return(NULL);
        !          15121:     return(xmlXPathEval(str, ctx));
        !          15122: }
        !          15123: 
        !          15124: /**
1.1       misho    15125:  * xmlXPathEvalExpression:
                   15126:  * @str:  the XPath expression
                   15127:  * @ctxt:  the XPath context
                   15128:  *
                   15129:  * Evaluate the XPath expression in the given context.
                   15130:  *
                   15131:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   15132:  *         the caller has to free the object.
                   15133:  */
                   15134: xmlXPathObjectPtr
                   15135: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
                   15136:     xmlXPathParserContextPtr pctxt;
                   15137:     xmlXPathObjectPtr res, tmp;
                   15138:     int stack = 0;
                   15139: 
                   15140:     CHECK_CTXT(ctxt)
                   15141: 
                   15142:     xmlXPathInit();
                   15143: 
                   15144:     pctxt = xmlXPathNewParserContext(str, ctxt);
                   15145:     if (pctxt == NULL)
                   15146:         return NULL;
                   15147:     xmlXPathEvalExpr(pctxt);
                   15148: 
                   15149:     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
                   15150:        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
                   15151:        res = NULL;
                   15152:     } else {
                   15153:        res = valuePop(pctxt);
                   15154:     }
                   15155:     do {
                   15156:         tmp = valuePop(pctxt);
                   15157:        if (tmp != NULL) {
                   15158:            xmlXPathReleaseObject(ctxt, tmp);
                   15159:            stack++;
                   15160:        }
                   15161:     } while (tmp != NULL);
                   15162:     if ((stack != 0) && (res != NULL)) {
                   15163:        xmlGenericError(xmlGenericErrorContext,
                   15164:                "xmlXPathEvalExpression: %d object left on the stack\n",
                   15165:                stack);
                   15166:     }
                   15167:     xmlXPathFreeParserContext(pctxt);
                   15168:     return(res);
                   15169: }
                   15170: 
                   15171: /************************************************************************
                   15172:  *                                                                     *
                   15173:  *     Extra functions not pertaining to the XPath spec                *
                   15174:  *                                                                     *
                   15175:  ************************************************************************/
                   15176: /**
                   15177:  * xmlXPathEscapeUriFunction:
                   15178:  * @ctxt:  the XPath Parser context
                   15179:  * @nargs:  the number of arguments
                   15180:  *
                   15181:  * Implement the escape-uri() XPath function
                   15182:  *    string escape-uri(string $str, bool $escape-reserved)
                   15183:  *
                   15184:  * This function applies the URI escaping rules defined in section 2 of [RFC
                   15185:  * 2396] to the string supplied as $uri-part, which typically represents all
                   15186:  * or part of a URI. The effect of the function is to replace any special
                   15187:  * character in the string by an escape sequence of the form %xx%yy...,
                   15188:  * where xxyy... is the hexadecimal representation of the octets used to
                   15189:  * represent the character in UTF-8.
                   15190:  *
                   15191:  * The set of characters that are escaped depends on the setting of the
                   15192:  * boolean argument $escape-reserved.
                   15193:  *
                   15194:  * If $escape-reserved is true, all characters are escaped other than lower
                   15195:  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
                   15196:  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
                   15197:  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
                   15198:  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
                   15199:  * A-F).
                   15200:  *
                   15201:  * If $escape-reserved is false, the behavior differs in that characters
                   15202:  * referred to in [RFC 2396] as reserved characters are not escaped. These
                   15203:  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
                   15204:  *
                   15205:  * [RFC 2396] does not define whether escaped URIs should use lower case or
                   15206:  * upper case for hexadecimal digits. To ensure that escaped URIs can be
                   15207:  * compared using string comparison functions, this function must always use
                   15208:  * the upper-case letters A-F.
                   15209:  *
                   15210:  * Generally, $escape-reserved should be set to true when escaping a string
                   15211:  * that is to form a single part of a URI, and to false when escaping an
                   15212:  * entire URI or URI reference.
                   15213:  *
                   15214:  * In the case of non-ascii characters, the string is encoded according to
                   15215:  * utf-8 and then converted according to RFC 2396.
                   15216:  *
                   15217:  * Examples
                   15218:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
                   15219:  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
                   15220:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
                   15221:  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
                   15222:  *
                   15223:  */
                   15224: static void
                   15225: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   15226:     xmlXPathObjectPtr str;
                   15227:     int escape_reserved;
1.1.1.3 ! misho    15228:     xmlBufPtr target;
1.1       misho    15229:     xmlChar *cptr;
                   15230:     xmlChar escape[4];
                   15231: 
                   15232:     CHECK_ARITY(2);
                   15233: 
                   15234:     escape_reserved = xmlXPathPopBoolean(ctxt);
                   15235: 
                   15236:     CAST_TO_STRING;
                   15237:     str = valuePop(ctxt);
                   15238: 
1.1.1.3 ! misho    15239:     target = xmlBufCreate();
1.1       misho    15240: 
                   15241:     escape[0] = '%';
                   15242:     escape[3] = 0;
                   15243: 
                   15244:     if (target) {
                   15245:        for (cptr = str->stringval; *cptr; cptr++) {
                   15246:            if ((*cptr >= 'A' && *cptr <= 'Z') ||
                   15247:                (*cptr >= 'a' && *cptr <= 'z') ||
                   15248:                (*cptr >= '0' && *cptr <= '9') ||
                   15249:                *cptr == '-' || *cptr == '_' || *cptr == '.' ||
                   15250:                *cptr == '!' || *cptr == '~' || *cptr == '*' ||
                   15251:                *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
                   15252:                (*cptr == '%' &&
                   15253:                 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
                   15254:                  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
                   15255:                  (cptr[1] >= '0' && cptr[1] <= '9')) &&
                   15256:                 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
                   15257:                  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
                   15258:                  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
                   15259:                (!escape_reserved &&
                   15260:                 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
                   15261:                  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
                   15262:                  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
                   15263:                  *cptr == ','))) {
1.1.1.3 ! misho    15264:                xmlBufAdd(target, cptr, 1);
1.1       misho    15265:            } else {
                   15266:                if ((*cptr >> 4) < 10)
                   15267:                    escape[1] = '0' + (*cptr >> 4);
                   15268:                else
                   15269:                    escape[1] = 'A' - 10 + (*cptr >> 4);
                   15270:                if ((*cptr & 0xF) < 10)
                   15271:                    escape[2] = '0' + (*cptr & 0xF);
                   15272:                else
                   15273:                    escape[2] = 'A' - 10 + (*cptr & 0xF);
                   15274: 
1.1.1.3 ! misho    15275:                xmlBufAdd(target, &escape[0], 3);
1.1       misho    15276:            }
                   15277:        }
                   15278:     }
                   15279:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
1.1.1.3 ! misho    15280:        xmlBufContent(target)));
        !          15281:     xmlBufFree(target);
1.1       misho    15282:     xmlXPathReleaseObject(ctxt->context, str);
                   15283: }
                   15284: 
                   15285: /**
                   15286:  * xmlXPathRegisterAllFunctions:
                   15287:  * @ctxt:  the XPath context
                   15288:  *
                   15289:  * Registers all default XPath functions in this context
                   15290:  */
                   15291: void
                   15292: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
                   15293: {
                   15294:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
                   15295:                          xmlXPathBooleanFunction);
                   15296:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
                   15297:                          xmlXPathCeilingFunction);
                   15298:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
                   15299:                          xmlXPathCountFunction);
                   15300:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
                   15301:                          xmlXPathConcatFunction);
                   15302:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
                   15303:                          xmlXPathContainsFunction);
                   15304:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
                   15305:                          xmlXPathIdFunction);
                   15306:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
                   15307:                          xmlXPathFalseFunction);
                   15308:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
                   15309:                          xmlXPathFloorFunction);
                   15310:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
                   15311:                          xmlXPathLastFunction);
                   15312:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
                   15313:                          xmlXPathLangFunction);
                   15314:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
                   15315:                          xmlXPathLocalNameFunction);
                   15316:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
                   15317:                          xmlXPathNotFunction);
                   15318:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
                   15319:                          xmlXPathNameFunction);
                   15320:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
                   15321:                          xmlXPathNamespaceURIFunction);
                   15322:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
                   15323:                          xmlXPathNormalizeFunction);
                   15324:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
                   15325:                          xmlXPathNumberFunction);
                   15326:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
                   15327:                          xmlXPathPositionFunction);
                   15328:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
                   15329:                          xmlXPathRoundFunction);
                   15330:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
                   15331:                          xmlXPathStringFunction);
                   15332:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
                   15333:                          xmlXPathStringLengthFunction);
                   15334:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
                   15335:                          xmlXPathStartsWithFunction);
                   15336:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
                   15337:                          xmlXPathSubstringFunction);
                   15338:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
                   15339:                          xmlXPathSubstringBeforeFunction);
                   15340:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
                   15341:                          xmlXPathSubstringAfterFunction);
                   15342:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
                   15343:                          xmlXPathSumFunction);
                   15344:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
                   15345:                          xmlXPathTrueFunction);
                   15346:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
                   15347:                          xmlXPathTranslateFunction);
                   15348: 
                   15349:     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
                   15350:         (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
                   15351:                          xmlXPathEscapeUriFunction);
                   15352: }
                   15353: 
                   15354: #endif /* LIBXML_XPATH_ENABLED */
                   15355: #define bottom_xpath
                   15356: #include "elfgcchack.h"

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