Annotation of XML/xpath.c, revision 1.76

1.1       daniel      1: /*
                      2:  * xpath.c: XML Path Language implementation
1.8       daniel      3:  *          XPath is a language for addressing parts of an XML document,
1.67      veillard    4:  *          designed to be used by both XSLT and XPointer
1.1       daniel      5:  *
1.67      veillard    6:  * Reference: W3C Recommendation 16 November 1999
                      7:  *     http://www.w3.org/TR/1999/REC-xpath-19991116
1.8       daniel      8:  * Public reference:
1.67      veillard    9:  *     http://www.w3.org/TR/xpath
1.1       daniel     10:  *
                     11:  * See COPYRIGHT for the status of this software
                     12:  *
                     13:  * Author: Daniel.Veillard@w3.org
                     14:  */
                     15: 
1.27      daniel     16: #ifdef WIN32
1.34      daniel     17: #include "win32config.h"
1.27      daniel     18: #else
1.28      daniel     19: #include "config.h"
1.27      daniel     20: #endif
                     21: 
1.72      veillard   22: #include <libxml/xmlversion.h>
1.45      daniel     23: #ifdef LIBXML_XPATH_ENABLED
                     24: 
1.27      daniel     25: #include <stdio.h>
                     26: #include <string.h>
                     27: 
                     28: #ifdef HAVE_SYS_TYPES_H
                     29: #include <sys/types.h>
                     30: #endif
1.12      daniel     31: #ifdef HAVE_MATH_H
1.5       daniel     32: #include <math.h>
1.12      daniel     33: #endif
1.13      daniel     34: #ifdef HAVE_MATH_H
                     35: #include <float.h>
                     36: #endif
1.12      daniel     37: #ifdef HAVE_IEEEFP_H
                     38: #include <ieeefp.h>
                     39: #endif
                     40: #ifdef HAVE_NAN_H
                     41: #include <nan.h>
                     42: #endif
1.27      daniel     43: #ifdef HAVE_CTYPE_H
1.19      daniel     44: #include <ctype.h>
1.27      daniel     45: #endif
                     46: 
1.45      daniel     47: #include <libxml/xmlmemory.h>
                     48: #include <libxml/tree.h>
                     49: #include <libxml/valid.h>
                     50: #include <libxml/xpath.h>
                     51: #include <libxml/parserInternals.h>
1.62      veillard   52: #ifdef LIBXML_XPTR_ENABLED
                     53: #include <libxml/xpointer.h>
                     54: #endif
1.76    ! veillard   55: #ifdef LIBXML_DEBUG_ENABLED
        !            56: #include <libxml/debugXML.h>
        !            57: #endif
1.1       daniel     58: 
1.53      veillard   59: /* #define DEBUG */
                     60: /* #define DEBUG_STEP */
                     61: /* #define DEBUG_EXPR */
1.35      daniel     62: 
1.76    ! veillard   63: void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
        !            64: double xmlXPathStringEvalNumber(const xmlChar *str);
        !            65: 
1.5       daniel     66: /*
1.10      daniel     67:  * Setup stuff for floating point
1.19      daniel     68:  * The lack of portability of this section of the libc is annoying !
1.5       daniel     69:  */
1.10      daniel     70: double xmlXPathNAN = 0;
                     71: double xmlXPathPINF = 1;
                     72: double xmlXPathMINF = -1;
1.12      daniel     73: 
                     74: #ifndef isinf
                     75: #ifndef HAVE_ISINF
1.13      daniel     76: 
                     77: #if HAVE_FPCLASS
                     78: 
                     79: int isinf(double d) {
                     80:     fpclass_t  type = fpclass(d);
                     81:     switch (type) {
                     82:        case FP_NINF:
                     83:            return(-1);
                     84:        case FP_PINF:
                     85:            return(1);
                     86:     }
                     87:     return(0);
                     88: }
                     89: 
                     90: #elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
                     91: 
                     92: #if HAVE_FP_CLASS_H
                     93: #include <fp_class.h>
                     94: #endif
                     95: 
                     96: int isinf(double d) {
                     97: #if HAVE_FP_CLASS
                     98:     int        fpclass = fp_class(d);
                     99: #else
                    100:     int        fpclass = fp_class_d(d);
                    101: #endif
                    102:     if (fpclass == FP_POS_INF)
                    103:        return(1);
                    104:     if (fpclass == FP_NEG_INF)
                    105:        return(-1);
                    106:     return(0);
                    107: }
                    108: 
                    109: #elif defined(HAVE_CLASS)
                    110: 
                    111: int isinf(double d) {
                    112:     int        fpclass = class(d);
                    113:     if (fpclass == FP_PLUS_INF)
                    114:        return(1);
                    115:     if (fpclass == FP_MINUS_INF)
                    116:        return(-1);
                    117:     return(0);
                    118: }
                    119: #elif defined(finite) || defined(HAVE_FINITE)
1.12      daniel    120: int isinf(double x) { return !finite(x) && x==x; }
1.19      daniel    121: #elif defined(HUGE_VAL)
1.46      daniel    122: int isinf(double x)
1.19      daniel    123: {
                    124:     if (x == HUGE_VAL)
                    125:         return(1);
                    126:     if (x == -HUGE_VAL)
                    127:         return(-1);
                    128:     return(0);
                    129: }
                    130: #endif 
1.13      daniel    131: 
1.12      daniel    132: #endif /* ! HAVE_ISINF */
                    133: #endif /* ! defined(isinf) */
                    134: 
                    135: #ifndef isnan
                    136: #ifndef HAVE_ISNAN
1.13      daniel    137: 
1.12      daniel    138: #ifdef HAVE_ISNAND
                    139: #define isnan(f) isnand(f)
                    140: #endif /* HAVE_iSNAND */
1.13      daniel    141: 
1.12      daniel    142: #endif /* ! HAVE_iSNAN */
                    143: #endif /* ! defined(isnan) */
1.10      daniel    144: 
                    145: /**
                    146:  * xmlXPathInit:
                    147:  *
                    148:  * Initialize the XPath environment
                    149:  */
                    150: void
                    151: xmlXPathInit(void) {
                    152:     static int initialized = 0;
                    153: 
                    154:     if (initialized) return;
                    155: 
                    156:     xmlXPathNAN = 0;
                    157:     xmlXPathNAN /= 0;
                    158: 
                    159:     xmlXPathPINF = 1;
                    160:     xmlXPathPINF /= 0;
                    161: 
                    162:     xmlXPathMINF = -1;
                    163:     xmlXPathMINF /= 0;
                    164: 
                    165:     initialized = 1;
                    166: }
1.5       daniel    167: 
1.1       daniel    168: /************************************************************************
                    169:  *                                                                     *
1.76    ! veillard  170:  *             Debugging related functions                             *
1.1       daniel    171:  *                                                                     *
                    172:  ************************************************************************/
                    173: 
1.76    ! veillard  174: FILE *xmlXPathDebug = NULL;
        !           175: 
1.71      veillard  176: #define TODO                                                           \
                    177:     fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n",           \
                    178:             __FILE__, __LINE__);
                    179: 
                    180: #define STRANGE                                                        \
                    181:     fprintf(xmlXPathDebug, "Internal error at %s:%d\n",                        \
                    182:             __FILE__, __LINE__);
1.76    ! veillard  183: 
        !           184: #ifdef LIBXML_DEBUG_ENABLED
        !           185: double xmlXPathStringEvalNumber(const xmlChar *str);
        !           186: void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
        !           187: 
        !           188: void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
        !           189:     int i;
        !           190:     char shift[100];
        !           191: 
        !           192:     for (i = 0;((i < depth) && (i < 25));i++)
        !           193:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           194:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           195:     if (cur == NULL) {
        !           196:        fprintf(output, shift);
        !           197:        fprintf(output, "Node is NULL !\n");
        !           198:        return;
        !           199:         
        !           200:     }
        !           201: 
        !           202:     if ((cur->type == XML_DOCUMENT_NODE) ||
        !           203:             (cur->type == XML_HTML_DOCUMENT_NODE)) {
        !           204:        fprintf(output, shift);
        !           205:        fprintf(output, " /\n");
        !           206:     } else if (cur->type == XML_ATTRIBUTE_NODE)
        !           207:        xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
        !           208:     else
        !           209:        xmlDebugDumpOneNode(output, cur, depth);
        !           210: }
        !           211: 
        !           212: void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
        !           213:     int i;
        !           214:     char shift[100];
        !           215: 
        !           216:     for (i = 0;((i < depth) && (i < 25));i++)
        !           217:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           218:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           219: 
        !           220:     if (cur == NULL) {
        !           221:        fprintf(output, shift);
        !           222:        fprintf(output, "NodeSet is NULL !\n");
        !           223:        return;
        !           224:         
        !           225:     }
        !           226: 
        !           227:     fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
        !           228:     for (i = 0;i < cur->nodeNr;i++) {
        !           229:        fprintf(output, shift);
        !           230:         fprintf(output, "%d", i + 1);
        !           231:        xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
        !           232:     }
        !           233: }
        !           234: 
        !           235: #if defined(LIBXML_XPTR_ENABLED)
        !           236: void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
        !           237: void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
        !           238:     int i;
        !           239:     char shift[100];
        !           240: 
        !           241:     for (i = 0;((i < depth) && (i < 25));i++)
        !           242:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           243:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           244: 
        !           245:     if (cur == NULL) {
        !           246:        fprintf(output, shift);
        !           247:        fprintf(output, "LocationSet is NULL !\n");
        !           248:        return;
        !           249:         
        !           250:     }
        !           251: 
        !           252:     for (i = 0;i < cur->locNr;i++) {
        !           253:        fprintf(output, shift);
        !           254:         fprintf(output, "%d : ", i + 1);
        !           255:        xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
        !           256:     }
        !           257: }
        !           258: #endif
        !           259: 
        !           260: void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
        !           261:     int i;
        !           262:     char shift[100];
        !           263: 
        !           264:     for (i = 0;((i < depth) && (i < 25));i++)
        !           265:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           266:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           267: 
        !           268:     fprintf(output, shift);
        !           269: 
        !           270:     if (cur == NULL) {
        !           271:         fprintf(output, "Object is empty (NULL)\n");
        !           272:        return;
        !           273:     }
        !           274:     switch(cur->type) {
        !           275:         case XPATH_UNDEFINED:
        !           276:            fprintf(output, "Object is uninitialized\n");
        !           277:            break;
        !           278:         case XPATH_NODESET:
        !           279:            fprintf(output, "Object is a Node Set :\n");
        !           280:            xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
        !           281:            break;
        !           282:         case XPATH_BOOLEAN:
        !           283:            fprintf(output, "Object is a Boolean : ");
        !           284:            if (cur->boolval) fprintf(output, "true\n");
        !           285:            else fprintf(output, "false\n");
        !           286:            break;
        !           287:         case XPATH_NUMBER:
        !           288:            fprintf(output, "Object is a number : %0g\n", cur->floatval);
        !           289:            break;
        !           290:         case XPATH_STRING:
        !           291:            fprintf(output, "Object is a string : ");
        !           292:            xmlDebugDumpString(output, cur->stringval);
        !           293:            fprintf(output, "\n");
        !           294:            break;
        !           295:        case XPATH_POINT:
        !           296:            fprintf(output, "Object is a point : index %d in node", cur->index);
        !           297:            xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
        !           298:            fprintf(output, "\n");
        !           299:            break;
        !           300:        case XPATH_RANGE:
        !           301:            if ((cur->user2 == NULL) ||
        !           302:                ((cur->user2 == cur->user) && (cur->index = cur->index2))) {
        !           303:                fprintf(output, "Object is a collapsed range :\n");
        !           304:                fprintf(output, shift);
        !           305:                if (cur->index >= 0)
        !           306:                    fprintf(output, "index %d in ", cur->index);
        !           307:                fprintf(output, "node\n");
        !           308:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
        !           309:                                      depth + 1);
        !           310:            } else  {
        !           311:                fprintf(output, "Object is a range :\n");
        !           312:                fprintf(output, shift);
        !           313:                fprintf(output, "From ");
        !           314:                if (cur->index >= 0)
        !           315:                    fprintf(output, "index %d in ", cur->index);
        !           316:                fprintf(output, "node\n");
        !           317:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
        !           318:                                      depth + 1);
        !           319:                fprintf(output, shift);
        !           320:                fprintf(output, "To ");
        !           321:                if (cur->index2 >= 0)
        !           322:                    fprintf(output, "index %d in ", cur->index2);
        !           323:                fprintf(output, "node\n");
        !           324:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
        !           325:                                      depth + 1);
        !           326:                fprintf(output, "\n");
        !           327:            }
        !           328:            break;
        !           329:        case XPATH_LOCATIONSET:
        !           330: #if defined(LIBXML_XPTR_ENABLED)
        !           331:            fprintf(output, "Object is a Location Set:\n");
        !           332:            xmlXPathDebugDumpLocationSet(output,
        !           333:                    (xmlLocationSetPtr) cur->user, depth);
        !           334: #endif
        !           335:            break;
        !           336:        case XPATH_USERS:
        !           337:            fprintf(output, "Object is user defined\n");
        !           338:            break;
        !           339:     }
        !           340: }
        !           341: #endif
        !           342: 
        !           343: /************************************************************************
        !           344:  *                                                                     *
        !           345:  *             Parser stacks related functions and macros              *
        !           346:  *                                                                     *
        !           347:  ************************************************************************/
1.71      veillard  348: 
1.1       daniel    349: /*
                    350:  * Generic function for accessing stacks in the Parser Context
                    351:  */
                    352: 
                    353: #define PUSH_AND_POP(type, name)                                       \
                    354: extern int name##Push(xmlXPathParserContextPtr ctxt, type value) {     \
                    355:     if (ctxt->name##Nr >= ctxt->name##Max) {                           \
                    356:        ctxt->name##Max *= 2;                                           \
1.50      veillard  357:         ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,         \
1.1       daniel    358:                     ctxt->name##Max * sizeof(ctxt->name##Tab[0]));     \
                    359:         if (ctxt->name##Tab == NULL) {                                 \
1.14      daniel    360:            fprintf(xmlXPathDebug, "realloc failed !\n");               \
1.36      daniel    361:            return(0);                                                  \
1.1       daniel    362:        }                                                               \
                    363:     }                                                                  \
                    364:     ctxt->name##Tab[ctxt->name##Nr] = value;                           \
                    365:     ctxt->name = value;                                                        \
                    366:     return(ctxt->name##Nr++);                                          \
                    367: }                                                                      \
                    368: extern type name##Pop(xmlXPathParserContextPtr ctxt) {                 \
                    369:     type ret;                                                          \
                    370:     if (ctxt->name##Nr <= 0) return(0);                                        \
                    371:     ctxt->name##Nr--;                                                  \
                    372:     if (ctxt->name##Nr > 0)                                            \
                    373:        ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];               \
                    374:     else                                                               \
                    375:         ctxt->name = NULL;                                             \
                    376:     ret = ctxt->name##Tab[ctxt->name##Nr];                             \
                    377:     ctxt->name##Tab[ctxt->name##Nr] = 0;                               \
                    378:     return(ret);                                                       \
                    379: }                                                                      \
                    380: 
                    381: PUSH_AND_POP(xmlXPathObjectPtr, value)
                    382: 
                    383: /*
                    384:  * Macros for accessing the content. Those should be used only by the parser,
                    385:  * and not exported.
                    386:  *
                    387:  * Dirty macros, i.e. one need to make assumption on the context to use them
                    388:  *
1.29      daniel    389:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
1.41      daniel    390:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
                    391:  *           in ISO-Latin or UTF-8.
                    392:  *           This should be used internally by the parser
1.1       daniel    393:  *           only to compare to ASCII values otherwise it would break when
                    394:  *           running with UTF-8 encoding.
1.29      daniel    395:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
1.1       daniel    396:  *           to compare on ASCII based substring.
1.29      daniel    397:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1.1       daniel    398:  *           strings within the parser.
                    399:  *   CURRENT Returns the current char value, with the full decoding of
                    400:  *           UTF-8 if we are using this mode. It returns an int.
                    401:  *   NEXT    Skip to the next character, this does the proper decoding
                    402:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
1.29      daniel    403:  *           It returns the pointer to the current xmlChar.
1.1       daniel    404:  */
                    405: 
                    406: #define CUR (*ctxt->cur)
                    407: #define SKIP(val) ctxt->cur += (val)
                    408: #define NXT(val) ctxt->cur[(val)]
                    409: #define CUR_PTR ctxt->cur
                    410: 
                    411: #define SKIP_BLANKS                                                    \
                    412:     while (IS_BLANK(*(ctxt->cur))) NEXT
                    413: 
                    414: #define CURRENT (*ctxt->cur)
                    415: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
                    416: 
                    417: /************************************************************************
                    418:  *                                                                     *
                    419:  *                     Error handling routines                         *
                    420:  *                                                                     *
                    421:  ************************************************************************/
                    422: 
1.4       daniel    423: 
                    424: const char *xmlXPathErrorMessages[] = {
                    425:     "Ok",
                    426:     "Number encoding",
                    427:     "Unfinished litteral",
                    428:     "Start of litteral",
                    429:     "Expected $ for variable reference",
                    430:     "Undefined variable",
                    431:     "Invalid predicate",
                    432:     "Invalid expression",
                    433:     "Missing closing curly brace",
                    434:     "Unregistered function",
1.5       daniel    435:     "Invalid operand",
1.8       daniel    436:     "Invalid type",
                    437:     "Invalid number of arguments",
1.57      veillard  438:     "Invalid context size",
                    439:     "Invalid context position",
1.72      veillard  440:     "Memory allocation error",
                    441:     "Syntax error",
                    442:     "Resource error",
                    443:     "Sub resource error"
1.4       daniel    444: };
                    445: 
                    446: /**
                    447:  * xmlXPathError:
                    448:  * @ctxt:  the XPath Parser context
                    449:  * @file:  the file name
                    450:  * @line:  the line number
                    451:  * @no:  the error number
                    452:  *
1.10      daniel    453:  * Create a new xmlNodeSetPtr of type double and of value @val
1.4       daniel    454:  *
                    455:  * Returns the newly created object.
                    456:  */
                    457: void
                    458: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
                    459:               int line, int no) {
                    460:     int n;
1.29      daniel    461:     const xmlChar *cur;
                    462:     const xmlChar *base;
1.4       daniel    463: 
1.9       daniel    464:     fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
1.4       daniel    465:             xmlXPathErrorMessages[no]);
                    466: 
                    467:     cur = ctxt->cur;
                    468:     base = ctxt->base;
                    469:     while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
                    470:        cur--;
                    471:     }
                    472:     n = 0;
                    473:     while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
                    474:         cur--;
                    475:     if ((*cur == '\n') || (*cur == '\r')) cur++;
                    476:     base = cur;
                    477:     n = 0;
                    478:     while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1.9       daniel    479:         fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
1.4       daniel    480:        n++;
                    481:     }
1.9       daniel    482:     fprintf(xmlXPathDebug, "\n");
1.4       daniel    483:     cur = ctxt->cur;
                    484:     while ((*cur == '\n') || (*cur == '\r'))
                    485:        cur--;
                    486:     n = 0;
                    487:     while ((cur != base) && (n++ < 80)) {
1.9       daniel    488:         fprintf(xmlXPathDebug, " ");
1.4       daniel    489:         base++;
                    490:     }
1.9       daniel    491:     fprintf(xmlXPathDebug,"^\n");
1.4       daniel    492: }
1.1       daniel    493: 
                    494: 
                    495: /************************************************************************
                    496:  *                                                                     *
                    497:  *                     Routines to handle NodeSets                     *
                    498:  *                                                                     *
                    499:  ************************************************************************/
                    500: 
                    501: #define XML_NODESET_DEFAULT    10
                    502: /**
                    503:  * xmlXPathNodeSetCreate:
                    504:  * @val:  an initial xmlNodePtr, or NULL
                    505:  *
1.10      daniel    506:  * Create a new xmlNodeSetPtr of type double and of value @val
1.1       daniel    507:  *
                    508:  * Returns the newly created object.
                    509:  */
                    510: xmlNodeSetPtr
                    511: xmlXPathNodeSetCreate(xmlNodePtr val) {
                    512:     xmlNodeSetPtr ret;
                    513: 
1.25      daniel    514:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1.1       daniel    515:     if (ret == NULL) {
1.9       daniel    516:         fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
1.1       daniel    517:        return(NULL);
                    518:     }
1.11      veillard  519:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1.1       daniel    520:     if (val != NULL) {
1.25      daniel    521:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1.1       daniel    522:                                             sizeof(xmlNodePtr));
                    523:        if (ret->nodeTab == NULL) {
1.9       daniel    524:            fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
1.1       daniel    525:            return(NULL);
                    526:        }
                    527:        memset(ret->nodeTab, 0 ,
1.11      veillard  528:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1.1       daniel    529:         ret->nodeMax = XML_NODESET_DEFAULT;
                    530:        ret->nodeTab[ret->nodeNr++] = val;
                    531:     }
                    532:     return(ret);
                    533: }
                    534: 
                    535: /**
                    536:  * xmlXPathNodeSetAdd:
                    537:  * @cur:  the initial node set
                    538:  * @val:  a new xmlNodePtr
                    539:  *
                    540:  * add a new xmlNodePtr ot an existing NodeSet
                    541:  */
                    542: void
                    543: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
                    544:     int i;
                    545: 
                    546:     if (val == NULL) return;
                    547: 
                    548:     /*
                    549:      * check against doublons
                    550:      */
                    551:     for (i = 0;i < cur->nodeNr;i++)
                    552:         if (cur->nodeTab[i] == val) return;
                    553: 
                    554:     /*
                    555:      * grow the nodeTab if needed
                    556:      */
                    557:     if (cur->nodeMax == 0) {
1.25      daniel    558:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1.1       daniel    559:                                             sizeof(xmlNodePtr));
                    560:        if (cur->nodeTab == NULL) {
1.9       daniel    561:            fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
1.1       daniel    562:            return;
                    563:        }
                    564:        memset(cur->nodeTab, 0 ,
1.11      veillard  565:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1.1       daniel    566:         cur->nodeMax = XML_NODESET_DEFAULT;
                    567:     } else if (cur->nodeNr == cur->nodeMax) {
                    568:         xmlNodePtr *temp;
                    569: 
                    570:         cur->nodeMax *= 2;
1.25      daniel    571:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1.1       daniel    572:                                      sizeof(xmlNodePtr));
                    573:        if (temp == NULL) {
1.9       daniel    574:            fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
1.1       daniel    575:            return;
                    576:        }
1.22      daniel    577:        cur->nodeTab = temp;
1.1       daniel    578:     }
                    579:     cur->nodeTab[cur->nodeNr++] = val;
                    580: }
                    581: 
                    582: /**
1.4       daniel    583:  * xmlXPathNodeSetMerge:
1.74      veillard  584:  * @val1:  the first NodeSet or NULL
1.4       daniel    585:  * @val2:  the second NodeSet
                    586:  *
                    587:  * Merges two nodesets, all nodes from @val2 are added to @val1
1.74      veillard  588:  * if @val1 is NULL, a new set is created and copied from @val2
1.4       daniel    589:  *
                    590:  * Returns val1 once extended or NULL in case of error.
                    591:  */
                    592: xmlNodeSetPtr
                    593: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
                    594:     int i;
                    595: 
                    596:     if (val2 == NULL) return(val1);
1.74      veillard  597:     if (val1 == NULL) {
                    598:        val1 = xmlXPathNodeSetCreate(NULL);
                    599:     }
1.4       daniel    600: 
                    601:     /*
1.6       daniel    602:      * !!!!! this can be optimized a lot, knowing that both
1.4       daniel    603:      *       val1 and val2 already have unicity of their values.
                    604:      */
                    605: 
                    606:     for (i = 0;i < val2->nodeNr;i++)
                    607:         xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
                    608: 
                    609:     return(val1);
                    610: }
                    611: 
                    612: /**
1.1       daniel    613:  * xmlXPathNodeSetDel:
                    614:  * @cur:  the initial node set
                    615:  * @val:  an xmlNodePtr
                    616:  *
                    617:  * Removes an xmlNodePtr from an existing NodeSet
                    618:  */
                    619: void
                    620: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
                    621:     int i;
                    622: 
1.5       daniel    623:     if (cur == NULL) return;
1.1       daniel    624:     if (val == NULL) return;
                    625: 
                    626:     /*
                    627:      * check against doublons
                    628:      */
                    629:     for (i = 0;i < cur->nodeNr;i++)
                    630:         if (cur->nodeTab[i] == val) break;
                    631: 
                    632:     if (i >= cur->nodeNr) {
                    633: #ifdef DEBUG
1.9       daniel    634:         fprintf(xmlXPathDebug, 
1.1       daniel    635:                "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
                    636:                val->name);
                    637: #endif
                    638:         return;
                    639:     }
                    640:     cur->nodeNr--;
                    641:     for (;i < cur->nodeNr;i++)
                    642:         cur->nodeTab[i] = cur->nodeTab[i + 1];
                    643:     cur->nodeTab[cur->nodeNr] = NULL;
                    644: }
                    645: 
                    646: /**
1.5       daniel    647:  * xmlXPathNodeSetRemove:
                    648:  * @cur:  the initial node set
                    649:  * @val:  the index to remove
                    650:  *
                    651:  * Removes an entry from an existing NodeSet list.
                    652:  */
                    653: void
                    654: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
                    655:     if (cur == NULL) return;
                    656:     if (val >= cur->nodeNr) return;
                    657:     cur->nodeNr--;
                    658:     for (;val < cur->nodeNr;val++)
                    659:         cur->nodeTab[val] = cur->nodeTab[val + 1];
                    660:     cur->nodeTab[cur->nodeNr] = NULL;
                    661: }
                    662: 
                    663: /**
1.1       daniel    664:  * xmlXPathFreeNodeSet:
                    665:  * @obj:  the xmlNodeSetPtr to free
                    666:  *
                    667:  * Free the NodeSet compound (not the actual nodes !).
                    668:  */
                    669: void
                    670: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
                    671:     if (obj == NULL) return;
                    672:     if (obj->nodeTab != NULL) {
                    673: #ifdef DEBUG
1.11      veillard  674:        memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
1.1       daniel    675: #endif
1.25      daniel    676:        xmlFree(obj->nodeTab);
1.1       daniel    677:     }
                    678: #ifdef DEBUG
1.11      veillard  679:     memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
1.1       daniel    680: #endif
1.25      daniel    681:     xmlFree(obj);
1.1       daniel    682: }
                    683: 
1.22      daniel    684: #if defined(DEBUG) || defined(DEBUG_STEP)
1.4       daniel    685: /**
                    686:  * xmlXPathDebugNodeSet:
                    687:  * @output:  a FILE * for the output
                    688:  * @obj:  the xmlNodeSetPtr to free
                    689:  *
                    690:  * Quick display of a NodeSet
                    691:  */
                    692: void
                    693: xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
                    694:     int i;
                    695: 
1.9       daniel    696:     if (output == NULL) output = xmlXPathDebug;
1.4       daniel    697:     if (obj == NULL)  {
                    698:         fprintf(output, "NodeSet == NULL !\n");
                    699:        return;
                    700:     }
                    701:     if (obj->nodeNr == 0) {
                    702:         fprintf(output, "NodeSet is empty\n");
                    703:        return;
                    704:     }
                    705:     if (obj->nodeTab == NULL) {
                    706:        fprintf(output, " nodeTab == NULL !\n");
                    707:        return;
                    708:     }
                    709:     for (i = 0; i < obj->nodeNr; i++) {
                    710:         if (obj->nodeTab[i] == NULL) {
                    711:            fprintf(output, " NULL !\n");
                    712:            return;
                    713:         }
1.32      daniel    714:        if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
                    715:            (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1.14      daniel    716:            fprintf(output, " /");
                    717:        else if (obj->nodeTab[i]->name == NULL)
1.4       daniel    718:            fprintf(output, " noname!");
                    719:        else fprintf(output, " %s", obj->nodeTab[i]->name);
                    720:     }
                    721:     fprintf(output, "\n");
                    722: }
                    723: #endif
                    724: 
1.21      daniel    725: /**
1.1       daniel    726:  * xmlXPathNewNodeSet:
                    727:  * @val:  the NodePtr value
                    728:  *
                    729:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
                    730:  * it with the single Node @val
                    731:  *
                    732:  * Returns the newly created object.
                    733:  */
                    734: xmlXPathObjectPtr
                    735: xmlXPathNewNodeSet(xmlNodePtr val) {
                    736:     xmlXPathObjectPtr ret;
                    737: 
1.25      daniel    738:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1.1       daniel    739:     if (ret == NULL) {
1.59      veillard  740:         fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
1.1       daniel    741:        return(NULL);
                    742:     }
1.11      veillard  743:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.1       daniel    744:     ret->type = XPATH_NODESET;
                    745:     ret->nodesetval = xmlXPathNodeSetCreate(val);
                    746:     return(ret);
                    747: }
                    748: 
                    749: /**
1.3       daniel    750:  * xmlXPathNewNodeSetList:
                    751:  * @val:  an existing NodeSet
                    752:  *
                    753:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
                    754:  * it with the Nodeset @val
                    755:  *
                    756:  * Returns the newly created object.
                    757:  */
                    758: xmlXPathObjectPtr
                    759: xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
                    760:     xmlXPathObjectPtr ret;
1.47      daniel    761:     int i;
1.3       daniel    762: 
1.48      daniel    763:     if (val == NULL)
                    764:        ret = NULL;
                    765:     else if (val->nodeTab == NULL)
1.47      daniel    766:            ret = xmlXPathNewNodeSet(NULL);
                    767:     else
                    768:        {
                    769:            ret = xmlXPathNewNodeSet(val->nodeTab[0]);
                    770:            for (i = 1; i < val->nodeNr; ++i)
                    771:                xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
1.48      daniel    772:            }
1.47      daniel    773: 
1.3       daniel    774:     return(ret);
                    775: }
                    776: 
                    777: /**
1.59      veillard  778:  * xmlXPathWrapNodeSet:
                    779:  * @val:  the NodePtr value
                    780:  *
                    781:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
                    782:  *
                    783:  * Returns the newly created object.
                    784:  */
                    785: xmlXPathObjectPtr
                    786: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
                    787:     xmlXPathObjectPtr ret;
                    788: 
                    789:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    790:     if (ret == NULL) {
                    791:         fprintf(xmlXPathDebug, "xmlXPathWrapNodeSet: out of memory\n");
                    792:        return(NULL);
                    793:     }
                    794:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    795:     ret->type = XPATH_NODESET;
                    796:     ret->nodesetval = val;
                    797:     return(ret);
                    798: }
                    799: 
                    800: /**
1.35      daniel    801:  * xmlXPathFreeNodeSetList:
                    802:  * @obj:  an existing NodeSetList object
                    803:  *
                    804:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
                    805:  * the list contrary to xmlXPathFreeObject().
                    806:  */
                    807: void
                    808: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
                    809:     if (obj == NULL) return;
                    810: #ifdef DEBUG
                    811:     memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
                    812: #endif
                    813:     xmlFree(obj);
                    814: }
                    815: 
1.71      veillard  816: /************************************************************************
                    817:  *                                                                     *
1.74      veillard  818:  *             Routines to handle extra functions                      *
                    819:  *                                                                     *
                    820:  ************************************************************************/
                    821: 
                    822: /**
                    823:  * xmlXPathRegisterFunc:
                    824:  * @ctxt:  the XPath context
                    825:  * @name:  the function name
                    826:  * @f:  the function implementation or NULL
                    827:  *
                    828:  * Register a new function. If @f is NULL it unregisters the function
                    829:  *
                    830:  * Returns 0 in case of success, -1 in case of error
                    831:  */
                    832: int              
                    833: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
                    834:                     xmlXPathFunction f) {
                    835:     int i;
                    836: 
                    837:     if (ctxt == NULL)
                    838:        return(-1);
                    839:     if (name == NULL)
                    840:        return(-1);
                    841: 
                    842:     for (i = 0;i < ctxt->nb_funcs;i++) {
1.75      veillard  843:        if (xmlStrEqual(ctxt->funcs[i].name, name)) {
1.74      veillard  844:            /*
                    845:             * It's just an update or a removal
                    846:             */
1.75      veillard  847:            ctxt->funcs[i].func = f;
1.74      veillard  848:            return(0);
                    849:        }
                    850:     }
                    851:     if (ctxt->max_funcs <= 0) {
                    852:        ctxt->max_funcs = 10;
                    853:        ctxt->nb_funcs = 0;
1.75      veillard  854:        ctxt->funcs = (xmlXPathFuncPtr) xmlMalloc(ctxt->max_funcs *
                    855:                                                    sizeof(xmlXPathFunct));
1.74      veillard  856:     } else if (ctxt->max_funcs <= ctxt->nb_funcs) {
                    857:        ctxt->max_funcs *= 2;
1.75      veillard  858:        ctxt->funcs = (xmlXPathFuncPtr) xmlRealloc(ctxt->funcs,
                    859:                                  ctxt->max_funcs * sizeof(xmlXPathFunct));
1.74      veillard  860:     }
                    861:     if (ctxt->funcs == NULL) {
                    862:         fprintf(xmlXPathDebug, "xmlXPathRegisterFunc: out of memory\n");
                    863:        return(-1);
                    864:     }
1.75      veillard  865:     ctxt->funcs[ctxt->nb_funcs].name = xmlStrdup(name);
                    866:     ctxt->funcs[ctxt->nb_funcs].func = f;
                    867:     ctxt->nb_funcs++;
1.74      veillard  868:     return(0);
                    869: }
                    870: 
                    871: /**
                    872:  * xmlXPathFunctionLookup:
                    873:  * @ctxt:  the XPath context
                    874:  * @name:  the function name
                    875:  *
                    876:  * Search in the Function array of the context for the given
                    877:  * function.
                    878:  *
                    879:  * Returns the xmlXPathFunction or NULL if not found
                    880:  */
                    881: xmlXPathFunction
                    882: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
                    883:     int i;
                    884: 
                    885:     if (ctxt == NULL)
                    886:        return(NULL);
                    887:     if (name == NULL)
                    888:        return(NULL);
                    889: 
                    890:     for (i = 0;i < ctxt->nb_funcs;i++) {
1.75      veillard  891:        if (xmlStrEqual(ctxt->funcs[i].name, name)) {
                    892:            return(ctxt->funcs[i].func);
1.74      veillard  893:        }
                    894:     }
                    895:     return(NULL);
                    896: }
                    897: 
                    898: /**
                    899:  * xmlXPathRegisteredFuncsCleanup:
                    900:  * @ctxt:  the XPath context
                    901:  *
                    902:  * Cleanup the XPath context data associated to registered functions
                    903:  */
                    904: void
                    905: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
                    906:     int i;
                    907: 
                    908:     if (ctxt == NULL)
                    909:        return;
                    910: 
                    911:     for (i = 0;i < ctxt->nb_funcs;i++) {
1.75      veillard  912:        xmlFree((xmlChar *) ctxt->funcs[i].name);
1.74      veillard  913:     }
                    914:     ctxt->nb_funcs = -1;
                    915:     ctxt->max_funcs = -1;
                    916:     if (ctxt->funcs != NULL)
                    917:        xmlFree(ctxt->funcs);
                    918:     ctxt->funcs = NULL;
                    919: }
                    920: 
                    921: /************************************************************************
                    922:  *                                                                     *
1.71      veillard  923:  *                     Routines to handle Variable                     *
                    924:  *                                                                     *
                    925:  ************************************************************************/
1.62      veillard  926: 
                    927: /**
1.74      veillard  928:  * xmlXPathRegisterVariable:
                    929:  * @ctxt:  the XPath context
                    930:  * @name:  the variable name
                    931:  * @value:  the variable value or NULL
                    932:  *
                    933:  * Register a new variable value. If @value is NULL it unregisters
                    934:  * the variable
                    935:  *
                    936:  * Returns 0 in case of success, -1 in case of error
                    937:  */
                    938: int              
                    939: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
                    940:                         xmlXPathObjectPtr value) {
                    941:     int i;
                    942: 
                    943:     if (ctxt == NULL)
                    944:        return(-1);
                    945:     if (name == NULL)
                    946:        return(-1);
                    947: 
                    948:     for (i = 0;i < ctxt->nb_variables;i++) {
1.75      veillard  949:        if (xmlStrEqual(ctxt->variables[i].name, name)) {
1.74      veillard  950:            /*
                    951:             * It's just an update or a removal
                    952:             */
1.75      veillard  953:            if (ctxt->variables[i].value != NULL) {
                    954:                xmlXPathFreeObject(ctxt->variables[i].value);
1.74      veillard  955:            }
1.75      veillard  956:            ctxt->variables[i].value = xmlXPathObjectCopy(value);
1.74      veillard  957:            return(0);
                    958:        }
                    959:     }
                    960:     if (ctxt->max_variables <= 0) {
                    961:        ctxt->max_variables = 10;
                    962:        ctxt->nb_variables = 0;
1.75      veillard  963:        ctxt->variables = (xmlXPathVariablePtr)
                    964:            xmlMalloc(ctxt->max_variables * sizeof(xmlXPathVariable));
1.74      veillard  965:     } else if (ctxt->max_variables <= ctxt->nb_variables) {
                    966:        ctxt->max_variables *= 2;
1.75      veillard  967:        ctxt->variables = (xmlXPathVariablePtr)
1.74      veillard  968:            xmlRealloc(ctxt->variables,
1.75      veillard  969:                       ctxt->max_variables * sizeof(xmlXPathVariable));
1.74      veillard  970:     }
                    971:     if (ctxt->variables == NULL) {
                    972:         fprintf(xmlXPathDebug, "xmlXPathRegisterVariable: out of memory\n");
                    973:        return(-1);
                    974:     }
1.75      veillard  975:     ctxt->variables[ctxt->nb_variables].name = xmlStrdup(name);
                    976:     ctxt->variables[ctxt->nb_variables].value = xmlXPathObjectCopy(value);
                    977:     ctxt->nb_variables++;
1.74      veillard  978:     return(0);
                    979: }
                    980: 
                    981: /**
                    982:  * xmlXPathVariableLookup:
                    983:  * @ctxt:  the XPath context
1.71      veillard  984:  * @name:  the variable name
1.62      veillard  985:  *
1.71      veillard  986:  * Search in the Variable array of the context for the given
                    987:  * variable value.
1.62      veillard  988:  *
1.71      veillard  989:  * Returns the value or NULL if not found
1.62      veillard  990:  */
                    991: xmlXPathObjectPtr
1.74      veillard  992: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
                    993:     int i;
                    994: 
                    995:     if (ctxt == NULL)
                    996:        return(NULL);
                    997:     if (name == NULL)
                    998:        return(NULL);
                    999: 
                   1000:     for (i = 0;i < ctxt->nb_variables;i++) {
1.75      veillard 1001:        if (xmlStrEqual(ctxt->variables[i].name, name)) {
                   1002:            return(xmlXPathObjectCopy(ctxt->variables[i].value));
1.74      veillard 1003:        }
                   1004:     }
1.71      veillard 1005:     return(NULL);
1.62      veillard 1006: }
                   1007: 
1.74      veillard 1008: /**
                   1009:  * xmlXPathRegisteredVariablesCleanup:
                   1010:  * @ctxt:  the XPath context
                   1011:  *
                   1012:  * Cleanup the XPath context data associated to registered variables
                   1013:  */
                   1014: void
                   1015: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
                   1016:     int i;
                   1017: 
                   1018:     if (ctxt == NULL)
                   1019:        return;
                   1020: 
                   1021:     for (i = 0;i < ctxt->nb_variables;i++) {
1.75      veillard 1022:        xmlFree((xmlChar *) ctxt->variables[i].name);
                   1023:        xmlXPathFreeObject(ctxt->variables[i].value);
1.74      veillard 1024:     }
                   1025:     ctxt->nb_variables = -1;
                   1026:     ctxt->max_variables = -1;
                   1027:     if (ctxt->variables != NULL)
                   1028:        xmlFree(ctxt->variables);
                   1029:     ctxt->variables = NULL;
                   1030: }
                   1031: 
1.71      veillard 1032: /************************************************************************
                   1033:  *                                                                     *
                   1034:  *                     Routines to handle Values                       *
                   1035:  *                                                                     *
                   1036:  ************************************************************************/
1.62      veillard 1037: 
1.71      veillard 1038: /* Allocations are terrible, one need to optimize all this !!! */
1.62      veillard 1039: 
                   1040: /**
1.71      veillard 1041:  * xmlXPathNewFloat:
                   1042:  * @val:  the double value
1.62      veillard 1043:  *
1.71      veillard 1044:  * Create a new xmlXPathObjectPtr of type double and of value @val
1.62      veillard 1045:  *
                   1046:  * Returns the newly created object.
                   1047:  */
                   1048: xmlXPathObjectPtr
1.71      veillard 1049: xmlXPathNewFloat(double val) {
1.62      veillard 1050:     xmlXPathObjectPtr ret;
                   1051: 
                   1052:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   1053:     if (ret == NULL) {
1.71      veillard 1054:         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
1.62      veillard 1055:        return(NULL);
                   1056:     }
                   1057:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71      veillard 1058:     ret->type = XPATH_NUMBER;
                   1059:     ret->floatval = val;
1.62      veillard 1060:     return(ret);
                   1061: }
                   1062: 
                   1063: /**
1.71      veillard 1064:  * xmlXPathNewBoolean:
                   1065:  * @val:  the boolean value
1.62      veillard 1066:  *
1.71      veillard 1067:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
1.62      veillard 1068:  *
                   1069:  * Returns the newly created object.
                   1070:  */
                   1071: xmlXPathObjectPtr
1.71      veillard 1072: xmlXPathNewBoolean(int val) {
1.62      veillard 1073:     xmlXPathObjectPtr ret;
                   1074: 
                   1075:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   1076:     if (ret == NULL) {
1.71      veillard 1077:         fprintf(xmlXPathDebug, "xmlXPathNewBoolean: out of memory\n");
1.62      veillard 1078:        return(NULL);
                   1079:     }
                   1080:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71      veillard 1081:     ret->type = XPATH_BOOLEAN;
                   1082:     ret->boolval = (val != 0);
1.62      veillard 1083:     return(ret);
                   1084: }
                   1085: 
                   1086: /**
1.71      veillard 1087:  * xmlXPathNewString:
                   1088:  * @val:  the xmlChar * value
1.62      veillard 1089:  *
1.71      veillard 1090:  * Create a new xmlXPathObjectPtr of type string and of value @val
1.62      veillard 1091:  *
                   1092:  * Returns the newly created object.
                   1093:  */
                   1094: xmlXPathObjectPtr
1.71      veillard 1095: xmlXPathNewString(const xmlChar *val) {
1.62      veillard 1096:     xmlXPathObjectPtr ret;
                   1097: 
                   1098:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   1099:     if (ret == NULL) {
1.71      veillard 1100:         fprintf(xmlXPathDebug, "xmlXPathNewString: out of memory\n");
1.62      veillard 1101:        return(NULL);
                   1102:     }
                   1103:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71      veillard 1104:     ret->type = XPATH_STRING;
                   1105:     ret->stringval = xmlStrdup(val);
1.62      veillard 1106:     return(ret);
                   1107: }
                   1108: 
                   1109: /**
1.71      veillard 1110:  * xmlXPathNewCString:
                   1111:  * @val:  the char * value
1.62      veillard 1112:  *
1.71      veillard 1113:  * Create a new xmlXPathObjectPtr of type string and of value @val
1.62      veillard 1114:  *
                   1115:  * Returns the newly created object.
                   1116:  */
                   1117: xmlXPathObjectPtr
1.71      veillard 1118: xmlXPathNewCString(const char *val) {
1.62      veillard 1119:     xmlXPathObjectPtr ret;
                   1120: 
                   1121:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   1122:     if (ret == NULL) {
1.71      veillard 1123:         fprintf(xmlXPathDebug, "xmlXPathNewCString: out of memory\n");
1.62      veillard 1124:        return(NULL);
                   1125:     }
                   1126:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71      veillard 1127:     ret->type = XPATH_STRING;
                   1128:     ret->stringval = xmlStrdup(BAD_CAST val);
1.62      veillard 1129:     return(ret);
                   1130: }
                   1131: 
1.35      daniel   1132: /**
1.74      veillard 1133:  * xmlXPathObjectCopy:
                   1134:  * @val:  the original object
                   1135:  *
                   1136:  * allocate a new copy of a given object
                   1137:  *
                   1138:  * Returns the newly created object.
                   1139:  */
                   1140: xmlXPathObjectPtr
                   1141: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
                   1142:     xmlXPathObjectPtr ret;
                   1143: 
                   1144:     if (val == NULL)
                   1145:        return(NULL);
                   1146: 
                   1147:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                   1148:     if (ret == NULL) {
                   1149:         fprintf(xmlXPathDebug, "xmlXPathObjectCopy: out of memory\n");
                   1150:        return(NULL);
                   1151:     }
                   1152:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
                   1153:     switch (val->type) {
                   1154:        case XPATH_BOOLEAN:
                   1155:        case XPATH_NUMBER:
                   1156:        case XPATH_STRING:
                   1157:        case XPATH_POINT:
                   1158:        case XPATH_RANGE:
                   1159:            break;
                   1160:        case XPATH_NODESET:
                   1161:            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
                   1162:            break;
                   1163:        case XPATH_LOCATIONSET:
                   1164: #ifdef LIBXML_XPTR_ENABLED
                   1165:        {
                   1166:            xmlLocationSetPtr loc = val->user;
                   1167:            ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
                   1168:            break;
                   1169:        }
                   1170: #endif
                   1171:        case XPATH_UNDEFINED:
                   1172:        case XPATH_USERS:
                   1173:            fprintf(xmlXPathDebug, "xmlXPathObjectCopy: unsupported type %d\n",
                   1174:                    val->type);
                   1175:     }
                   1176:     return(ret);
                   1177: }
                   1178: 
                   1179: /**
1.1       daniel   1180:  * xmlXPathFreeObject:
                   1181:  * @obj:  the object to free
                   1182:  *
                   1183:  * Free up an xmlXPathObjectPtr object.
                   1184:  */
                   1185: void
                   1186: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
                   1187:     if (obj == NULL) return;
1.62      veillard 1188:     if (obj->type == XPATH_NODESET) {
                   1189:        if (obj->nodesetval != NULL)
                   1190:            xmlXPathFreeNodeSet(obj->nodesetval);
1.72      veillard 1191: #ifdef LIBXML_XPTR_ENABLED
1.70      veillard 1192:     } else if (obj->type == XPATH_LOCATIONSET) {
                   1193:        if (obj->user != NULL)
1.73      veillard 1194:            xmlXPtrFreeLocationSet(obj->user);
1.72      veillard 1195: #endif
1.62      veillard 1196:     } else if (obj->type == XPATH_STRING) {
                   1197:        if (obj->stringval != NULL)
                   1198:            xmlFree(obj->stringval);
                   1199:     }
                   1200: 
1.1       daniel   1201: #ifdef DEBUG
1.11      veillard 1202:     memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1.1       daniel   1203: #endif
1.25      daniel   1204:     xmlFree(obj);
1.1       daniel   1205: }
                   1206: 
                   1207: /************************************************************************
                   1208:  *                                                                     *
                   1209:  *             Routines to handle XPath contexts                       *
                   1210:  *                                                                     *
                   1211:  ************************************************************************/
                   1212: 
                   1213: /**
                   1214:  * xmlXPathNewContext:
1.2       daniel   1215:  * @doc:  the XML document
1.1       daniel   1216:  *
                   1217:  * Create a new xmlXPathContext
                   1218:  *
                   1219:  * Returns the xmlXPathContext just allocated.
                   1220:  */
                   1221: xmlXPathContextPtr
1.26      daniel   1222: xmlXPathNewContext(xmlDocPtr doc) {
1.1       daniel   1223:     xmlXPathContextPtr ret;
                   1224: 
1.25      daniel   1225:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
1.1       daniel   1226:     if (ret == NULL) {
1.9       daniel   1227:         fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
1.1       daniel   1228:        return(NULL);
                   1229:     }
1.11      veillard 1230:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
1.2       daniel   1231:     ret->doc = doc;
1.35      daniel   1232:     ret->node = NULL;
1.26      daniel   1233: 
                   1234:     ret->nb_variables = 0;
                   1235:     ret->max_variables = 0;
                   1236:     ret->variables = NULL;
                   1237: 
                   1238:     ret->nb_types = 0;
                   1239:     ret->max_types = 0;
                   1240:     ret->types = NULL;
                   1241: 
                   1242:     ret->nb_funcs = 0;
                   1243:     ret->max_funcs = 0;
                   1244:     ret->funcs = NULL;
                   1245: 
                   1246:     ret->nb_axis = 0;
                   1247:     ret->max_axis = 0;
                   1248:     ret->axis = NULL;
                   1249: 
1.19      daniel   1250:     ret->namespaces = NULL;
1.26      daniel   1251:     ret->user = NULL;
1.19      daniel   1252:     ret->nsNr = 0;
1.57      veillard 1253: 
                   1254:     ret->contextSize = -1;
                   1255:     ret->proximityPosition = -1;
1.1       daniel   1256:     return(ret);
                   1257: }
                   1258: 
                   1259: /**
                   1260:  * xmlXPathFreeContext:
                   1261:  * @ctxt:  the context to free
                   1262:  *
                   1263:  * Free up an xmlXPathContext
                   1264:  */
                   1265: void
                   1266: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
1.19      daniel   1267:     if (ctxt->namespaces != NULL)
1.25      daniel   1268:         xmlFree(ctxt->namespaces);
1.19      daniel   1269: 
1.74      veillard 1270:     xmlXPathRegisteredFuncsCleanup(ctxt);
                   1271:     xmlXPathRegisteredVariablesCleanup(ctxt);
1.1       daniel   1272: #ifdef DEBUG
1.11      veillard 1273:     memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
1.1       daniel   1274: #endif
1.25      daniel   1275:     xmlFree(ctxt);
1.1       daniel   1276: }
                   1277: 
                   1278: /************************************************************************
                   1279:  *                                                                     *
                   1280:  *             Routines to handle XPath parser contexts                *
                   1281:  *                                                                     *
                   1282:  ************************************************************************/
                   1283: 
1.59      veillard 1284: #define CHECK_CTXT(ctxt)                                               \
1.2       daniel   1285:     if (ctxt == NULL) {                                                \
1.9       daniel   1286:         fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
1.2       daniel   1287:                __FILE__, __LINE__);                                    \
                   1288:     }                                                                  \
                   1289: 
                   1290: 
1.59      veillard 1291: #define CHECK_CONTEXT(ctxt)                                            \
1.2       daniel   1292:     if (ctxt == NULL) {                                                \
1.9       daniel   1293:         fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n",   \
1.2       daniel   1294:                __FILE__, __LINE__);                                    \
                   1295:     }                                                                  \
                   1296:     if (ctxt->doc == NULL) {                                           \
1.9       daniel   1297:         fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n",  \
1.2       daniel   1298:                __FILE__, __LINE__);                                    \
                   1299:     }                                                                  \
1.42      daniel   1300:     if (ctxt->doc->children == NULL) {                                         \
1.9       daniel   1301:         fprintf(xmlXPathDebug,                                         \
                   1302:                "%s:%d Internal error: document without root\n",        \
1.2       daniel   1303:                __FILE__, __LINE__);                                    \
                   1304:     }                                                                  \
                   1305: 
                   1306: 
1.1       daniel   1307: /**
                   1308:  * xmlXPathNewParserContext:
                   1309:  * @str:  the XPath expression
                   1310:  * @ctxt:  the XPath context
                   1311:  *
                   1312:  * Create a new xmlXPathParserContext
                   1313:  *
                   1314:  * Returns the xmlXPathParserContext just allocated.
                   1315:  */
                   1316: xmlXPathParserContextPtr
1.29      daniel   1317: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
1.1       daniel   1318:     xmlXPathParserContextPtr ret;
                   1319: 
1.25      daniel   1320:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
1.1       daniel   1321:     if (ret == NULL) {
1.9       daniel   1322:         fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
1.1       daniel   1323:        return(NULL);
                   1324:     }
1.11      veillard 1325:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
1.1       daniel   1326:     ret->cur = ret->base = str;
                   1327:     ret->context = ctxt;
                   1328: 
                   1329:     /* Allocate the value stack */
                   1330:     ret->valueTab = (xmlXPathObjectPtr *) 
1.25      daniel   1331:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1.1       daniel   1332:     ret->valueNr = 0;
                   1333:     ret->valueMax = 10;
                   1334:     ret->value = NULL;
                   1335:     return(ret);
                   1336: }
                   1337: 
                   1338: /**
                   1339:  * xmlXPathFreeParserContext:
                   1340:  * @ctxt:  the context to free
                   1341:  *
                   1342:  * Free up an xmlXPathParserContext
                   1343:  */
                   1344: void
                   1345: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
                   1346:     if (ctxt->valueTab != NULL) {
                   1347: #ifdef DEBUG
1.11      veillard 1348:         memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
1.1       daniel   1349: #endif
1.25      daniel   1350:         xmlFree(ctxt->valueTab);
1.1       daniel   1351:     }
                   1352: #ifdef DEBUG
1.11      veillard 1353:     memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
1.1       daniel   1354: #endif
1.25      daniel   1355:     xmlFree(ctxt);
1.1       daniel   1356: }
                   1357: 
                   1358: /************************************************************************
                   1359:  *                                                                     *
                   1360:  *             The implicit core function library                      *
                   1361:  *                                                                     *
                   1362:  ************************************************************************/
                   1363: 
1.3       daniel   1364: /*
1.6       daniel   1365:  * Auto-pop and cast to a number
                   1366:  */
1.8       daniel   1367: void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1368: 
1.6       daniel   1369: 
                   1370: #define POP_FLOAT                                              \
                   1371:     arg = valuePop(ctxt);                                      \
                   1372:     if (arg == NULL) {                                         \
1.49      daniel   1373:        XP_ERROR(XPATH_INVALID_OPERAND);                                \
1.6       daniel   1374:     }                                                          \
                   1375:     if (arg->type != XPATH_NUMBER) {                           \
                   1376:         valuePush(ctxt, arg);                                  \
1.10      daniel   1377:         xmlXPathNumberFunction(ctxt, 1);                       \
1.6       daniel   1378:        arg = valuePop(ctxt);                                   \
                   1379:     }
                   1380: 
1.1       daniel   1381: /**
1.18      daniel   1382:  * xmlXPathEqualNodeSetString
                   1383:  * @arg:  the nodeset object argument
                   1384:  * @str:  the string to compare to.
                   1385:  *
                   1386:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   1387:  * If one object to be compared is a node-set and the other is a string,
                   1388:  * then the comparison will be true if and only if there is a node in
                   1389:  * the node-set such that the result of performing the comparison on the
                   1390:  * string-value of the node and the other string is true.
                   1391:  *
                   1392:  * Returns 0 or 1 depending on the results of the test.
                   1393:  */
                   1394: int
1.29      daniel   1395: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
1.18      daniel   1396:     int i;
                   1397:     xmlNodeSetPtr ns;
1.29      daniel   1398:     xmlChar *str2;
1.18      daniel   1399: 
                   1400:     if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
                   1401:         return(0);
                   1402:     ns = arg->nodesetval;
                   1403:     for (i = 0;i < ns->nodeNr;i++) {
                   1404:          str2 = xmlNodeGetContent(ns->nodeTab[i]);
1.58      veillard 1405:         if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
1.25      daniel   1406:             xmlFree(str2);
1.18      daniel   1407:             return(1);
                   1408:         }
1.25      daniel   1409:         xmlFree(str2);
1.18      daniel   1410:     }
                   1411:     return(0);
                   1412: }
                   1413: 
                   1414: /**
                   1415:  * xmlXPathEqualNodeSetFloat
                   1416:  * @arg:  the nodeset object argument
                   1417:  * @f:  the float to compare to
                   1418:  *
                   1419:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   1420:  * If one object to be compared is a node-set and the other is a number,
                   1421:  * then the comparison will be true if and only if there is a node in
                   1422:  * the node-set such that the result of performing the comparison on the
                   1423:  * number to be compared and on the result of converting the string-value
                   1424:  * of that node to a number using the number function is true.
                   1425:  *
                   1426:  * Returns 0 or 1 depending on the results of the test.
                   1427:  */
                   1428: int
                   1429: xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
1.21      daniel   1430:     char buf[100] = "";
1.18      daniel   1431: 
                   1432:     if ((arg == NULL) || (arg->type != XPATH_NODESET))
                   1433:         return(0);
                   1434: 
                   1435:     if (isnan(f))
                   1436:        sprintf(buf, "NaN");
                   1437:     else if (isinf(f) > 0)
                   1438:        sprintf(buf, "+Infinity");
                   1439:     else if (isinf(f) < 0)
                   1440:        sprintf(buf, "-Infinity");
                   1441:     else
                   1442:        sprintf(buf, "%0g", f);
                   1443: 
1.21      daniel   1444:     return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
1.18      daniel   1445: }
                   1446: 
                   1447: 
                   1448: /**
                   1449:  * xmlXPathEqualNodeSets
                   1450:  * @arg1:  first nodeset object argument
                   1451:  * @arg2:  second nodeset object argument
                   1452:  *
                   1453:  * Implement the equal operation on XPath nodesets: @arg1 == @arg2
                   1454:  * If both objects to be compared are node-sets, then the comparison
                   1455:  * will be true if and only if there is a node in the first node-set and
                   1456:  * a node in the second node-set such that the result of performing the
                   1457:  * comparison on the string-values of the two nodes is true.
                   1458:  *
                   1459:  * (needless to say, this is a costly operation)
                   1460:  *
                   1461:  * Returns 0 or 1 depending on the results of the test.
                   1462:  */
                   1463: int
                   1464: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
                   1465:     int i;
                   1466:     xmlNodeSetPtr ns;
1.29      daniel   1467:     xmlChar *str;
1.18      daniel   1468: 
                   1469:     if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
                   1470:         return(0);
                   1471:     if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
                   1472:         return(0);
                   1473: 
                   1474:     ns = arg1->nodesetval;
                   1475:     for (i = 0;i < ns->nodeNr;i++) {
                   1476:          str = xmlNodeGetContent(ns->nodeTab[i]);
                   1477:         if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
1.25      daniel   1478:             xmlFree(str);
1.18      daniel   1479:             return(1);
                   1480:         }
1.25      daniel   1481:         xmlFree(str);
1.18      daniel   1482:     }
                   1483:     return(0);
                   1484: }
                   1485: 
                   1486: /**
1.1       daniel   1487:  * xmlXPathEqualValues:
1.18      daniel   1488:  * @ctxt:  the XPath Parser context
1.1       daniel   1489:  *
                   1490:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
                   1491:  *
                   1492:  * Returns 0 or 1 depending on the results of the test.
                   1493:  */
                   1494: int
1.18      daniel   1495: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
                   1496:     xmlXPathObjectPtr arg1, arg2;
                   1497:     int ret = 0;
                   1498: 
                   1499:     arg1 = valuePop(ctxt);
                   1500:     if (arg1 == NULL)
1.49      daniel   1501:        XP_ERROR0(XPATH_INVALID_OPERAND);
1.18      daniel   1502: 
                   1503:     arg2 = valuePop(ctxt);
                   1504:     if (arg2 == NULL) {
                   1505:        xmlXPathFreeObject(arg1);
1.49      daniel   1506:        XP_ERROR0(XPATH_INVALID_OPERAND);
1.18      daniel   1507:     }
                   1508:   
1.5       daniel   1509:     if (arg1 == arg2) {
                   1510: #ifdef DEBUG_EXPR
1.9       daniel   1511:         fprintf(xmlXPathDebug, "Equal: by pointer\n");
1.5       daniel   1512: #endif
                   1513:         return(1);
                   1514:     }
1.18      daniel   1515: 
1.3       daniel   1516:     switch (arg1->type) {
                   1517:         case XPATH_UNDEFINED:
1.5       daniel   1518: #ifdef DEBUG_EXPR
1.9       daniel   1519:            fprintf(xmlXPathDebug, "Equal: undefined\n");
1.5       daniel   1520: #endif
1.18      daniel   1521:            break;
1.3       daniel   1522:         case XPATH_NODESET:
1.18      daniel   1523:            switch (arg2->type) {
                   1524:                case XPATH_UNDEFINED:
                   1525: #ifdef DEBUG_EXPR
                   1526:                    fprintf(xmlXPathDebug, "Equal: undefined\n");
                   1527: #endif
                   1528:                    break;
                   1529:                case XPATH_NODESET:
                   1530:                    ret = xmlXPathEqualNodeSets(arg1, arg2);
                   1531:                    break;
                   1532:                case XPATH_BOOLEAN:
                   1533:                    if ((arg1->nodesetval == NULL) ||
                   1534:                        (arg1->nodesetval->nodeNr == 0)) ret = 0;
                   1535:                    else 
                   1536:                        ret = 1;
                   1537:                    ret = (ret == arg2->boolval);
                   1538:                    break;
                   1539:                case XPATH_NUMBER:
                   1540:                    ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
                   1541:                    break;
                   1542:                case XPATH_STRING:
                   1543:                    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
                   1544:                    break;
1.59      veillard 1545:                case XPATH_USERS:
1.62      veillard 1546:                case XPATH_POINT:
                   1547:                case XPATH_RANGE:
1.63      veillard 1548:                case XPATH_LOCATIONSET:
1.59      veillard 1549:                    TODO
                   1550:                    break;
1.18      daniel   1551:            }
1.3       daniel   1552:            break;
                   1553:         case XPATH_BOOLEAN:
1.18      daniel   1554:            switch (arg2->type) {
                   1555:                case XPATH_UNDEFINED:
1.5       daniel   1556: #ifdef DEBUG_EXPR
1.18      daniel   1557:                    fprintf(xmlXPathDebug, "Equal: undefined\n");
1.5       daniel   1558: #endif
1.18      daniel   1559:                    break;
                   1560:                case XPATH_NODESET:
                   1561:                    if ((arg2->nodesetval == NULL) ||
                   1562:                        (arg2->nodesetval->nodeNr == 0)) ret = 0;
                   1563:                    else 
                   1564:                        ret = 1;
                   1565:                    break;
                   1566:                case XPATH_BOOLEAN:
                   1567: #ifdef DEBUG_EXPR
                   1568:                    fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
                   1569:                            arg1->boolval, arg2->boolval);
                   1570: #endif
                   1571:                    ret = (arg1->boolval == arg2->boolval);
                   1572:                    break;
                   1573:                case XPATH_NUMBER:
                   1574:                    if (arg2->floatval) ret = 1;
                   1575:                    else ret = 0;
                   1576:                    ret = (arg1->boolval == ret);
                   1577:                    break;
                   1578:                case XPATH_STRING:
                   1579:                    if ((arg2->stringval == NULL) ||
                   1580:                        (arg2->stringval[0] == 0)) ret = 0;
                   1581:                    else 
                   1582:                        ret = 1;
                   1583:                    ret = (arg1->boolval == ret);
                   1584:                    break;
1.59      veillard 1585:                case XPATH_USERS:
1.62      veillard 1586:                case XPATH_POINT:
                   1587:                case XPATH_RANGE:
1.63      veillard 1588:                case XPATH_LOCATIONSET:
1.59      veillard 1589:                    TODO
                   1590:                    break;
1.18      daniel   1591:            }
                   1592:            break;
1.3       daniel   1593:         case XPATH_NUMBER:
1.18      daniel   1594:            switch (arg2->type) {
                   1595:                case XPATH_UNDEFINED:
1.5       daniel   1596: #ifdef DEBUG_EXPR
1.18      daniel   1597:                    fprintf(xmlXPathDebug, "Equal: undefined\n");
1.5       daniel   1598: #endif
1.18      daniel   1599:                    break;
                   1600:                case XPATH_NODESET:
                   1601:                    ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
                   1602:                    break;
                   1603:                case XPATH_BOOLEAN:
                   1604:                    if (arg1->floatval) ret = 1;
                   1605:                    else ret = 0;
                   1606:                    ret = (arg2->boolval == ret);
                   1607:                    break;
                   1608:                case XPATH_STRING:
                   1609:                    valuePush(ctxt, arg2);
                   1610:                    xmlXPathNumberFunction(ctxt, 1);
                   1611:                    arg2 = valuePop(ctxt);
                   1612:                    /* no break on purpose */
                   1613:                case XPATH_NUMBER:
                   1614:                    ret = (arg1->floatval == arg2->floatval);
                   1615:                    break;
1.59      veillard 1616:                case XPATH_USERS:
1.62      veillard 1617:                case XPATH_POINT:
                   1618:                case XPATH_RANGE:
1.63      veillard 1619:                case XPATH_LOCATIONSET:
1.59      veillard 1620:                    TODO
                   1621:                    break;
1.18      daniel   1622:            }
                   1623:            break;
1.3       daniel   1624:         case XPATH_STRING:
1.18      daniel   1625:            switch (arg2->type) {
                   1626:                case XPATH_UNDEFINED:
                   1627: #ifdef DEBUG_EXPR
                   1628:                    fprintf(xmlXPathDebug, "Equal: undefined\n");
                   1629: #endif
                   1630:                    break;
                   1631:                case XPATH_NODESET:
                   1632:                    ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
                   1633:                    break;
                   1634:                case XPATH_BOOLEAN:
                   1635:                    if ((arg1->stringval == NULL) ||
                   1636:                        (arg1->stringval[0] == 0)) ret = 0;
                   1637:                    else 
                   1638:                        ret = 1;
                   1639:                    ret = (arg2->boolval == ret);
                   1640:                    break;
                   1641:                case XPATH_STRING:
1.58      veillard 1642:                    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
1.18      daniel   1643:                    break;
                   1644:                case XPATH_NUMBER:
                   1645:                    valuePush(ctxt, arg1);
                   1646:                    xmlXPathNumberFunction(ctxt, 1);
                   1647:                    arg1 = valuePop(ctxt);
                   1648:                    ret = (arg1->floatval == arg2->floatval);
                   1649:                    break;
1.59      veillard 1650:                case XPATH_USERS:
1.62      veillard 1651:                case XPATH_POINT:
                   1652:                case XPATH_RANGE:
1.63      veillard 1653:                case XPATH_LOCATIONSET:
1.59      veillard 1654:                    TODO
                   1655:                    break;
1.18      daniel   1656:            }
                   1657:            break;
1.59      veillard 1658:         case XPATH_USERS:
1.62      veillard 1659:        case XPATH_POINT:
                   1660:        case XPATH_RANGE:
1.63      veillard 1661:        case XPATH_LOCATIONSET:
1.59      veillard 1662:            TODO
                   1663:            break;
1.3       daniel   1664:     }
1.18      daniel   1665:     xmlXPathFreeObject(arg1);
                   1666:     xmlXPathFreeObject(arg2);
                   1667:     return(ret);
1.1       daniel   1668: }
                   1669: 
                   1670: /**
                   1671:  * xmlXPathCompareValues:
1.18      daniel   1672:  * @ctxt:  the XPath Parser context
1.1       daniel   1673:  * @inf:  less than (1) or greater than (2)
                   1674:  * @strict:  is the comparison strict
                   1675:  *
                   1676:  * Implement the compare operation on XPath objects: 
                   1677:  *     @arg1 < @arg2    (1, 1, ...
                   1678:  *     @arg1 <= @arg2   (1, 0, ...
                   1679:  *     @arg1 > @arg2    (0, 1, ...
                   1680:  *     @arg1 >= @arg2   (0, 0, ...
                   1681:  *
1.18      daniel   1682:  * When neither object to be compared is a node-set and the operator is
                   1683:  * <=, <, >=, >, then the objects are compared by converted both objects
                   1684:  * to numbers and comparing the numbers according to IEEE 754. The <
                   1685:  * comparison will be true if and only if the first number is less than the
                   1686:  * second number. The <= comparison will be true if and only if the first
                   1687:  * number is less than or equal to the second number. The > comparison
                   1688:  * will be true if and only if the first number is greater than the second
                   1689:  * number. The >= comparison will be true if and only if the first number
                   1690:  * is greater than or equal to the second number.
1.1       daniel   1691:  */
                   1692: int
1.18      daniel   1693: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
                   1694:     int ret = 0;
                   1695:     xmlXPathObjectPtr arg1, arg2;
                   1696: 
                   1697:     arg2 = valuePop(ctxt);
                   1698:     if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
                   1699:         if (arg2 != NULL)
                   1700:            xmlXPathFreeObject(arg2);
1.49      daniel   1701:        XP_ERROR0(XPATH_INVALID_OPERAND);
1.18      daniel   1702:     }
                   1703:   
                   1704:     arg1 = valuePop(ctxt);
                   1705:     if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
                   1706:         if (arg1 != NULL)
                   1707:            xmlXPathFreeObject(arg1);
                   1708:        xmlXPathFreeObject(arg2);
1.49      daniel   1709:        XP_ERROR0(XPATH_INVALID_OPERAND);
1.18      daniel   1710:     }
                   1711: 
                   1712:     if (arg1->type != XPATH_NUMBER) {
                   1713:        valuePush(ctxt, arg1);
                   1714:        xmlXPathNumberFunction(ctxt, 1);
                   1715:        arg1 = valuePop(ctxt);
                   1716:     }
                   1717:     if (arg1->type != XPATH_NUMBER) {
                   1718:        xmlXPathFreeObject(arg1);
                   1719:        xmlXPathFreeObject(arg2);
1.49      daniel   1720:        XP_ERROR0(XPATH_INVALID_OPERAND);
1.18      daniel   1721:     }
                   1722:     if (arg2->type != XPATH_NUMBER) {
                   1723:        valuePush(ctxt, arg2);
                   1724:        xmlXPathNumberFunction(ctxt, 1);
                   1725:        arg2 = valuePop(ctxt);
                   1726:     }
                   1727:     if (arg2->type != XPATH_NUMBER) {
                   1728:        xmlXPathFreeObject(arg1);
                   1729:        xmlXPathFreeObject(arg2);
1.49      daniel   1730:        XP_ERROR0(XPATH_INVALID_OPERAND);
1.18      daniel   1731:     }
                   1732:     /*
                   1733:      * Add tests for infinity and nan
                   1734:      * => feedback on 3.4 for Inf and NaN
                   1735:      */
                   1736:     if (inf && strict) 
                   1737:         ret = (arg1->floatval < arg2->floatval);
                   1738:     else if (inf && !strict)
                   1739:         ret = (arg1->floatval <= arg2->floatval);
                   1740:     else if (!inf && strict)
                   1741:         ret = (arg1->floatval > arg2->floatval);
                   1742:     else if (!inf && !strict)
                   1743:         ret = (arg1->floatval >= arg2->floatval);
                   1744:     xmlXPathFreeObject(arg1);
                   1745:     xmlXPathFreeObject(arg2);
                   1746:     return(ret);
1.1       daniel   1747: }
                   1748: 
                   1749: /**
                   1750:  * xmlXPathValueFlipSign:
1.6       daniel   1751:  * @ctxt:  the XPath Parser context
1.1       daniel   1752:  *
                   1753:  * Implement the unary - operation on an XPath object
1.6       daniel   1754:  * The numeric operators convert their operands to numbers as if
                   1755:  * by calling the number function.
1.1       daniel   1756:  */
                   1757: void
1.6       daniel   1758: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
                   1759:     xmlXPathObjectPtr arg;
                   1760:     
                   1761:     POP_FLOAT
                   1762:     arg->floatval = -arg->floatval;
                   1763:     valuePush(ctxt, arg);
1.1       daniel   1764: }
                   1765: 
                   1766: /**
                   1767:  * xmlXPathAddValues:
1.6       daniel   1768:  * @ctxt:  the XPath Parser context
1.1       daniel   1769:  *
1.10      daniel   1770:  * Implement the add operation on XPath objects:
1.6       daniel   1771:  * The numeric operators convert their operands to numbers as if
                   1772:  * by calling the number function.
1.1       daniel   1773:  */
1.6       daniel   1774: void
                   1775: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
                   1776:     xmlXPathObjectPtr arg;
1.10      daniel   1777:     double val;
1.6       daniel   1778: 
                   1779:     POP_FLOAT
                   1780:     val = arg->floatval;
                   1781:     xmlXPathFreeObject(arg);
                   1782: 
                   1783:     POP_FLOAT
                   1784:     arg->floatval += val;
                   1785:     valuePush(ctxt, arg);
1.1       daniel   1786: }
                   1787: 
                   1788: /**
                   1789:  * xmlXPathSubValues:
1.6       daniel   1790:  * @ctxt:  the XPath Parser context
1.1       daniel   1791:  *
1.10      daniel   1792:  * Implement the substraction operation on XPath objects:
1.6       daniel   1793:  * The numeric operators convert their operands to numbers as if
                   1794:  * by calling the number function.
                   1795:  */
                   1796: void
                   1797: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
                   1798:     xmlXPathObjectPtr arg;
1.10      daniel   1799:     double val;
1.6       daniel   1800: 
                   1801:     POP_FLOAT
                   1802:     val = arg->floatval;
                   1803:     xmlXPathFreeObject(arg);
                   1804: 
                   1805:     POP_FLOAT
                   1806:     arg->floatval -= val;
                   1807:     valuePush(ctxt, arg);
1.1       daniel   1808: }
                   1809: 
                   1810: /**
                   1811:  * xmlXPathMultValues:
1.6       daniel   1812:  * @ctxt:  the XPath Parser context
1.1       daniel   1813:  *
1.10      daniel   1814:  * Implement the multiply operation on XPath objects:
1.6       daniel   1815:  * The numeric operators convert their operands to numbers as if
                   1816:  * by calling the number function.
1.1       daniel   1817:  */
1.6       daniel   1818: void
                   1819: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
                   1820:     xmlXPathObjectPtr arg;
1.10      daniel   1821:     double val;
1.6       daniel   1822: 
                   1823:     POP_FLOAT
                   1824:     val = arg->floatval;
                   1825:     xmlXPathFreeObject(arg);
                   1826: 
                   1827:     POP_FLOAT
                   1828:     arg->floatval *= val;
                   1829:     valuePush(ctxt, arg);
1.1       daniel   1830: }
                   1831: 
                   1832: /**
                   1833:  * xmlXPathDivValues:
1.6       daniel   1834:  * @ctxt:  the XPath Parser context
1.1       daniel   1835:  *
1.10      daniel   1836:  * Implement the div operation on XPath objects:
1.6       daniel   1837:  * The numeric operators convert their operands to numbers as if
                   1838:  * by calling the number function.
1.1       daniel   1839:  */
1.6       daniel   1840: void
                   1841: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
                   1842:     xmlXPathObjectPtr arg;
1.10      daniel   1843:     double val;
1.6       daniel   1844: 
                   1845:     POP_FLOAT
                   1846:     val = arg->floatval;
                   1847:     xmlXPathFreeObject(arg);
                   1848: 
                   1849:     POP_FLOAT
                   1850:     arg->floatval /= val;
                   1851:     valuePush(ctxt, arg);
1.1       daniel   1852: }
                   1853: 
                   1854: /**
                   1855:  * xmlXPathModValues:
1.6       daniel   1856:  * @ctxt:  the XPath Parser context
1.1       daniel   1857:  *
                   1858:  * Implement the div operation on XPath objects: @arg1 / @arg2
1.6       daniel   1859:  * The numeric operators convert their operands to numbers as if
                   1860:  * by calling the number function.
1.1       daniel   1861:  */
1.6       daniel   1862: void
                   1863: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
                   1864:     xmlXPathObjectPtr arg;
1.10      daniel   1865:     double val;
1.6       daniel   1866: 
                   1867:     POP_FLOAT
                   1868:     val = arg->floatval;
                   1869:     xmlXPathFreeObject(arg);
                   1870: 
                   1871:     POP_FLOAT
                   1872:     arg->floatval /= val;
                   1873:     valuePush(ctxt, arg);
1.1       daniel   1874: }
                   1875: 
                   1876: /************************************************************************
                   1877:  *                                                                     *
1.2       daniel   1878:  *             The traversal functions                                 *
                   1879:  *                                                                     *
                   1880:  ************************************************************************/
                   1881: 
1.59      veillard 1882: typedef enum {
                   1883:     AXIS_ANCESTOR = 1,
                   1884:     AXIS_ANCESTOR_OR_SELF,
                   1885:     AXIS_ATTRIBUTE,
                   1886:     AXIS_CHILD,
                   1887:     AXIS_DESCENDANT,
                   1888:     AXIS_DESCENDANT_OR_SELF,
                   1889:     AXIS_FOLLOWING,
                   1890:     AXIS_FOLLOWING_SIBLING,
                   1891:     AXIS_NAMESPACE,
                   1892:     AXIS_PARENT,
                   1893:     AXIS_PRECEDING,
                   1894:     AXIS_PRECEDING_SIBLING,
                   1895:     AXIS_SELF
                   1896: } xmlXPathAxisVal;
1.3       daniel   1897: 
                   1898: /*
                   1899:  * A traversal function enumerates nodes along an axis.
                   1900:  * Initially it must be called with NULL, and it indicates
                   1901:  * termination on the axis by returning NULL.
                   1902:  */
                   1903: typedef xmlNodePtr (*xmlXPathTraversalFunction)
                   1904:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
                   1905: 
1.2       daniel   1906: /**
                   1907:  * mlXPathNextSelf:
                   1908:  * @ctxt:  the XPath Parser context
                   1909:  * @cur:  the current node in the traversal
                   1910:  *
                   1911:  * Traversal function for the "self" direction
                   1912:  * he self axis contains just the context node itself
1.19      daniel   1913:  *
                   1914:  * Returns the next element following that axis
1.2       daniel   1915:  */
                   1916: xmlNodePtr
                   1917: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   1918:     if (cur == NULL)
                   1919:         return(ctxt->context->node);
                   1920:     return(NULL);
                   1921: }
                   1922: 
                   1923: /**
                   1924:  * mlXPathNextChild:
                   1925:  * @ctxt:  the XPath Parser context
                   1926:  * @cur:  the current node in the traversal
                   1927:  *
                   1928:  * Traversal function for the "child" direction
                   1929:  * The child axis contains the children of the context node in document order.
1.19      daniel   1930:  *
                   1931:  * Returns the next element following that axis
1.2       daniel   1932:  */
                   1933: xmlNodePtr
                   1934: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14      daniel   1935:     if (cur == NULL) {
1.37      daniel   1936:        if (ctxt->context->node == NULL) return(NULL);
                   1937:        switch (ctxt->context->node->type) {
                   1938:             case XML_ELEMENT_NODE:
                   1939:             case XML_TEXT_NODE:
                   1940:             case XML_CDATA_SECTION_NODE:
                   1941:             case XML_ENTITY_REF_NODE:
                   1942:             case XML_ENTITY_NODE:
                   1943:             case XML_PI_NODE:
                   1944:             case XML_COMMENT_NODE:
                   1945:             case XML_NOTATION_NODE:
1.42      daniel   1946:             case XML_DTD_NODE:
                   1947:                return(ctxt->context->node->children);
1.37      daniel   1948:             case XML_DOCUMENT_NODE:
                   1949:             case XML_DOCUMENT_TYPE_NODE:
                   1950:             case XML_DOCUMENT_FRAG_NODE:
                   1951:             case XML_HTML_DOCUMENT_NODE:
1.55      veillard 1952: #ifdef LIBXML_SGML_ENABLED
                   1953:            case XML_SGML_DOCUMENT_NODE:
                   1954: #endif
1.42      daniel   1955:                return(((xmlDocPtr) ctxt->context->node)->children);
1.43      daniel   1956:            case XML_ELEMENT_DECL:
                   1957:            case XML_ATTRIBUTE_DECL:
1.44      daniel   1958:            case XML_ENTITY_DECL:
1.43      daniel   1959:             case XML_ATTRIBUTE_NODE:
                   1960:                return(NULL);
1.37      daniel   1961:        }
                   1962:        return(NULL);
1.14      daniel   1963:     }
1.35      daniel   1964:     if ((cur->type == XML_DOCUMENT_NODE) ||
                   1965:         (cur->type == XML_HTML_DOCUMENT_NODE))
1.14      daniel   1966:        return(NULL);
1.2       daniel   1967:     return(cur->next);
                   1968: }
                   1969: 
                   1970: /**
                   1971:  * mlXPathNextDescendant:
                   1972:  * @ctxt:  the XPath Parser context
                   1973:  * @cur:  the current node in the traversal
                   1974:  *
                   1975:  * Traversal function for the "descendant" direction
                   1976:  * the descendant axis contains the descendants of the context node in document
                   1977:  * order; a descendant is a child or a child of a child and so on.
1.19      daniel   1978:  *
                   1979:  * Returns the next element following that axis
1.2       daniel   1980:  */
                   1981: xmlNodePtr
                   1982: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14      daniel   1983:     if (cur == NULL) {
1.37      daniel   1984:        if (ctxt->context->node == NULL)
                   1985:            return(NULL);
                   1986:        if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
                   1987:            return(NULL);
                   1988: 
1.14      daniel   1989:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1.42      daniel   1990:            return(ctxt->context->doc->children);
                   1991:         return(ctxt->context->node->children);
1.14      daniel   1992:     }
1.2       daniel   1993: 
1.48      daniel   1994:     if (cur->children != NULL)
                   1995:        {
                   1996:        if (cur->children->type != XML_ENTITY_DECL)
                   1997:                        return(cur->children);
                   1998:        }
1.2       daniel   1999:     if (cur->next != NULL) return(cur->next);
                   2000:     
                   2001:     do {
                   2002:         cur = cur->parent;
                   2003:        if (cur == NULL) return(NULL);
                   2004:        if (cur == ctxt->context->node) return(NULL);
                   2005:        if (cur->next != NULL) {
                   2006:            cur = cur->next;
                   2007:            return(cur);
                   2008:        }
                   2009:     } while (cur != NULL);
                   2010:     return(cur);
                   2011: }
                   2012: 
                   2013: /**
                   2014:  * mlXPathNextDescendantOrSelf:
                   2015:  * @ctxt:  the XPath Parser context
                   2016:  * @cur:  the current node in the traversal
                   2017:  *
                   2018:  * Traversal function for the "descendant-or-self" direction
                   2019:  * the descendant-or-self axis contains the context node and the descendants
                   2020:  * of the context node in document order; thus the context node is the first
                   2021:  * node on the axis, and the first child of the context node is the second node
                   2022:  * on the axis
1.19      daniel   2023:  *
                   2024:  * Returns the next element following that axis
1.2       daniel   2025:  */
                   2026: xmlNodePtr
                   2027: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.37      daniel   2028:     if (cur == NULL) {
                   2029:        if (ctxt->context->node == NULL)
                   2030:            return(NULL);
                   2031:        if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
                   2032:            return(NULL);
1.2       daniel   2033:         return(ctxt->context->node);
1.37      daniel   2034:     }
1.2       daniel   2035: 
1.37      daniel   2036:     return(xmlXPathNextDescendant(ctxt, cur));
1.2       daniel   2037: }
                   2038: 
                   2039: /**
                   2040:  * xmlXPathNextParent:
                   2041:  * @ctxt:  the XPath Parser context
                   2042:  * @cur:  the current node in the traversal
                   2043:  *
                   2044:  * Traversal function for the "parent" direction
                   2045:  * The parent axis contains the parent of the context node, if there is one.
1.19      daniel   2046:  *
                   2047:  * Returns the next element following that axis
1.2       daniel   2048:  */
                   2049: xmlNodePtr
                   2050: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   2051:     /*
                   2052:      * the parent of an attribute or namespace node is the element
                   2053:      * to which the attribute or namespace node is attached
1.37      daniel   2054:      * Namespace handling !!!
1.2       daniel   2055:      */
1.14      daniel   2056:     if (cur == NULL) {
1.37      daniel   2057:        if (ctxt->context->node == NULL) return(NULL);
                   2058:        switch (ctxt->context->node->type) {
                   2059:             case XML_ELEMENT_NODE:
                   2060:             case XML_TEXT_NODE:
                   2061:             case XML_CDATA_SECTION_NODE:
                   2062:             case XML_ENTITY_REF_NODE:
                   2063:             case XML_ENTITY_NODE:
                   2064:             case XML_PI_NODE:
                   2065:             case XML_COMMENT_NODE:
                   2066:             case XML_NOTATION_NODE:
1.42      daniel   2067:             case XML_DTD_NODE:
1.43      daniel   2068:            case XML_ELEMENT_DECL:
                   2069:            case XML_ATTRIBUTE_DECL:
1.44      daniel   2070:            case XML_ENTITY_DECL:
1.37      daniel   2071:                if (ctxt->context->node->parent == NULL)
                   2072:                    return((xmlNodePtr) ctxt->context->doc);
                   2073:                return(ctxt->context->node->parent);
                   2074:             case XML_ATTRIBUTE_NODE: {
                   2075:                xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
                   2076: 
1.42      daniel   2077:                return(att->parent);
1.37      daniel   2078:            }
                   2079:             case XML_DOCUMENT_NODE:
                   2080:             case XML_DOCUMENT_TYPE_NODE:
                   2081:             case XML_DOCUMENT_FRAG_NODE:
                   2082:             case XML_HTML_DOCUMENT_NODE:
1.55      veillard 2083: #ifdef LIBXML_SGML_ENABLED
                   2084:            case XML_SGML_DOCUMENT_NODE:
                   2085: #endif
1.37      daniel   2086:                 return(NULL);
                   2087:        }
1.14      daniel   2088:     }
1.2       daniel   2089:     return(NULL);
                   2090: }
                   2091: 
                   2092: /**
                   2093:  * xmlXPathNextAncestor:
                   2094:  * @ctxt:  the XPath Parser context
                   2095:  * @cur:  the current node in the traversal
                   2096:  *
                   2097:  * Traversal function for the "ancestor" direction
                   2098:  * the ancestor axis contains the ancestors of the context node; the ancestors
                   2099:  * of the context node consist of the parent of context node and the parent's
                   2100:  * parent and so on; the nodes are ordered in reverse document order; thus the
                   2101:  * parent is the first node on the axis, and the parent's parent is the second
                   2102:  * node on the axis
1.19      daniel   2103:  *
                   2104:  * Returns the next element following that axis
1.2       daniel   2105:  */
                   2106: xmlNodePtr
                   2107: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   2108:     /*
                   2109:      * the parent of an attribute or namespace node is the element
                   2110:      * to which the attribute or namespace node is attached
1.37      daniel   2111:      * !!!!!!!!!!!!!
1.2       daniel   2112:      */
1.14      daniel   2113:     if (cur == NULL) {
1.37      daniel   2114:        if (ctxt->context->node == NULL) return(NULL);
                   2115:        switch (ctxt->context->node->type) {
                   2116:             case XML_ELEMENT_NODE:
                   2117:             case XML_TEXT_NODE:
                   2118:             case XML_CDATA_SECTION_NODE:
                   2119:             case XML_ENTITY_REF_NODE:
                   2120:             case XML_ENTITY_NODE:
                   2121:             case XML_PI_NODE:
                   2122:             case XML_COMMENT_NODE:
1.42      daniel   2123:            case XML_DTD_NODE:
1.43      daniel   2124:            case XML_ELEMENT_DECL:
                   2125:            case XML_ATTRIBUTE_DECL:
1.44      daniel   2126:            case XML_ENTITY_DECL:
1.37      daniel   2127:             case XML_NOTATION_NODE:
                   2128:                if (ctxt->context->node->parent == NULL)
                   2129:                    return((xmlNodePtr) ctxt->context->doc);
                   2130:                return(ctxt->context->node->parent);
                   2131:             case XML_ATTRIBUTE_NODE: {
                   2132:                xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
                   2133: 
1.42      daniel   2134:                return(cur->parent);
1.37      daniel   2135:            }
                   2136:             case XML_DOCUMENT_NODE:
                   2137:             case XML_DOCUMENT_TYPE_NODE:
                   2138:             case XML_DOCUMENT_FRAG_NODE:
                   2139:             case XML_HTML_DOCUMENT_NODE:
1.55      veillard 2140: #ifdef LIBXML_SGML_ENABLED
                   2141:            case XML_SGML_DOCUMENT_NODE:
                   2142: #endif
1.37      daniel   2143:                 return(NULL);
                   2144:        }
                   2145:        return(NULL);
1.14      daniel   2146:     }
1.42      daniel   2147:     if (cur == ctxt->context->doc->children)
1.14      daniel   2148:        return((xmlNodePtr) ctxt->context->doc);
                   2149:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   2150:        return(NULL);
1.37      daniel   2151:     switch (cur->type) {
                   2152:        case XML_ELEMENT_NODE:
                   2153:        case XML_TEXT_NODE:
                   2154:        case XML_CDATA_SECTION_NODE:
                   2155:        case XML_ENTITY_REF_NODE:
                   2156:        case XML_ENTITY_NODE:
                   2157:        case XML_PI_NODE:
                   2158:        case XML_COMMENT_NODE:
                   2159:        case XML_NOTATION_NODE:
1.42      daniel   2160:        case XML_DTD_NODE:
1.43      daniel   2161:         case XML_ELEMENT_DECL:
                   2162:         case XML_ATTRIBUTE_DECL:
1.44      daniel   2163:         case XML_ENTITY_DECL:
1.37      daniel   2164:            return(cur->parent);
                   2165:        case XML_ATTRIBUTE_NODE: {
                   2166:            xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
                   2167: 
1.42      daniel   2168:            return(att->parent);
1.37      daniel   2169:        }
                   2170:        case XML_DOCUMENT_NODE:
                   2171:        case XML_DOCUMENT_TYPE_NODE:
                   2172:        case XML_DOCUMENT_FRAG_NODE:
                   2173:        case XML_HTML_DOCUMENT_NODE:
1.55      veillard 2174: #ifdef LIBXML_SGML_ENABLED
                   2175:        case XML_SGML_DOCUMENT_NODE:
                   2176: #endif
1.37      daniel   2177:            return(NULL);
                   2178:     }
                   2179:     return(NULL);
1.2       daniel   2180: }
                   2181: 
                   2182: /**
                   2183:  * xmlXPathNextAncestorOrSelf:
                   2184:  * @ctxt:  the XPath Parser context
                   2185:  * @cur:  the current node in the traversal
                   2186:  *
                   2187:  * Traversal function for the "ancestor-or-self" direction
1.19      daniel   2188:  * he ancestor-or-self axis contains the context node and ancestors of
                   2189:  * the context node in reverse document order; thus the context node is
                   2190:  * the first node on the axis, and the context node's parent the second;
                   2191:  * parent here is defined the same as with the parent axis.
                   2192:  *
                   2193:  * Returns the next element following that axis
1.2       daniel   2194:  */
                   2195: xmlNodePtr
                   2196: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   2197:     if (cur == NULL)
                   2198:         return(ctxt->context->node);
1.37      daniel   2199:     return(xmlXPathNextAncestor(ctxt, cur));
1.2       daniel   2200: }
                   2201: 
                   2202: /**
                   2203:  * xmlXPathNextFollowingSibling:
                   2204:  * @ctxt:  the XPath Parser context
                   2205:  * @cur:  the current node in the traversal
                   2206:  *
                   2207:  * Traversal function for the "following-sibling" direction
                   2208:  * The following-sibling axis contains the following siblings of the context
                   2209:  * node in document order.
1.19      daniel   2210:  *
                   2211:  * Returns the next element following that axis
1.2       daniel   2212:  */
                   2213: xmlNodePtr
                   2214: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14      daniel   2215:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   2216:         return(NULL);
1.2       daniel   2217:     if (cur == NULL)
                   2218:         return(ctxt->context->node->next);
                   2219:     return(cur->next);
                   2220: }
                   2221: 
                   2222: /**
                   2223:  * xmlXPathNextPrecedingSibling:
                   2224:  * @ctxt:  the XPath Parser context
                   2225:  * @cur:  the current node in the traversal
                   2226:  *
                   2227:  * Traversal function for the "preceding-sibling" direction
                   2228:  * The preceding-sibling axis contains the preceding siblings of the context
                   2229:  * node in reverse document order; the first preceding sibling is first on the
                   2230:  * axis; the sibling preceding that node is the second on the axis and so on.
1.19      daniel   2231:  *
                   2232:  * Returns the next element following that axis
1.2       daniel   2233:  */
                   2234: xmlNodePtr
                   2235: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14      daniel   2236:     if (cur == (xmlNodePtr) ctxt->context->doc)
                   2237:         return(NULL);
1.2       daniel   2238:     if (cur == NULL)
                   2239:         return(ctxt->context->node->prev);
                   2240:     return(cur->prev);
                   2241: }
                   2242: 
                   2243: /**
                   2244:  * xmlXPathNextFollowing:
                   2245:  * @ctxt:  the XPath Parser context
                   2246:  * @cur:  the current node in the traversal
                   2247:  *
                   2248:  * Traversal function for the "following" direction
                   2249:  * The following axis contains all nodes in the same document as the context
                   2250:  * node that are after the context node in document order, excluding any
                   2251:  * descendants and excluding attribute nodes and namespace nodes; the nodes
                   2252:  * are ordered in document order
1.19      daniel   2253:  *
                   2254:  * Returns the next element following that axis
1.2       daniel   2255:  */
                   2256: xmlNodePtr
                   2257: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.60      veillard 2258:     if (cur != NULL && cur->children != NULL)
                   2259:         return cur->children ;
1.63      veillard 2260:     if (cur == NULL) cur = ctxt->context->node;
                   2261:     if (cur == NULL) return(NULL) ; /* ERROR */
                   2262:     if (cur->next != NULL) return(cur->next) ;
1.60      veillard 2263:     do {
                   2264:         cur = cur->parent;
                   2265:         if (cur == NULL) return(NULL);
1.63      veillard 2266:         if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */
                   2267:         if (cur->next != NULL) return(cur->next);
1.60      veillard 2268:     } while (cur != NULL);
                   2269:     return(cur);
                   2270: }
                   2271: 
                   2272: /*
1.63      veillard 2273:  * xmlXPathIsAncestor:
                   2274:  * @ancestor:  the ancestor node
                   2275:  * @node:  the current node
                   2276:  *
                   2277:  * Check that @ancestor is a @node's ancestor
                   2278:  *
1.60      veillard 2279:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
                   2280:  */
                   2281: static int
1.63      veillard 2282: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
1.60      veillard 2283:     xmlNodePtr tmp ;
                   2284:     if (ancestor == NULL || node == NULL) return 0 ;
                   2285:     for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) {
                   2286:         if (tmp->parent == ancestor)
                   2287:             return 1 ;
                   2288:     }
                   2289:     return 0 ;
                   2290: }
                   2291: 
                   2292: /**
                   2293:  * xmlXPathNextPreceding:
                   2294:  * @ctxt:  the XPath Parser context
                   2295:  * @cur:  the current node in the traversal
                   2296:  *
                   2297:  * Traversal function for the "preceding" direction
                   2298:  * the preceding axis contains all nodes in the same document as the context
                   2299:  * node that are before the context node in document order, excluding any
                   2300:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
                   2301:  * ordered in reverse document order
                   2302:  *
                   2303:  * Returns the next element following that axis
                   2304:  */
                   2305: xmlNodePtr
                   2306: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                   2307:     if (cur == NULL)
                   2308:         cur = ctxt->context->node ;
                   2309:     do {
                   2310:         if (cur->prev != NULL) {
                   2311:             for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
                   2312:                 ;
                   2313:             return(cur) ;
                   2314:         }
                   2315: 
                   2316:         cur = cur->parent;
                   2317:         if (cur == NULL) return(NULL);
                   2318:         if (cur == ctxt->context->doc->children) return(NULL);
1.63      veillard 2319:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
1.2       daniel   2320:     return(cur);
                   2321: }
                   2322: 
                   2323: /**
                   2324:  * xmlXPathNextNamespace:
                   2325:  * @ctxt:  the XPath Parser context
                   2326:  * @cur:  the current attribute in the traversal
                   2327:  *
                   2328:  * Traversal function for the "namespace" direction
                   2329:  * the namespace axis contains the namespace nodes of the context node;
                   2330:  * the order of nodes on this axis is implementation-defined; the axis will
                   2331:  * be empty unless the context node is an element
1.19      daniel   2332:  *
                   2333:  * Returns the next element following that axis
1.2       daniel   2334:  */
1.19      daniel   2335: xmlNsPtr
1.2       daniel   2336: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1.19      daniel   2337:     if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
                   2338:         if (ctxt->context->namespaces != NULL)
1.25      daniel   2339:            xmlFree(ctxt->context->namespaces);
1.19      daniel   2340:        ctxt->context->namespaces = 
                   2341:            xmlGetNsList(ctxt->context->doc, ctxt->context->node);
                   2342:        if (ctxt->context->namespaces == NULL) return(NULL);
                   2343:        ctxt->context->nsNr = 0;
                   2344:     }
                   2345:     return(ctxt->context->namespaces[ctxt->context->nsNr++]);
1.2       daniel   2346: }
                   2347: 
                   2348: /**
                   2349:  * xmlXPathNextAttribute:
                   2350:  * @ctxt:  the XPath Parser context
                   2351:  * @cur:  the current attribute in the traversal
                   2352:  *
                   2353:  * Traversal function for the "attribute" direction
1.33      daniel   2354:  * TODO: support DTD inherited default attributes
1.19      daniel   2355:  *
                   2356:  * Returns the next element following that axis
1.2       daniel   2357:  */
                   2358: xmlAttrPtr
                   2359: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1.18      daniel   2360:     if (cur == NULL) {
                   2361:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
                   2362:            return(NULL);
1.2       daniel   2363:         return(ctxt->context->node->properties);
1.18      daniel   2364:     }
1.2       daniel   2365:     return(cur->next);
                   2366: }
                   2367: 
                   2368: /************************************************************************
                   2369:  *                                                                     *
1.3       daniel   2370:  *             NodeTest Functions                                      *
                   2371:  *                                                                     *
                   2372:  ************************************************************************/
                   2373: 
1.59      veillard 2374: typedef enum {
                   2375:     NODE_TEST_NONE = 0,
                   2376:     NODE_TEST_TYPE = 1,
                   2377:     NODE_TEST_PI = 2,
                   2378:     NODE_TEST_ALL = 3,
                   2379:     NODE_TEST_NS = 4,
                   2380:     NODE_TEST_NAME = 5
                   2381: } xmlXPathTestVal;
                   2382: 
                   2383: typedef enum {
1.66      veillard 2384:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
                   2385:     NODE_TYPE_TEXT = XML_TEXT_NODE,
                   2386:     NODE_TYPE_PI = XML_PI_NODE,
                   2387:     NODE_TYPE_NODE = XML_ELEMENT_NODE
1.59      veillard 2388: } xmlXPathTypeVal;
1.3       daniel   2389: 
                   2390: #define IS_FUNCTION                    200
                   2391: 
                   2392: /**
                   2393:  * xmlXPathNodeCollectAndTest:
                   2394:  * @ctxt:  the XPath Parser context
1.59      veillard 2395:  * @axis:  the XPath axis
                   2396:  * @test:  the XPath test
                   2397:  * @type:  the XPath type
                   2398:  * @prefix:  the namesapce prefix if any
                   2399:  * @name:  the name used in the search if any
1.3       daniel   2400:  *
                   2401:  * This is the function implementing a step: based on the current list
                   2402:  * of nodes, it builds up a new list, looking at all nodes under that
                   2403:  * axis and selecting them.
                   2404:  *
                   2405:  * Returns the new NodeSet resulting from the search.
                   2406:  */
1.59      veillard 2407: void
                   2408: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
                   2409:                            xmlXPathTestVal test, xmlXPathTypeVal type,
                   2410:                           const xmlChar *prefix, const xmlChar *name) {
1.4       daniel   2411: #ifdef DEBUG_STEP
                   2412:     int n = 0, t = 0;
1.3       daniel   2413: #endif
                   2414:     int i;
                   2415:     xmlNodeSetPtr ret;
                   2416:     xmlXPathTraversalFunction next = NULL;
                   2417:     xmlNodePtr cur = NULL;
1.59      veillard 2418:     xmlXPathObjectPtr obj;
                   2419:     xmlNodeSetPtr nodelist;
                   2420: 
                   2421:     CHECK_TYPE(XPATH_NODESET);
                   2422:     obj = valuePop(ctxt);
1.3       daniel   2423: 
1.4       daniel   2424: #ifdef DEBUG_STEP
1.9       daniel   2425:     fprintf(xmlXPathDebug, "new step : ");
1.4       daniel   2426: #endif
1.3       daniel   2427:     switch (axis) {
                   2428:         case AXIS_ANCESTOR:
1.4       daniel   2429: #ifdef DEBUG_STEP
1.9       daniel   2430:            fprintf(xmlXPathDebug, "axis 'ancestors' ");
1.4       daniel   2431: #endif
1.3       daniel   2432:            next = xmlXPathNextAncestor; break;
                   2433:         case AXIS_ANCESTOR_OR_SELF:
1.4       daniel   2434: #ifdef DEBUG_STEP
1.9       daniel   2435:            fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1.4       daniel   2436: #endif
1.3       daniel   2437:            next = xmlXPathNextAncestorOrSelf; break;
                   2438:         case AXIS_ATTRIBUTE:
1.4       daniel   2439: #ifdef DEBUG_STEP
1.9       daniel   2440:            fprintf(xmlXPathDebug, "axis 'attributes' ");
1.4       daniel   2441: #endif
1.19      daniel   2442:            next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
1.3       daniel   2443:            break;
                   2444:         case AXIS_CHILD:
1.4       daniel   2445: #ifdef DEBUG_STEP
1.9       daniel   2446:            fprintf(xmlXPathDebug, "axis 'child' ");
1.4       daniel   2447: #endif
1.3       daniel   2448:            next = xmlXPathNextChild; break;
                   2449:         case AXIS_DESCENDANT:
1.4       daniel   2450: #ifdef DEBUG_STEP
1.9       daniel   2451:            fprintf(xmlXPathDebug, "axis 'descendant' ");
1.4       daniel   2452: #endif
1.3       daniel   2453:            next = xmlXPathNextDescendant; break;
                   2454:         case AXIS_DESCENDANT_OR_SELF:
1.4       daniel   2455: #ifdef DEBUG_STEP
1.9       daniel   2456:            fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1.4       daniel   2457: #endif
1.3       daniel   2458:            next = xmlXPathNextDescendantOrSelf; break;
                   2459:         case AXIS_FOLLOWING:
1.4       daniel   2460: #ifdef DEBUG_STEP
1.9       daniel   2461:            fprintf(xmlXPathDebug, "axis 'following' ");
1.4       daniel   2462: #endif
1.3       daniel   2463:            next = xmlXPathNextFollowing; break;
                   2464:         case AXIS_FOLLOWING_SIBLING:
1.4       daniel   2465: #ifdef DEBUG_STEP
1.9       daniel   2466:            fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1.4       daniel   2467: #endif
1.3       daniel   2468:            next = xmlXPathNextFollowingSibling; break;
                   2469:         case AXIS_NAMESPACE:
1.4       daniel   2470: #ifdef DEBUG_STEP
1.9       daniel   2471:            fprintf(xmlXPathDebug, "axis 'namespace' ");
1.4       daniel   2472: #endif
1.19      daniel   2473:            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
1.3       daniel   2474:            break;
                   2475:         case AXIS_PARENT:
1.4       daniel   2476: #ifdef DEBUG_STEP
1.9       daniel   2477:            fprintf(xmlXPathDebug, "axis 'parent' ");
1.4       daniel   2478: #endif
1.3       daniel   2479:            next = xmlXPathNextParent; break;
                   2480:         case AXIS_PRECEDING:
1.4       daniel   2481: #ifdef DEBUG_STEP
1.9       daniel   2482:            fprintf(xmlXPathDebug, "axis 'preceding' ");
1.4       daniel   2483: #endif
1.3       daniel   2484:            next = xmlXPathNextPreceding; break;
                   2485:         case AXIS_PRECEDING_SIBLING:
1.4       daniel   2486: #ifdef DEBUG_STEP
1.9       daniel   2487:            fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1.4       daniel   2488: #endif
1.3       daniel   2489:            next = xmlXPathNextPrecedingSibling; break;
                   2490:         case AXIS_SELF:
1.4       daniel   2491: #ifdef DEBUG_STEP
1.9       daniel   2492:            fprintf(xmlXPathDebug, "axis 'self' ");
1.4       daniel   2493: #endif
1.3       daniel   2494:            next = xmlXPathNextSelf; break;
                   2495:     }
1.59      veillard 2496:     if (next == NULL)
                   2497:        return;
                   2498: 
                   2499:     nodelist = obj->nodesetval;
1.3       daniel   2500:     ret = xmlXPathNodeSetCreate(NULL);
1.4       daniel   2501: #ifdef DEBUG_STEP
1.9       daniel   2502:     fprintf(xmlXPathDebug, " context contains %d nodes\n",
1.59      veillard 2503:             nodelist->nodeNr);
1.4       daniel   2504:     switch (test) {
                   2505:        case NODE_TEST_NONE:
1.35      daniel   2506:            fprintf(xmlXPathDebug, "           searching for none !!!\n");
1.4       daniel   2507:            break;
                   2508:        case NODE_TEST_TYPE:
1.35      daniel   2509:            fprintf(xmlXPathDebug, "           searching for type %d\n", type);
1.4       daniel   2510:            break;
                   2511:        case NODE_TEST_PI:
1.35      daniel   2512:            fprintf(xmlXPathDebug, "           searching for PI !!!\n");
1.4       daniel   2513:            break;
                   2514:        case NODE_TEST_ALL:
1.35      daniel   2515:            fprintf(xmlXPathDebug, "           searching for *\n");
1.4       daniel   2516:            break;
                   2517:        case NODE_TEST_NS:
1.35      daniel   2518:            fprintf(xmlXPathDebug, "           searching for namespace %s\n",
1.9       daniel   2519:                    prefix);
1.4       daniel   2520:            break;
                   2521:        case NODE_TEST_NAME:
1.35      daniel   2522:            fprintf(xmlXPathDebug, "           searching for name %s\n", name);
1.4       daniel   2523:            if (prefix != NULL)
1.9       daniel   2524:                fprintf(xmlXPathDebug, "           with namespace %s\n",
                   2525:                        prefix);
1.4       daniel   2526:            break;
                   2527:     }
1.9       daniel   2528:     fprintf(xmlXPathDebug, "Testing : ");
1.4       daniel   2529: #endif
1.73      veillard 2530:     /*
                   2531:      * 2.3 Node Tests
                   2532:      *  - For the attribute axis, the principal node type is attribute. 
                   2533:      *  - For the namespace axis, the principal node type is namespace. 
                   2534:      *  - For other axes, the principal node type is element. 
                   2535:      *
                   2536:      * A node test * is true for any node of the
                   2537:      * principal node type. For example, child::* willi
                   2538:      * select all element children of the context node
                   2539:      */
1.59      veillard 2540:     for (i = 0;i < nodelist->nodeNr; i++) {
                   2541:         ctxt->context->node = nodelist->nodeTab[i];
1.3       daniel   2542: 
                   2543:        cur = NULL;
                   2544:        do {
                   2545:            cur = next(ctxt, cur);
                   2546:            if (cur == NULL) break;
1.9       daniel   2547: #ifdef DEBUG_STEP
1.4       daniel   2548:             t++;
1.9       daniel   2549:             fprintf(xmlXPathDebug, " %s", cur->name);
1.4       daniel   2550: #endif
1.3       daniel   2551:            switch (test) {
                   2552:                 case NODE_TEST_NONE:
1.6       daniel   2553:                    STRANGE
1.59      veillard 2554:                    return;
1.3       daniel   2555:                 case NODE_TEST_TYPE:
1.35      daniel   2556:                    if ((cur->type == type) ||
                   2557:                        ((type == XML_ELEMENT_NODE) && 
                   2558:                         ((cur->type == XML_DOCUMENT_NODE) ||
                   2559:                          (cur->type == XML_HTML_DOCUMENT_NODE)))) {
1.9       daniel   2560: #ifdef DEBUG_STEP
1.3       daniel   2561:                         n++;
                   2562: #endif
                   2563:                        xmlXPathNodeSetAdd(ret, cur);
                   2564:                    }
                   2565:                    break;
                   2566:                 case NODE_TEST_PI:
1.19      daniel   2567:                    if (cur->type == XML_PI_NODE) {
1.22      daniel   2568:                        if ((name != NULL) &&
1.58      veillard 2569:                            (!xmlStrEqual(name, cur->name)))
1.22      daniel   2570:                            break;
1.19      daniel   2571: #ifdef DEBUG_STEP
1.22      daniel   2572:                        n++;
1.19      daniel   2573: #endif
1.22      daniel   2574:                        xmlXPathNodeSetAdd(ret, cur);
1.19      daniel   2575:                    }
1.3       daniel   2576:                    break;
                   2577:                 case NODE_TEST_ALL:
1.19      daniel   2578:                    if ((cur->type == XML_ELEMENT_NODE) ||
1.73      veillard 2579:                        (cur->type == XML_DOCUMENT_NODE) ||
                   2580:                        (cur->type == XML_HTML_DOCUMENT_NODE)) {
1.9       daniel   2581: #ifdef DEBUG_STEP
1.3       daniel   2582:                         n++;
                   2583: #endif
                   2584:                        xmlXPathNodeSetAdd(ret, cur);
                   2585:                    }
                   2586:                    break;
1.19      daniel   2587:                 case NODE_TEST_NS: {
1.22      daniel   2588:                    TODO /* namespace search */
1.3       daniel   2589:                    break;
1.19      daniel   2590:                }
1.3       daniel   2591:                 case NODE_TEST_NAME:
1.15      daniel   2592:                    switch (cur->type) {
                   2593:                        case XML_ELEMENT_NODE:
1.58      veillard 2594:                            if (xmlStrEqual(name, cur->name) && 
1.15      daniel   2595:                                (((prefix == NULL) ||
                   2596:                                  ((cur->ns != NULL) && 
1.58      veillard 2597:                                   (xmlStrEqual(prefix, cur->ns->href)))))) {
1.9       daniel   2598: #ifdef DEBUG_STEP
1.59      veillard 2599:                                n++;
1.3       daniel   2600: #endif
1.15      daniel   2601:                                xmlXPathNodeSetAdd(ret, cur);
                   2602:                            }
1.19      daniel   2603:                            break;
                   2604:                        case XML_ATTRIBUTE_NODE: {
                   2605:                            xmlAttrPtr attr = (xmlAttrPtr) cur;
1.58      veillard 2606:                            if (xmlStrEqual(name, attr->name)) {
1.19      daniel   2607: #ifdef DEBUG_STEP
1.59      veillard 2608:                                n++;
1.19      daniel   2609: #endif
                   2610:                                xmlXPathNodeSetAdd(ret, cur);
                   2611:                            }
                   2612:                            break;
                   2613:                        }
1.15      daniel   2614:                        default:
                   2615:                            break;
1.3       daniel   2616:                    }
                   2617:                    break;
                   2618:            }
                   2619:        } while (cur != NULL);
                   2620:     }
1.9       daniel   2621: #ifdef DEBUG_STEP
                   2622:     fprintf(xmlXPathDebug,
                   2623:             "\nExamined %d nodes, found %d nodes at that step\n", t, n);
1.3       daniel   2624: #endif
1.59      veillard 2625:     xmlXPathFreeObject(obj);
                   2626:     valuePush(ctxt, xmlXPathWrapNodeSet(ret));
1.3       daniel   2627: }
                   2628: 
                   2629: 
                   2630: /************************************************************************
                   2631:  *                                                                     *
1.2       daniel   2632:  *             Implicit tree core function library                     *
                   2633:  *                                                                     *
                   2634:  ************************************************************************/
                   2635: 
                   2636: /**
                   2637:  * xmlXPathRoot:
                   2638:  * @ctxt:  the XPath Parser context
                   2639:  *
                   2640:  * Initialize the context to the root of the document
                   2641:  */
                   2642: void
                   2643: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
1.69      veillard 2644:     if (ctxt->value != NULL) {
                   2645:        xmlXPathObjectPtr obj;
1.59      veillard 2646: 
1.69      veillard 2647:        CHECK_TYPE(XPATH_NODESET);
                   2648:        obj = valuePop(ctxt);
                   2649:        xmlXPathFreeObject(obj);
                   2650:     }
1.14      daniel   2651:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
1.59      veillard 2652:     valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
1.2       daniel   2653: }
                   2654: 
                   2655: /************************************************************************
                   2656:  *                                                                     *
1.1       daniel   2657:  *             The explicit core function library                      *
                   2658:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib        *
                   2659:  *                                                                     *
                   2660:  ************************************************************************/
                   2661: 
1.5       daniel   2662: 
1.1       daniel   2663: /**
                   2664:  * xmlXPathLastFunction:
                   2665:  * @ctxt:  the XPath Parser context
                   2666:  *
                   2667:  * Implement the last() XPath function
1.5       daniel   2668:  * The last function returns the number of nodes in the context node list.
1.1       daniel   2669:  */
                   2670: void
1.8       daniel   2671: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   2672:     CHECK_ARITY(0);
1.57      veillard 2673:     if (ctxt->context->contextSize > 0) {
                   2674:        valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
                   2675: #ifdef DEBUG_EXPR
                   2676:        fprintf(xmlXPathDebug, "last() : %d\n", ctxt->context->contextSize);
                   2677: #endif
1.5       daniel   2678:     } else {
1.57      veillard 2679:        XP_ERROR(XPATH_INVALID_CTXT_SIZE);
1.5       daniel   2680:     }
1.1       daniel   2681: }
                   2682: 
                   2683: /**
                   2684:  * xmlXPathPositionFunction:
                   2685:  * @ctxt:  the XPath Parser context
                   2686:  *
                   2687:  * Implement the position() XPath function
1.4       daniel   2688:  * The position function returns the position of the context node in the
                   2689:  * context node list. The first position is 1, and so the last positionr
                   2690:  * will be equal to last().
1.1       daniel   2691:  */
                   2692: void
1.8       daniel   2693: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   2694:     CHECK_ARITY(0);
1.57      veillard 2695:     if (ctxt->context->proximityPosition > 0) {
                   2696:        valuePush(ctxt,
                   2697:                  xmlXPathNewFloat((double) ctxt->context->proximityPosition));
                   2698: #ifdef DEBUG_EXPR
                   2699:        fprintf(xmlXPathDebug, "position() : %d\n",
                   2700:                ctxt->context->proximityPosition);
                   2701: #endif
                   2702:     } else {
                   2703:        XP_ERROR(XPATH_INVALID_CTXT_POSITION);
1.4       daniel   2704:     }
1.1       daniel   2705: }
                   2706: 
                   2707: /**
                   2708:  * xmlXPathCountFunction:
                   2709:  * @ctxt:  the XPath Parser context
                   2710:  *
                   2711:  * Implement the count() XPath function
                   2712:  */
                   2713: void
1.8       daniel   2714: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5       daniel   2715:     xmlXPathObjectPtr cur;
                   2716: 
1.8       daniel   2717:     CHECK_ARITY(1);
                   2718:     CHECK_TYPE(XPATH_NODESET);
1.5       daniel   2719:     cur = valuePop(ctxt);
                   2720: 
1.10      daniel   2721:     valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
1.5       daniel   2722:     xmlXPathFreeObject(cur);
1.1       daniel   2723: }
                   2724: 
                   2725: /**
                   2726:  * xmlXPathIdFunction:
                   2727:  * @ctxt:  the XPath Parser context
                   2728:  *
                   2729:  * Implement the id() XPath function
1.8       daniel   2730:  * The id function selects elements by their unique ID
                   2731:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
                   2732:  * then the result is the union of the result of applying id to the
                   2733:  * string value of each of the nodes in the argument node-set. When the
                   2734:  * argument to id is of any other type, the argument is converted to a
                   2735:  * string as if by a call to the string function; the string is split
                   2736:  * into a whitespace-separated list of tokens (whitespace is any sequence
                   2737:  * of characters matching the production S); the result is a node-set
                   2738:  * containing the elements in the same document as the context node that
                   2739:  * have a unique ID equal to any of the tokens in the list.
1.1       daniel   2740:  */
                   2741: void
1.8       daniel   2742: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.29      daniel   2743:     const xmlChar *tokens;
                   2744:     const xmlChar *cur;
                   2745:     xmlChar *ID;
1.19      daniel   2746:     xmlAttrPtr attr;
                   2747:     xmlNodePtr elem = NULL;
                   2748:     xmlXPathObjectPtr ret, obj;
                   2749: 
1.8       daniel   2750:     CHECK_ARITY(1);
1.19      daniel   2751:     obj = valuePop(ctxt);
1.49      daniel   2752:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
1.19      daniel   2753:     if (obj->type == XPATH_NODESET) {
1.22      daniel   2754:         TODO /* ID function in case of NodeSet */
1.19      daniel   2755:     }
                   2756:     if (obj->type != XPATH_STRING) {
                   2757:         valuePush(ctxt, obj);
                   2758:        xmlXPathStringFunction(ctxt, 1);
                   2759:        obj = valuePop(ctxt);
                   2760:        if (obj->type != XPATH_STRING) {
                   2761:            xmlXPathFreeObject(obj);
                   2762:            return;
                   2763:        }
                   2764:     }
                   2765:     tokens = obj->stringval;
                   2766: 
                   2767:     ret = xmlXPathNewNodeSet(NULL);
                   2768:     valuePush(ctxt, ret);
                   2769:     if (tokens == NULL) {
                   2770:        xmlXPathFreeObject(obj);
                   2771:         return;
                   2772:     }
                   2773: 
                   2774:     cur = tokens;
                   2775:     
                   2776:     while (IS_BLANK(*cur)) cur++;
                   2777:     while (*cur != 0) {
                   2778:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2779:               (*cur == '.') || (*cur == '-') ||
                   2780:               (*cur == '_') || (*cur == ':') || 
                   2781:               (IS_COMBINING(*cur)) ||
                   2782:               (IS_EXTENDER(*cur)))
                   2783:               cur++;
                   2784: 
                   2785:        if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
                   2786: 
                   2787:         ID = xmlStrndup(tokens, cur - tokens);
                   2788:        attr = xmlGetID(ctxt->context->doc, ID);
                   2789:        if (attr != NULL) {
1.42      daniel   2790:            elem = attr->parent;
1.19      daniel   2791:             xmlXPathNodeSetAdd(ret->nodesetval, elem);
                   2792:         }
                   2793:        if (ID != NULL)
1.25      daniel   2794:            xmlFree(ID);
1.19      daniel   2795: 
                   2796:        while (IS_BLANK(*cur)) cur++;
                   2797:        tokens = cur;
                   2798:     }
                   2799:     xmlXPathFreeObject(obj);
                   2800:     return;
1.1       daniel   2801: }
                   2802: 
                   2803: /**
                   2804:  * xmlXPathLocalPartFunction:
                   2805:  * @ctxt:  the XPath Parser context
                   2806:  *
                   2807:  * Implement the local-part() XPath function
1.8       daniel   2808:  * The local-part function returns a string containing the local part
                   2809:  * of the name of the node in the argument node-set that is first in
                   2810:  * document order. If the node-set is empty or the first node has no
                   2811:  * name, an empty string is returned. If the argument is omitted it
                   2812:  * defaults to the context node.
1.1       daniel   2813:  */
                   2814: void
1.8       daniel   2815: xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5       daniel   2816:     xmlXPathObjectPtr cur;
                   2817: 
1.8       daniel   2818:     CHECK_ARITY(1);
                   2819:     CHECK_TYPE(XPATH_NODESET);
1.5       daniel   2820:     cur = valuePop(ctxt);
                   2821: 
                   2822:     if (cur->nodesetval->nodeNr == 0) {
1.21      daniel   2823:        valuePush(ctxt, xmlXPathNewCString(""));
1.5       daniel   2824:     } else {
                   2825:        int i = 0; /* Should be first in document order !!!!! */
                   2826:        valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
                   2827:     }
                   2828:     xmlXPathFreeObject(cur);
1.1       daniel   2829: }
                   2830: 
                   2831: /**
                   2832:  * xmlXPathNamespaceFunction:
                   2833:  * @ctxt:  the XPath Parser context
                   2834:  *
                   2835:  * Implement the namespace() XPath function
1.8       daniel   2836:  * The namespace function returns a string containing the namespace URI
                   2837:  * of the expanded name of the node in the argument node-set that is
                   2838:  * first in document order. If the node-set is empty, the first node has
                   2839:  * no name, or the expanded name has no namespace URI, an empty string
                   2840:  * is returned. If the argument is omitted it defaults to the context node.
1.1       daniel   2841:  */
                   2842: void
1.8       daniel   2843: xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5       daniel   2844:     xmlXPathObjectPtr cur;
                   2845: 
1.19      daniel   2846:     if (nargs == 0) {
                   2847:         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
                   2848:        nargs = 1;
                   2849:     }
1.8       daniel   2850:     CHECK_ARITY(1);
                   2851:     CHECK_TYPE(XPATH_NODESET);
1.5       daniel   2852:     cur = valuePop(ctxt);
                   2853: 
                   2854:     if (cur->nodesetval->nodeNr == 0) {
1.21      daniel   2855:        valuePush(ctxt, xmlXPathNewCString(""));
1.5       daniel   2856:     } else {
                   2857:        int i = 0; /* Should be first in document order !!!!! */
                   2858: 
                   2859:        if (cur->nodesetval->nodeTab[i]->ns == NULL)
1.21      daniel   2860:            valuePush(ctxt, xmlXPathNewCString(""));
1.5       daniel   2861:        else
                   2862:            valuePush(ctxt, xmlXPathNewString(
                   2863:                      cur->nodesetval->nodeTab[i]->ns->href));
                   2864:     }
                   2865:     xmlXPathFreeObject(cur);
1.1       daniel   2866: }
                   2867: 
                   2868: /**
                   2869:  * xmlXPathNameFunction:
                   2870:  * @ctxt:  the XPath Parser context
                   2871:  *
1.8       daniel   2872:  * Implement the name() XPath function
                   2873:  * The name function returns a string containing a QName representing
                   2874:  * the name of the node in the argument node-set that is first in documenti
                   2875:  * order. The QName must represent the name with respect to the namespace
                   2876:  * declarations in effect on the node whose name is being represented.
                   2877:  * Typically, this will be the form in which the name occurred in the XML
                   2878:  * source. This need not be the case if there are namespace declarations
                   2879:  * in effect on the node that associate multiple prefixes with the same
                   2880:  * namespace. However, an implementation may include information about
                   2881:  * the original prefix in its representation of nodes; in this case, an
                   2882:  * implementation can ensure that the returned string is always the same
                   2883:  * as the QName used in the XML source. If the argument it omitted it
                   2884:  * defaults to the context node.
                   2885:  * Libxml keep the original prefix so the "real qualified name" used is
                   2886:  * returned.
1.1       daniel   2887:  */
                   2888: void
1.8       daniel   2889: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5       daniel   2890:     xmlXPathObjectPtr cur;
                   2891: 
1.8       daniel   2892:     CHECK_ARITY(1);
                   2893:     CHECK_TYPE(XPATH_NODESET);
1.5       daniel   2894:     cur = valuePop(ctxt);
                   2895: 
                   2896:     if (cur->nodesetval->nodeNr == 0) {
1.21      daniel   2897:        valuePush(ctxt, xmlXPathNewCString(""));
1.5       daniel   2898:     } else {
                   2899:        int i = 0; /* Should be first in document order !!!!! */
                   2900: 
                   2901:        if (cur->nodesetval->nodeTab[i]->ns == NULL)
                   2902:            valuePush(ctxt, xmlXPathNewString(
1.8       daniel   2903:                        cur->nodesetval->nodeTab[i]->name));
                   2904:            
                   2905:        else {
1.21      daniel   2906:            char name[2000];
1.54      veillard 2907: #ifdef HAVE_SNPRINTF
                   2908:            snprintf(name, sizeof(name), "%s:%s", 
                   2909:                    (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
                   2910:                    (char *) cur->nodesetval->nodeTab[i]->name);
                   2911: #else
1.21      daniel   2912:            sprintf(name, "%s:%s", 
                   2913:                    (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
                   2914:                    (char *) cur->nodesetval->nodeTab[i]->name);
1.54      veillard 2915: #endif
                   2916:             name[sizeof(name) - 1] = 0;
1.21      daniel   2917:            valuePush(ctxt, xmlXPathNewCString(name));
1.8       daniel   2918:         }
1.5       daniel   2919:     }
                   2920:     xmlXPathFreeObject(cur);
1.1       daniel   2921: }
                   2922: 
                   2923: /**
                   2924:  * xmlXPathStringFunction:
                   2925:  * @ctxt:  the XPath Parser context
                   2926:  *
                   2927:  * Implement the string() XPath function
1.8       daniel   2928:  * he string function converts an object to a string as follows:
                   2929:  *    - A node-set is converted to a string by returning the value of
                   2930:  *      the node in the node-set that is first in document order.
                   2931:  *      If the node-set is empty, an empty string is returned.
                   2932:  *    - A number is converted to a string as follows
                   2933:  *      + NaN is converted to the string NaN 
                   2934:  *      + positive zero is converted to the string 0 
                   2935:  *      + negative zero is converted to the string 0 
                   2936:  *      + positive infinity is converted to the string Infinity 
                   2937:  *      + negative infinity is converted to the string -Infinity 
                   2938:  *      + if the number is an integer, the number is represented in
                   2939:  *        decimal form as a Number with no decimal point and no leading
                   2940:  *        zeros, preceded by a minus sign (-) if the number is negative
                   2941:  *      + otherwise, the number is represented in decimal form as a
                   2942:  *        Number including a decimal point with at least one digit
                   2943:  *        before the decimal point and at least one digit after the
                   2944:  *        decimal point, preceded by a minus sign (-) if the number
                   2945:  *        is negative; there must be no leading zeros before the decimal
                   2946:  *        point apart possibly from the one required digit immediatelyi
                   2947:  *        before the decimal point; beyond the one required digit
                   2948:  *        after the decimal point there must be as many, but only as
                   2949:  *        many, more digits as are needed to uniquely distinguish the
                   2950:  *        number from all other IEEE 754 numeric values.
                   2951:  *    - The boolean false value is converted to the string false.
                   2952:  *      The boolean true value is converted to the string true.
1.1       daniel   2953:  */
                   2954: void
1.8       daniel   2955: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5       daniel   2956:     xmlXPathObjectPtr cur;
                   2957: 
1.8       daniel   2958:     CHECK_ARITY(1);
1.5       daniel   2959:     cur = valuePop(ctxt);
1.49      daniel   2960:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
1.5       daniel   2961:     switch (cur->type) {
1.59      veillard 2962:        case XPATH_UNDEFINED:
                   2963: #ifdef DEBUG_EXPR
                   2964:            fprintf(xmlXPathDebug, "String: undefined\n");
                   2965: #endif
                   2966:            valuePush(ctxt, xmlXPathNewCString(""));
                   2967:            break;
1.5       daniel   2968:         case XPATH_NODESET:
                   2969:            if (cur->nodesetval->nodeNr == 0) {
1.21      daniel   2970:                valuePush(ctxt, xmlXPathNewCString(""));
1.5       daniel   2971:            } else {
1.29      daniel   2972:                xmlChar *res;
1.8       daniel   2973:                int i = 0; /* Should be first in document order !!!!! */
1.5       daniel   2974:                res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
                   2975:                valuePush(ctxt, xmlXPathNewString(res));
1.25      daniel   2976:                xmlFree(res);
1.5       daniel   2977:            }
                   2978:            xmlXPathFreeObject(cur);
                   2979:            return;
                   2980:        case XPATH_STRING:
                   2981:            valuePush(ctxt, cur);
                   2982:            return;
                   2983:         case XPATH_BOOLEAN:
1.21      daniel   2984:            if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
                   2985:            else valuePush(ctxt, xmlXPathNewCString("false"));
1.5       daniel   2986:            xmlXPathFreeObject(cur);
                   2987:            return;
                   2988:        case XPATH_NUMBER: {
1.21      daniel   2989:            char buf[100];
1.5       daniel   2990: 
1.10      daniel   2991:            if (isnan(cur->floatval))
                   2992:                sprintf(buf, "NaN");
                   2993:            else if (isinf(cur->floatval) > 0)
                   2994:                sprintf(buf, "+Infinity");
                   2995:            else if (isinf(cur->floatval) < 0)
                   2996:                sprintf(buf, "-Infinity");
                   2997:            else
                   2998:                sprintf(buf, "%0g", cur->floatval);
1.21      daniel   2999:            valuePush(ctxt, xmlXPathNewCString(buf));
1.11      veillard 3000:            xmlXPathFreeObject(cur);
1.5       daniel   3001:            return;
                   3002:        }
1.59      veillard 3003:        case XPATH_USERS:
1.62      veillard 3004:        case XPATH_POINT:
                   3005:        case XPATH_RANGE:
1.63      veillard 3006:        case XPATH_LOCATIONSET:
1.59      veillard 3007:            TODO
                   3008:            valuePush(ctxt, xmlXPathNewCString(""));
                   3009:            break;
1.5       daniel   3010:     }
                   3011:     STRANGE
1.1       daniel   3012: }
                   3013: 
                   3014: /**
                   3015:  * xmlXPathStringLengthFunction:
                   3016:  * @ctxt:  the XPath Parser context
                   3017:  *
                   3018:  * Implement the string-length() XPath function
1.8       daniel   3019:  * The string-length returns the number of characters in the string
                   3020:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
                   3021:  * the context node converted to a string, in other words the value
                   3022:  * of the context node.
1.1       daniel   3023:  */
                   3024: void
1.8       daniel   3025: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3026:     xmlXPathObjectPtr cur;
                   3027: 
                   3028:     if (nargs == 0) {
                   3029:        if (ctxt->context->node == NULL) {
                   3030:            valuePush(ctxt, xmlXPathNewFloat(0));
                   3031:        } else {
1.29      daniel   3032:            xmlChar *content;
1.8       daniel   3033: 
                   3034:            content = xmlNodeGetContent(ctxt->context->node);
                   3035:            valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
1.25      daniel   3036:            xmlFree(content);
1.8       daniel   3037:        }
                   3038:        return;
                   3039:     }
                   3040:     CHECK_ARITY(1);
                   3041:     CHECK_TYPE(XPATH_STRING);
                   3042:     cur = valuePop(ctxt);
                   3043:     valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
                   3044:     xmlXPathFreeObject(cur);
1.1       daniel   3045: }
                   3046: 
                   3047: /**
                   3048:  * xmlXPathConcatFunction:
                   3049:  * @ctxt:  the XPath Parser context
                   3050:  *
                   3051:  * Implement the concat() XPath function
1.8       daniel   3052:  * The concat function returns the concatenation of its arguments.
1.1       daniel   3053:  */
                   3054: void
1.8       daniel   3055: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.50      veillard 3056:     xmlXPathObjectPtr cur, newobj;
1.29      daniel   3057:     xmlChar *tmp;
1.8       daniel   3058: 
                   3059:     if (nargs < 2) {
                   3060:        CHECK_ARITY(2);
                   3061:     }
                   3062: 
                   3063:     cur = valuePop(ctxt);
                   3064:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
                   3065:         xmlXPathFreeObject(cur);
                   3066:        return;
                   3067:     }
                   3068:     nargs--;
                   3069: 
                   3070:     while (nargs > 0) {
1.50      veillard 3071:        newobj = valuePop(ctxt);
                   3072:        if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
                   3073:            xmlXPathFreeObject(newobj);
1.8       daniel   3074:            xmlXPathFreeObject(cur);
1.49      daniel   3075:            XP_ERROR(XPATH_INVALID_TYPE);
1.8       daniel   3076:        }
1.50      veillard 3077:        tmp = xmlStrcat(newobj->stringval, cur->stringval);
                   3078:        newobj->stringval = cur->stringval;
1.8       daniel   3079:        cur->stringval = tmp;
1.9       daniel   3080: 
1.50      veillard 3081:        xmlXPathFreeObject(newobj);
1.9       daniel   3082:        nargs--;
1.8       daniel   3083:     }
                   3084:     valuePush(ctxt, cur);
1.1       daniel   3085: }
                   3086: 
                   3087: /**
                   3088:  * xmlXPathContainsFunction:
                   3089:  * @ctxt:  the XPath Parser context
                   3090:  *
                   3091:  * Implement the contains() XPath function
1.8       daniel   3092:  * The contains function returns true if the first argument string
                   3093:  * contains the second argument string, and otherwise returns false.
1.1       daniel   3094:  */
                   3095: void
1.8       daniel   3096: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3097:     xmlXPathObjectPtr hay, needle;
                   3098: 
                   3099:     CHECK_ARITY(2);
                   3100:     CHECK_TYPE(XPATH_STRING);
                   3101:     needle = valuePop(ctxt);
                   3102:     hay = valuePop(ctxt);
                   3103:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
                   3104:         xmlXPathFreeObject(hay);
                   3105:         xmlXPathFreeObject(needle);
1.49      daniel   3106:        XP_ERROR(XPATH_INVALID_TYPE);
1.8       daniel   3107:     }
                   3108:     if (xmlStrstr(hay->stringval, needle->stringval))
                   3109:         valuePush(ctxt, xmlXPathNewBoolean(1));
                   3110:     else
                   3111:         valuePush(ctxt, xmlXPathNewBoolean(0));
                   3112:     xmlXPathFreeObject(hay);
                   3113:     xmlXPathFreeObject(needle);
1.1       daniel   3114: }
                   3115: 
                   3116: /**
1.9       daniel   3117:  * xmlXPathStartsWithFunction:
1.1       daniel   3118:  * @ctxt:  the XPath Parser context
                   3119:  *
1.9       daniel   3120:  * Implement the starts-with() XPath function
1.8       daniel   3121:  * The starts-with function returns true if the first argument string
                   3122:  * starts with the second argument string, and otherwise returns false.
1.1       daniel   3123:  */
                   3124: void
1.9       daniel   3125: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.8       daniel   3126:     xmlXPathObjectPtr hay, needle;
                   3127:     int n;
                   3128: 
                   3129:     CHECK_ARITY(2);
                   3130:     CHECK_TYPE(XPATH_STRING);
                   3131:     needle = valuePop(ctxt);
                   3132:     hay = valuePop(ctxt);
                   3133:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
                   3134:         xmlXPathFreeObject(hay);
                   3135:         xmlXPathFreeObject(needle);
1.49      daniel   3136:        XP_ERROR(XPATH_INVALID_TYPE);
1.8       daniel   3137:     }
                   3138:     n = xmlStrlen(needle->stringval);
                   3139:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
                   3140:         valuePush(ctxt, xmlXPathNewBoolean(0));
                   3141:     else
                   3142:         valuePush(ctxt, xmlXPathNewBoolean(1));
                   3143:     xmlXPathFreeObject(hay);
                   3144:     xmlXPathFreeObject(needle);
1.1       daniel   3145: }
                   3146: 
                   3147: /**
                   3148:  * xmlXPathSubstringFunction:
                   3149:  * @ctxt:  the XPath Parser context
                   3150:  *
                   3151:  * Implement the substring() XPath function
1.8       daniel   3152:  * The substring function returns the substring of the first argument
                   3153:  * starting at the position specified in the second argument with
                   3154:  * length specified in the third argument. For example,
                   3155:  * substring("12345",2,3) returns "234". If the third argument is not
                   3156:  * specified, it returns the substring starting at the position specified
                   3157:  * in the second argument and continuing to the end of the string. For
                   3158:  * example, substring("12345",2) returns "2345".  More precisely, each
                   3159:  * character in the string (see [3.6 Strings]) is considered to have a
                   3160:  * numeric position: the position of the first character is 1, the position
                   3161:  * of the second character is 2 and so on. The returned substring contains
                   3162:  * those characters for which the position of the character is greater than
                   3163:  * or equal to the second argument and, if the third argument is specified,
                   3164:  * less than the sum of the second and third arguments; the comparisons
                   3165:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
                   3166:  *  - substring("12345", 1.5, 2.6) returns "234" 
                   3167:  *  - substring("12345", 0, 3) returns "12" 
                   3168:  *  - substring("12345", 0 div 0, 3) returns "" 
                   3169:  *  - substring("12345", 1, 0 div 0) returns "" 
                   3170:  *  - substring("12345", -42, 1 div 0) returns "12345" 
                   3171:  *  - substring("12345", -1 div 0, 1 div 0) returns "" 
                   3172:  */
                   3173: void
                   3174: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3175:     xmlXPathObjectPtr str, start, len;
1.10      daniel   3176:     double le, in;
1.8       daniel   3177:     int i, l;
1.29      daniel   3178:     xmlChar *ret;
1.8       daniel   3179: 
                   3180:     /* 
                   3181:      * Conformance needs to be checked !!!!!
                   3182:      */
                   3183:     if (nargs < 2) {
                   3184:        CHECK_ARITY(2);
                   3185:     }
                   3186:     if (nargs > 3) {
                   3187:        CHECK_ARITY(3);
                   3188:     }
1.9       daniel   3189:     if (nargs == 3) {
                   3190:        CHECK_TYPE(XPATH_NUMBER);
                   3191:        len = valuePop(ctxt);
                   3192:        le = len->floatval;
                   3193:         xmlXPathFreeObject(len);
                   3194:     } else {
                   3195:        le = 2000000000;
                   3196:     }
                   3197:     CHECK_TYPE(XPATH_NUMBER);
                   3198:     start = valuePop(ctxt);
                   3199:     in = start->floatval;
                   3200:     xmlXPathFreeObject(start);
1.8       daniel   3201:     CHECK_TYPE(XPATH_STRING);
                   3202:     str = valuePop(ctxt);
1.9       daniel   3203:     le += in;
                   3204: 
                   3205:     /* integer index of the first char */
1.49      daniel   3206:     i = (int) in;
1.10      daniel   3207:     if (((double)i) != in) i++;
1.9       daniel   3208:     
                   3209:     /* integer index of the last char */
1.49      daniel   3210:     l = (int) le;
1.10      daniel   3211:     if (((double)l) != le) l++;
1.9       daniel   3212: 
                   3213:     /* back to a zero based len */
                   3214:     i--;
                   3215:     l--;
                   3216: 
                   3217:     /* check against the string len */
                   3218:     if (l > 1024) {
                   3219:         l = xmlStrlen(str->stringval);
1.8       daniel   3220:     }
                   3221:     if (i < 0) {
                   3222:         i = 0;
                   3223:     }
1.9       daniel   3224: 
                   3225:     /* number of chars to copy */
                   3226:     l -= i;
                   3227: 
1.8       daniel   3228:     ret = xmlStrsub(str->stringval, i, l);
                   3229:     if (ret == NULL)
1.21      daniel   3230:        valuePush(ctxt, xmlXPathNewCString(""));
1.11      veillard 3231:     else {
1.8       daniel   3232:        valuePush(ctxt, xmlXPathNewString(ret));
1.25      daniel   3233:        xmlFree(ret);
1.11      veillard 3234:     }
1.8       daniel   3235:     xmlXPathFreeObject(str);
1.1       daniel   3236: }
                   3237: 
                   3238: /**
                   3239:  * xmlXPathSubstringBeforeFunction:
                   3240:  * @ctxt:  the XPath Parser context
                   3241:  *
                   3242:  * Implement the substring-before() XPath function
1.8       daniel   3243:  * The substring-before function returns the substring of the first
                   3244:  * argument string that precedes the first occurrence of the second
                   3245:  * argument string in the first argument string, or the empty string
                   3246:  * if the first argument string does not contain the second argument
                   3247:  * string. For example, substring-before("1999/04/01","/") returns 1999.
1.1       daniel   3248:  */
                   3249: void
1.8       daniel   3250: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56      veillard 3251:   xmlXPathObjectPtr str;
                   3252:   xmlXPathObjectPtr find;
                   3253:   xmlBufferPtr target;
                   3254:   const xmlChar *point;
                   3255:   int offset;
                   3256:   
                   3257:   CHECK_ARITY(2);
                   3258:   find = valuePop(ctxt);
                   3259:   str = valuePop(ctxt);
                   3260:   
                   3261:   target = xmlBufferCreate();
                   3262:   if (target) {
                   3263:     point = xmlStrstr(str->stringval, find->stringval);
                   3264:     if (point) {
                   3265:       offset = (int)(point - str->stringval);
                   3266:       xmlBufferAdd(target, str->stringval, offset);
                   3267:     }
                   3268:     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
                   3269:     xmlBufferFree(target);
                   3270:   }
                   3271:   
                   3272:   xmlXPathFreeObject(str);
                   3273:   xmlXPathFreeObject(find);
1.1       daniel   3274: }
                   3275: 
                   3276: /**
                   3277:  * xmlXPathSubstringAfterFunction:
                   3278:  * @ctxt:  the XPath Parser context
                   3279:  *
                   3280:  * Implement the substring-after() XPath function
1.8       daniel   3281:  * The substring-after function returns the substring of the first
                   3282:  * argument string that follows the first occurrence of the second
                   3283:  * argument string in the first argument string, or the empty stringi
                   3284:  * if the first argument string does not contain the second argument
                   3285:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
                   3286:  * and substring-after("1999/04/01","19") returns 99/04/01.
1.1       daniel   3287:  */
                   3288: void
1.8       daniel   3289: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56      veillard 3290:   xmlXPathObjectPtr str;
                   3291:   xmlXPathObjectPtr find;
                   3292:   xmlBufferPtr target;
                   3293:   const xmlChar *point;
                   3294:   int offset;
                   3295:   
                   3296:   CHECK_ARITY(2);
                   3297:   find = valuePop(ctxt);
                   3298:   str = valuePop(ctxt);
                   3299:   
                   3300:   target = xmlBufferCreate();
                   3301:   if (target) {
                   3302:     point = xmlStrstr(str->stringval, find->stringval);
                   3303:     if (point) {
                   3304:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
                   3305:       xmlBufferAdd(target, &str->stringval[offset],
                   3306:                   xmlStrlen(str->stringval) - offset);
                   3307:     }
                   3308:     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
                   3309:     xmlBufferFree(target);
                   3310:   }
                   3311:   
                   3312:   xmlXPathFreeObject(str);
                   3313:   xmlXPathFreeObject(find);
1.1       daniel   3314: }
                   3315: 
                   3316: /**
                   3317:  * xmlXPathNormalizeFunction:
                   3318:  * @ctxt:  the XPath Parser context
                   3319:  *
                   3320:  * Implement the normalize() XPath function
1.8       daniel   3321:  * The normalize function returns the argument string with white
                   3322:  * space normalized by stripping leading and trailing whitespace
                   3323:  * and replacing sequences of whitespace characters by a single
                   3324:  * space. Whitespace characters are the same allowed by the S production
                   3325:  * in XML. If the argument is omitted, it defaults to the context
                   3326:  * node converted to a string, in other words the value of the context node.
1.1       daniel   3327:  */
                   3328: void
1.8       daniel   3329: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56      veillard 3330:   xmlXPathObjectPtr obj = NULL;
                   3331:   xmlChar *source = NULL;
                   3332:   xmlBufferPtr target;
                   3333:   xmlChar blank;
                   3334:   
                   3335:   if (nargs < 1) {
                   3336:     /* Use current context node */
                   3337:     CHECK_ARITY(0);
                   3338:     TODO /* source = xmlNodeGetContent(ctxt->context->node); */
                   3339:   } else if (nargs >= 1) {
                   3340:     /* Use argument */
1.8       daniel   3341:     CHECK_ARITY(1);
1.56      veillard 3342:     obj = valuePop(ctxt);
                   3343:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
                   3344:     source = obj->stringval;
                   3345:   }
                   3346:   target = xmlBufferCreate();
                   3347:   if (target && source) {
                   3348:     
                   3349:     /* Skip leading whitespaces */
                   3350:     while (IS_BLANK(*source))
                   3351:       source++;
                   3352:   
                   3353:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
                   3354:     blank = 0;
                   3355:     while (*source) {
                   3356:       if (IS_BLANK(*source)) {
                   3357:        blank = *source;
                   3358:       } else {
                   3359:        if (blank) {
                   3360:          xmlBufferAdd(target, &blank, 1);
                   3361:          blank = 0;
                   3362:        }
                   3363:        xmlBufferAdd(target, source, 1);
                   3364:       }
                   3365:       source++;
                   3366:     }
                   3367:   
                   3368:     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
                   3369:     xmlBufferFree(target);
                   3370:   }
                   3371:   if (obj)
                   3372:     xmlXPathFreeObject(obj);
1.1       daniel   3373: }
                   3374: 
                   3375: /**
                   3376:  * xmlXPathTranslateFunction:
                   3377:  * @ctxt:  the XPath Parser context
                   3378:  *
                   3379:  * Implement the translate() XPath function
1.8       daniel   3380:  * The translate function returns the first argument string with
                   3381:  * occurrences of characters in the second argument string replaced
                   3382:  * by the character at the corresponding position in the third argument
                   3383:  * string. For example, translate("bar","abc","ABC") returns the string
                   3384:  * BAr. If there is a character in the second argument string with no
                   3385:  * character at a corresponding position in the third argument string
                   3386:  * (because the second argument string is longer than the third argument
                   3387:  * string), then occurrences of that character in the first argument
                   3388:  * string are removed. For example, translate("--aaa--","abc-","ABC")
                   3389:  * returns "AAA". If a character occurs more than once in second
                   3390:  * argument string, then the first occurrence determines the replacement
                   3391:  * character. If the third argument string is longer than the second
                   3392:  * argument string, then excess characters are ignored.
                   3393:  */
                   3394: void
                   3395: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56      veillard 3396:   xmlXPathObjectPtr str;
                   3397:   xmlXPathObjectPtr from;
                   3398:   xmlXPathObjectPtr to;
                   3399:   xmlBufferPtr target;
                   3400:   int i, offset, max;
                   3401:   xmlChar ch;
                   3402:   const xmlChar *point;
                   3403: 
                   3404:   CHECK_ARITY(3);
                   3405: 
                   3406:   to = valuePop(ctxt);
                   3407:   from = valuePop(ctxt);
                   3408:   str = valuePop(ctxt);
                   3409: 
                   3410:   target = xmlBufferCreate();
                   3411:   if (target) {
                   3412:     max = xmlStrlen(to->stringval);
                   3413:     for (i = 0; (ch = str->stringval[i]); i++) {
                   3414:       point = xmlStrchr(from->stringval, ch);
                   3415:       if (point) {
                   3416:        /* Warning: This may not work with UTF-8 */
                   3417:        offset = (int)(point - from->stringval);
                   3418:        if (offset < max)
                   3419:          xmlBufferAdd(target, &to->stringval[offset], 1);
                   3420:       } else
                   3421:        xmlBufferAdd(target, &ch, 1);
                   3422:     }
                   3423:   }
                   3424:   valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
                   3425:   xmlBufferFree(target);
                   3426:   xmlXPathFreeObject(str);
                   3427:   xmlXPathFreeObject(from);
                   3428:   xmlXPathFreeObject(to);
1.1       daniel   3429: }
                   3430: 
                   3431: /**
                   3432:  * xmlXPathBooleanFunction:
                   3433:  * @ctxt:  the XPath Parser context
                   3434:  *
                   3435:  * Implement the boolean() XPath function
1.8       daniel   3436:  * he boolean function converts its argument to a boolean as follows:
                   3437:  *    - a number is true if and only if it is neither positive or
                   3438:  *      negative zero nor NaN
                   3439:  *    - a node-set is true if and only if it is non-empty
                   3440:  *    - a string is true if and only if its length is non-zero
1.1       daniel   3441:  */
                   3442: void
1.8       daniel   3443: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3444:     xmlXPathObjectPtr cur;
                   3445:     int res = 0;
                   3446: 
                   3447:     CHECK_ARITY(1);
                   3448:     cur = valuePop(ctxt);
1.49      daniel   3449:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
1.8       daniel   3450:     switch (cur->type) {
                   3451:         case XPATH_NODESET:
                   3452:            if ((cur->nodesetval == NULL) ||
                   3453:                (cur->nodesetval->nodeNr == 0)) res = 0;
                   3454:            else 
                   3455:                res = 1;
                   3456:            break;
                   3457:        case XPATH_STRING:
                   3458:            if ((cur->stringval == NULL) ||
                   3459:                (cur->stringval[0] == 0)) res = 0;
                   3460:            else 
                   3461:                res = 1;
                   3462:            break;
                   3463:         case XPATH_BOOLEAN:
                   3464:            valuePush(ctxt, cur);
                   3465:            return;
                   3466:        case XPATH_NUMBER:
                   3467:            if (cur->floatval) res = 1;
                   3468:            break;
                   3469:        default:
                   3470:            STRANGE
                   3471:     }
                   3472:     xmlXPathFreeObject(cur);
                   3473:     valuePush(ctxt, xmlXPathNewBoolean(res));
1.1       daniel   3474: }
                   3475: 
                   3476: /**
                   3477:  * xmlXPathNotFunction:
                   3478:  * @ctxt:  the XPath Parser context
                   3479:  *
                   3480:  * Implement the not() XPath function
1.8       daniel   3481:  * The not function returns true if its argument is false,
                   3482:  * and false otherwise.
1.1       daniel   3483:  */
                   3484: void
1.8       daniel   3485: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3486:     CHECK_ARITY(1);
                   3487:     CHECK_TYPE(XPATH_BOOLEAN);
                   3488:     ctxt->value->boolval = ! ctxt->value->boolval;
1.1       daniel   3489: }
                   3490: 
                   3491: /**
                   3492:  * xmlXPathTrueFunction:
                   3493:  * @ctxt:  the XPath Parser context
                   3494:  *
                   3495:  * Implement the true() XPath function
                   3496:  */
                   3497: void
1.8       daniel   3498: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3499:     CHECK_ARITY(0);
                   3500:     valuePush(ctxt, xmlXPathNewBoolean(1));
1.1       daniel   3501: }
                   3502: 
                   3503: /**
                   3504:  * xmlXPathFalseFunction:
                   3505:  * @ctxt:  the XPath Parser context
                   3506:  *
                   3507:  * Implement the false() XPath function
                   3508:  */
                   3509: void
1.8       daniel   3510: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3511:     CHECK_ARITY(0);
                   3512:     valuePush(ctxt, xmlXPathNewBoolean(0));
1.1       daniel   3513: }
                   3514: 
                   3515: /**
                   3516:  * xmlXPathLangFunction:
                   3517:  * @ctxt:  the XPath Parser context
                   3518:  *
                   3519:  * Implement the lang() XPath function
1.8       daniel   3520:  * The lang function returns true or false depending on whether the
                   3521:  * language of the context node as specified by xml:lang attributes
                   3522:  * is the same as or is a sublanguage of the language specified by
                   3523:  * the argument string. The language of the context node is determined
                   3524:  * by the value of the xml:lang attribute on the context node, or, if
                   3525:  * the context node has no xml:lang attribute, by the value of the
                   3526:  * xml:lang attribute on the nearest ancestor of the context node that
                   3527:  * has an xml:lang attribute. If there is no such attribute, then lang
                   3528:  * returns false. If there is such an attribute, then lang returns
                   3529:  * true if the attribute value is equal to the argument ignoring case,
                   3530:  * or if there is some suffix starting with - such that the attribute
                   3531:  * value is equal to the argument ignoring that suffix of the attribute
                   3532:  * value and ignoring case.
                   3533:  */
                   3534: void
                   3535: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.19      daniel   3536:     xmlXPathObjectPtr val;
1.29      daniel   3537:     const xmlChar *theLang;
                   3538:     const xmlChar *lang;
1.19      daniel   3539:     int ret = 0;
                   3540:     int i;
                   3541: 
                   3542:     CHECK_ARITY(1);
                   3543:     CHECK_TYPE(XPATH_STRING);
                   3544:     val = valuePop(ctxt);
                   3545:     lang = val->stringval;
                   3546:     theLang = xmlNodeGetLang(ctxt->context->node);
                   3547:     if ((theLang != NULL) && (lang != NULL)) {
                   3548:         for (i = 0;lang[i] != 0;i++)
                   3549:            if (toupper(lang[i]) != toupper(theLang[i]))
                   3550:                goto not_equal;
                   3551:         ret = 1;
                   3552:     }
                   3553: not_equal:
                   3554:     xmlXPathFreeObject(val);
                   3555:     valuePush(ctxt, xmlXPathNewBoolean(ret));
1.1       daniel   3556: }
                   3557: 
                   3558: /**
                   3559:  * xmlXPathNumberFunction:
                   3560:  * @ctxt:  the XPath Parser context
                   3561:  *
                   3562:  * Implement the number() XPath function
                   3563:  */
                   3564: void
1.8       daniel   3565: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5       daniel   3566:     xmlXPathObjectPtr cur;
1.10      daniel   3567:     double res;
1.5       daniel   3568: 
1.8       daniel   3569:     CHECK_ARITY(1);
1.5       daniel   3570:     cur = valuePop(ctxt);
                   3571:     switch (cur->type) {
1.59      veillard 3572:        case XPATH_UNDEFINED:
                   3573: #ifdef DEBUG_EXPR
                   3574:            fprintf(xmlXPathDebug, "NUMBER: undefined\n");
                   3575: #endif
                   3576:            valuePush(ctxt, xmlXPathNewFloat(0.0));
                   3577:            break;
1.5       daniel   3578:         case XPATH_NODESET:
                   3579:            valuePush(ctxt, cur);
1.8       daniel   3580:            xmlXPathStringFunction(ctxt, 1);
1.5       daniel   3581:            cur = valuePop(ctxt);
                   3582:        case XPATH_STRING:
                   3583:            res = xmlXPathStringEvalNumber(cur->stringval);
                   3584:            valuePush(ctxt, xmlXPathNewFloat(res));
                   3585:            xmlXPathFreeObject(cur);
                   3586:            return;
                   3587:         case XPATH_BOOLEAN:
                   3588:            if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
                   3589:            else valuePush(ctxt, xmlXPathNewFloat(0.0));
                   3590:            xmlXPathFreeObject(cur);
                   3591:            return;
                   3592:        case XPATH_NUMBER:
                   3593:            valuePush(ctxt, cur);
                   3594:            return;
1.59      veillard 3595:        case XPATH_USERS:
1.62      veillard 3596:        case XPATH_POINT:
                   3597:        case XPATH_RANGE:
1.63      veillard 3598:        case XPATH_LOCATIONSET:
1.59      veillard 3599:            TODO
                   3600:            valuePush(ctxt, xmlXPathNewFloat(0.0));
                   3601:            break;
1.5       daniel   3602:     }
                   3603:     STRANGE
1.1       daniel   3604: }
                   3605: 
                   3606: /**
                   3607:  * xmlXPathSumFunction:
                   3608:  * @ctxt:  the XPath Parser context
                   3609:  *
                   3610:  * Implement the sum() XPath function
1.8       daniel   3611:  * The sum function returns the sum of the values of the nodes in
                   3612:  * the argument node-set.
1.1       daniel   3613:  */
                   3614: void
1.8       daniel   3615: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3616:     CHECK_ARITY(1);
                   3617:     TODO /* BUG Sum : don't understand the definition */
1.1       daniel   3618: }
                   3619: 
                   3620: /**
                   3621:  * xmlXPathFloorFunction:
                   3622:  * @ctxt:  the XPath Parser context
                   3623:  *
                   3624:  * Implement the floor() XPath function
1.8       daniel   3625:  * The floor function returns the largest (closest to positive infinity)
                   3626:  * number that is not greater than the argument and that is an integer.
1.1       daniel   3627:  */
                   3628: void
1.8       daniel   3629: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   3630:     CHECK_ARITY(1);
                   3631:     CHECK_TYPE(XPATH_NUMBER);
1.9       daniel   3632:     /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
1.10      daniel   3633:     ctxt->value->floatval = (double)((int) ctxt->value->floatval);
1.1       daniel   3634: }
                   3635: 
                   3636: /**
                   3637:  * xmlXPathCeilingFunction:
                   3638:  * @ctxt:  the XPath Parser context
                   3639:  *
                   3640:  * Implement the ceiling() XPath function
1.8       daniel   3641:  * The ceiling function returns the smallest (closest to negative infinity)
                   3642:  * number that is not less than the argument and that is an integer.
1.1       daniel   3643:  */
                   3644: void
1.8       daniel   3645: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.10      daniel   3646:     double f;
1.8       daniel   3647: 
                   3648:     CHECK_ARITY(1);
                   3649:     CHECK_TYPE(XPATH_NUMBER);
1.10      daniel   3650:     f = (double)((int) ctxt->value->floatval);
1.8       daniel   3651:     if (f != ctxt->value->floatval)
                   3652:        ctxt->value->floatval = f + 1;
1.1       daniel   3653: }
                   3654: 
                   3655: /**
                   3656:  * xmlXPathRoundFunction:
                   3657:  * @ctxt:  the XPath Parser context
                   3658:  *
                   3659:  * Implement the round() XPath function
1.8       daniel   3660:  * The round function returns the number that is closest to the
                   3661:  * argument and that is an integer. If there are two such numbers,
                   3662:  * then the one that is even is returned.
                   3663:  */
                   3664: void
                   3665: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.10      daniel   3666:     double f;
1.8       daniel   3667: 
                   3668:     CHECK_ARITY(1);
                   3669:     CHECK_TYPE(XPATH_NUMBER);
1.9       daniel   3670:     /* round(0.50000001) => 0  !!!!! */
1.10      daniel   3671:     f = (double)((int) ctxt->value->floatval);
1.8       daniel   3672:     if (ctxt->value->floatval < f + 0.5)
                   3673:         ctxt->value->floatval = f;
                   3674:     else if (ctxt->value->floatval == f + 0.5)
                   3675:         ctxt->value->floatval = f; /* !!!! Not following the spec here */
                   3676:     else 
                   3677:         ctxt->value->floatval = f + 1;
1.1       daniel   3678: }
                   3679: 
                   3680: /************************************************************************
                   3681:  *                                                                     *
                   3682:  *                     The Parser                                      *
                   3683:  *                                                                     *
                   3684:  ************************************************************************/
                   3685: 
1.4       daniel   3686: /*
                   3687:  * a couple of forward declarations since we use a recursive call based
                   3688:  * implementation.
                   3689:  */
1.1       daniel   3690: void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
1.4       daniel   3691: void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
                   3692: void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
                   3693: void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
1.1       daniel   3694: 
                   3695: /**
                   3696:  * xmlXPathParseNCName:
                   3697:  * @ctxt:  the XPath Parser context
                   3698:  *
                   3699:  * parse an XML namespace non qualified name.
                   3700:  *
                   3701:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
                   3702:  *
                   3703:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
                   3704:  *                       CombiningChar | Extender
                   3705:  *
                   3706:  * Returns the namespace name or NULL
                   3707:  */
                   3708: 
1.29      daniel   3709: xmlChar *
1.1       daniel   3710: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
1.29      daniel   3711:     const xmlChar *q;
                   3712:     xmlChar *ret = NULL;
1.1       daniel   3713: 
                   3714:     if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
                   3715:     q = NEXT;
                   3716: 
                   3717:     while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
                   3718:            (CUR == '.') || (CUR == '-') ||
                   3719:           (CUR == '_') ||
                   3720:           (IS_COMBINING(CUR)) ||
                   3721:           (IS_EXTENDER(CUR)))
                   3722:        NEXT;
                   3723:     
                   3724:     ret = xmlStrndup(q, CUR_PTR - q);
                   3725: 
                   3726:     return(ret);
                   3727: }
                   3728: 
                   3729: /**
                   3730:  * xmlXPathParseQName:
                   3731:  * @ctxt:  the XPath Parser context
1.29      daniel   3732:  * @prefix:  a xmlChar ** 
1.1       daniel   3733:  *
                   3734:  * parse an XML qualified name
                   3735:  *
                   3736:  * [NS 5] QName ::= (Prefix ':')? LocalPart
                   3737:  *
                   3738:  * [NS 6] Prefix ::= NCName
                   3739:  *
                   3740:  * [NS 7] LocalPart ::= NCName
                   3741:  *
                   3742:  * Returns the function returns the local part, and prefix is updated
                   3743:  *   to get the Prefix if any.
                   3744:  */
                   3745: 
1.29      daniel   3746: xmlChar *
                   3747: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
                   3748:     xmlChar *ret = NULL;
1.1       daniel   3749: 
                   3750:     *prefix = NULL;
                   3751:     ret = xmlXPathParseNCName(ctxt);
                   3752:     if (CUR == ':') {
                   3753:         *prefix = ret;
                   3754:        NEXT;
                   3755:        ret = xmlXPathParseNCName(ctxt);
                   3756:     }
                   3757:     return(ret);
                   3758: }
                   3759: 
                   3760: /**
1.74      veillard 3761:  * xmlXPathParseName:
                   3762:  * @ctxt:  the XPointer Parser context
                   3763:  *
                   3764:  * parse an XML name
                   3765:  *
                   3766:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                   3767:  *                  CombiningChar | Extender
                   3768:  *
                   3769:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                   3770:  *
                   3771:  * Returns the namespace name or NULL
                   3772:  */
                   3773: 
                   3774: xmlChar *
                   3775: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
                   3776:     const xmlChar *q;
                   3777:     xmlChar *ret = NULL;
                   3778: 
                   3779:     if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
                   3780:     q = NEXT;
                   3781: 
                   3782:     /* TODO Make this UTF8 compliant !!! */
                   3783:     while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
                   3784:            (CUR == '.') || (CUR == '-') ||
                   3785:           (CUR == '_') || (CUR == ':') ||
                   3786:           (IS_COMBINING(CUR)) ||
                   3787:           (IS_EXTENDER(CUR)))
                   3788:        NEXT;
                   3789:     
                   3790:     ret = xmlStrndup(q, CUR_PTR - q);
                   3791: 
                   3792:     return(ret);
                   3793: }
                   3794: 
                   3795: /**
1.5       daniel   3796:  * xmlXPathStringEvalNumber:
                   3797:  * @str:  A string to scan
                   3798:  *
                   3799:  *  [30]   Number ::=   Digits ('.' Digits)?
                   3800:  *                    | '.' Digits 
                   3801:  *  [31]   Digits ::=   [0-9]+
                   3802:  *
                   3803:  * Parse and evaluate a Number in the string
                   3804:  *
                   3805:  * BUG: "1.' is not valid ... James promised correction
                   3806:  *       as Digits ('.' Digits?)?
                   3807:  *
1.10      daniel   3808:  * Returns the double value.
1.5       daniel   3809:  */
1.10      daniel   3810: double
1.29      daniel   3811: xmlXPathStringEvalNumber(const xmlChar *str) {
                   3812:     const xmlChar *cur = str;
1.10      daniel   3813:     double ret = 0.0;
                   3814:     double mult = 1;
1.5       daniel   3815:     int ok = 0;
                   3816: 
                   3817:     while (*cur == ' ') cur++;
                   3818:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
1.10      daniel   3819:         return(xmlXPathNAN);
1.5       daniel   3820:     }
                   3821:     while ((*cur >= '0') && (*cur <= '9')) {
                   3822:         ret = ret * 10 + (*cur - '0');
                   3823:        ok = 1;
                   3824:        cur++;
                   3825:     }
                   3826:     if (*cur == '.') {
                   3827:         cur++;
                   3828:        if (((*cur < '0') || (*cur > '9')) && (!ok)) {
1.10      daniel   3829:            return(xmlXPathNAN);
1.5       daniel   3830:        }
                   3831:        while ((*cur >= '0') && (*cur <= '9')) {
                   3832:            mult /= 10;
                   3833:            ret = ret  + (*cur - '0') * mult;
                   3834:            cur++;
                   3835:        }
                   3836:     }
                   3837:     while (*cur == ' ') cur++;
1.10      daniel   3838:     if (*cur != 0) return(xmlXPathNAN);
1.5       daniel   3839:     return(ret);
                   3840: }
                   3841: 
                   3842: /**
1.1       daniel   3843:  * xmlXPathEvalNumber:
                   3844:  * @ctxt:  the XPath Parser context
                   3845:  *
                   3846:  *  [30]   Number ::=   Digits ('.' Digits)?
                   3847:  *                    | '.' Digits 
                   3848:  *  [31]   Digits ::=   [0-9]+
                   3849:  *
                   3850:  * Parse and evaluate a Number, then push it on the stack
                   3851:  *
1.4       daniel   3852:  * BUG: "1.' is not valid ... James promised correction
                   3853:  *       as Digits ('.' Digits?)?
1.1       daniel   3854:  */
                   3855: void
                   3856: xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
1.10      daniel   3857:     double ret = 0.0;
                   3858:     double mult = 1;
1.4       daniel   3859:     int ok = 0;
1.1       daniel   3860: 
                   3861:     CHECK_ERROR;
                   3862:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
1.49      daniel   3863:         XP_ERROR(XPATH_NUMBER_ERROR);
1.1       daniel   3864:     }
                   3865:     while ((CUR >= '0') && (CUR <= '9')) {
                   3866:         ret = ret * 10 + (CUR - '0');
1.4       daniel   3867:        ok = 1;
1.1       daniel   3868:        NEXT;
                   3869:     }
                   3870:     if (CUR == '.') {
                   3871:         NEXT;
1.4       daniel   3872:        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
1.49      daniel   3873:             XP_ERROR(XPATH_NUMBER_ERROR);
1.1       daniel   3874:        }
                   3875:        while ((CUR >= '0') && (CUR <= '9')) {
                   3876:            mult /= 10;
                   3877:            ret = ret  + (CUR - '0') * mult;
                   3878:            NEXT;
                   3879:        }
                   3880:     }
                   3881:     valuePush(ctxt, xmlXPathNewFloat(ret));
                   3882: }
                   3883: 
                   3884: /**
                   3885:  * xmlXPathEvalLiteral:
                   3886:  * @ctxt:  the XPath Parser context
                   3887:  *
                   3888:  * Parse a Literal and push it on the stack.
                   3889:  *
                   3890:  *  [29]   Literal ::=   '"' [^"]* '"'
                   3891:  *                    | "'" [^']* "'"
                   3892:  *
1.22      daniel   3893:  * TODO: xmlXPathEvalLiteral memory allocation could be improved.
1.1       daniel   3894:  */
                   3895: void
                   3896: xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
1.29      daniel   3897:     const xmlChar *q;
                   3898:     xmlChar *ret = NULL;
1.1       daniel   3899: 
                   3900:     if (CUR == '"') {
                   3901:         NEXT;
                   3902:        q = CUR_PTR;
                   3903:        while ((IS_CHAR(CUR)) && (CUR != '"'))
                   3904:            NEXT;
                   3905:        if (!IS_CHAR(CUR)) {
1.49      daniel   3906:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
1.1       daniel   3907:        } else {
                   3908:            ret = xmlStrndup(q, CUR_PTR - q);
                   3909:            NEXT;
                   3910:         }
                   3911:     } else if (CUR == '\'') {
                   3912:         NEXT;
                   3913:        q = CUR_PTR;
                   3914:        while ((IS_CHAR(CUR)) && (CUR != '\''))
                   3915:            NEXT;
                   3916:        if (!IS_CHAR(CUR)) {
1.49      daniel   3917:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
1.1       daniel   3918:        } else {
                   3919:            ret = xmlStrndup(q, CUR_PTR - q);
                   3920:            NEXT;
                   3921:         }
                   3922:     } else {
1.49      daniel   3923:        XP_ERROR(XPATH_START_LITERAL_ERROR);
1.1       daniel   3924:     }
                   3925:     if (ret == NULL) return;
                   3926:     valuePush(ctxt, xmlXPathNewString(ret));
1.25      daniel   3927:     xmlFree(ret);
1.1       daniel   3928: }
                   3929: 
                   3930: /**
                   3931:  * xmlXPathEvalVariableReference:
                   3932:  * @ctxt:  the XPath Parser context
                   3933:  *
                   3934:  * Parse a VariableReference, evaluate it and push it on the stack.
                   3935:  *
                   3936:  * The variable bindings consist of a mapping from variable names
                   3937:  * to variable values. The value of a variable is an object, which
                   3938:  * of any of the types that are possible for the value of an expression,
                   3939:  * and may also be of additional types not specified here.
                   3940:  *
                   3941:  * Early evaluation is possible since:
                   3942:  * The variable bindings [...] used to evaluate a subexpression are
                   3943:  * always the same as those used to evaluate the containing expression. 
                   3944:  *
                   3945:  *  [36]   VariableReference ::=   '$' QName 
                   3946:  */
                   3947: void
                   3948: xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
1.29      daniel   3949:     xmlChar *name;
1.1       daniel   3950:     xmlXPathObjectPtr value;
                   3951: 
1.68      veillard 3952:     SKIP_BLANKS;
1.1       daniel   3953:     if (CUR != '$') {
1.49      daniel   3954:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
1.1       daniel   3955:     }
1.74      veillard 3956:     name = xmlXPathParseName(ctxt);
1.1       daniel   3957:     if (name == NULL) {
1.49      daniel   3958:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
1.1       daniel   3959:     }
1.74      veillard 3960:     value = xmlXPathVariableLookup(ctxt->context, name);
1.1       daniel   3961:     if (value == NULL) {
1.49      daniel   3962:        XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
1.1       daniel   3963:     }
                   3964:     valuePush(ctxt, value);
1.25      daniel   3965:     xmlFree(name);
1.68      veillard 3966:     SKIP_BLANKS;
1.1       daniel   3967: }
                   3968: 
1.65      veillard 3969: /**
                   3970:  * xmlXPathIsNodeType:
                   3971:  * @ctxt:  the XPath Parser context
                   3972:  * @name:  a name string
                   3973:  *
                   3974:  * Is the name given a NodeType one.
                   3975:  *
                   3976:  *  [38]   NodeType ::=   'comment'
                   3977:  *                    | 'text'
                   3978:  *                    | 'processing-instruction'
                   3979:  *                    | 'node'
                   3980:  *
                   3981:  * Returns 1 if true 0 otherwise
                   3982:  */
                   3983: int
                   3984: xmlXPathIsNodeType(const xmlChar *name) {
                   3985:     if (name == NULL)
                   3986:        return(0);
                   3987: 
                   3988:     if (xmlStrEqual(name, BAD_CAST "comment"))
                   3989:        return(1);
                   3990:     if (xmlStrEqual(name, BAD_CAST "text"))
                   3991:        return(1);
                   3992:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
                   3993:        return(1);
                   3994:     if (xmlStrEqual(name, BAD_CAST "node"))
                   3995:        return(1);
                   3996:     return(0);
                   3997: }
                   3998: 
1.1       daniel   3999:  
                   4000: /**
1.65      veillard 4001:  * xmlXPathIsFunction:
1.1       daniel   4002:  * @ctxt:  the XPath Parser context
                   4003:  * @name:  a name string
                   4004:  *
                   4005:  * Search for a function of the given name
                   4006:  *
                   4007:  *  [35]   FunctionName ::=   QName - NodeType 
                   4008:  *
1.22      daniel   4009:  * TODO: for the moment the function list is hardcoded from the spec !!!!
1.1       daniel   4010:  *
                   4011:  * Returns the xmlXPathFunction if found, or NULL otherwise
                   4012:  */
                   4013: xmlXPathFunction
1.29      daniel   4014: xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
1.74      veillard 4015:     if (name == NULL)
                   4016:        return(NULL);
                   4017: 
1.1       daniel   4018:     switch (name[0]) {
                   4019:         case 'b':
1.58      veillard 4020:            if (xmlStrEqual(name, BAD_CAST "boolean"))
1.9       daniel   4021:                return(xmlXPathBooleanFunction);
1.1       daniel   4022:            break;
                   4023:         case 'c':
1.58      veillard 4024:            if (xmlStrEqual(name, BAD_CAST "ceiling"))
1.9       daniel   4025:                return(xmlXPathCeilingFunction);
1.58      veillard 4026:            if (xmlStrEqual(name, BAD_CAST "count"))
1.9       daniel   4027:                return(xmlXPathCountFunction);
1.58      veillard 4028:            if (xmlStrEqual(name, BAD_CAST "concat"))
1.9       daniel   4029:                return(xmlXPathConcatFunction);
1.58      veillard 4030:            if (xmlStrEqual(name, BAD_CAST "contains"))
1.9       daniel   4031:                return(xmlXPathContainsFunction);
1.1       daniel   4032:            break;
                   4033:         case 'i':
1.58      veillard 4034:            if (xmlStrEqual(name, BAD_CAST "id"))
1.9       daniel   4035:                return(xmlXPathIdFunction);
1.1       daniel   4036:            break;
                   4037:         case 'f':
1.58      veillard 4038:            if (xmlStrEqual(name, BAD_CAST "false"))
1.9       daniel   4039:                return(xmlXPathFalseFunction);
1.58      veillard 4040:            if (xmlStrEqual(name, BAD_CAST "floor"))
1.9       daniel   4041:                return(xmlXPathFloorFunction);
1.1       daniel   4042:            break;
                   4043:         case 'l':
1.58      veillard 4044:            if (xmlStrEqual(name, BAD_CAST "last"))
1.9       daniel   4045:                return(xmlXPathLastFunction);
1.58      veillard 4046:            if (xmlStrEqual(name, BAD_CAST "lang"))
1.9       daniel   4047:                return(xmlXPathLangFunction);
1.58      veillard 4048:            if (xmlStrEqual(name, BAD_CAST "local-part"))
1.9       daniel   4049:                return(xmlXPathLocalPartFunction);
1.1       daniel   4050:            break;
                   4051:         case 'n':
1.58      veillard 4052:            if (xmlStrEqual(name, BAD_CAST "not"))
1.9       daniel   4053:                return(xmlXPathNotFunction);
1.58      veillard 4054:            if (xmlStrEqual(name, BAD_CAST "name"))
1.9       daniel   4055:                return(xmlXPathNameFunction);
1.58      veillard 4056:            if (xmlStrEqual(name, BAD_CAST "namespace"))
1.9       daniel   4057:                return(xmlXPathNamespaceFunction);
1.58      veillard 4058:            if (xmlStrEqual(name, BAD_CAST "normalize-space"))
1.30      daniel   4059:                return(xmlXPathNormalizeFunction);
1.58      veillard 4060:            if (xmlStrEqual(name, BAD_CAST "normalize"))
1.9       daniel   4061:                return(xmlXPathNormalizeFunction);
1.58      veillard 4062:            if (xmlStrEqual(name, BAD_CAST "number"))
1.9       daniel   4063:                return(xmlXPathNumberFunction);
1.1       daniel   4064:            break;
                   4065:         case 'p':
1.58      veillard 4066:            if (xmlStrEqual(name, BAD_CAST "position"))
1.9       daniel   4067:                return(xmlXPathPositionFunction);
1.1       daniel   4068:            break;
                   4069:         case 'r':
1.58      veillard 4070:            if (xmlStrEqual(name, BAD_CAST "round"))
1.9       daniel   4071:                return(xmlXPathRoundFunction);
1.1       daniel   4072:            break;
                   4073:         case 's':
1.58      veillard 4074:            if (xmlStrEqual(name, BAD_CAST "string"))
1.9       daniel   4075:                return(xmlXPathStringFunction);
1.58      veillard 4076:            if (xmlStrEqual(name, BAD_CAST "string-length"))
1.9       daniel   4077:                return(xmlXPathStringLengthFunction);
1.58      veillard 4078:            if (xmlStrEqual(name, BAD_CAST "starts-with"))
1.9       daniel   4079:                return(xmlXPathStartsWithFunction);
1.58      veillard 4080:            if (xmlStrEqual(name, BAD_CAST "substring"))
1.9       daniel   4081:                return(xmlXPathSubstringFunction);
1.58      veillard 4082:            if (xmlStrEqual(name, BAD_CAST "substring-before"))
1.9       daniel   4083:                return(xmlXPathSubstringBeforeFunction);
1.58      veillard 4084:            if (xmlStrEqual(name, BAD_CAST "substring-after"))
1.9       daniel   4085:                return(xmlXPathSubstringAfterFunction);
1.58      veillard 4086:            if (xmlStrEqual(name, BAD_CAST "sum"))
1.9       daniel   4087:                return(xmlXPathSumFunction);
1.1       daniel   4088:            break;
                   4089:         case 't':
1.58      veillard 4090:            if (xmlStrEqual(name, BAD_CAST "true"))
1.9       daniel   4091:                return(xmlXPathTrueFunction);
1.58      veillard 4092:            if (xmlStrEqual(name, BAD_CAST "translate"))
1.9       daniel   4093:                return(xmlXPathTranslateFunction);
1.1       daniel   4094:            break;
                   4095:     }
1.74      veillard 4096:     return(xmlXPathFunctionLookup(ctxt->context, name));
1.1       daniel   4097: }
                   4098:  
                   4099: /**
                   4100:  * xmlXPathEvalFunctionCall:
                   4101:  * @ctxt:  the XPath Parser context
                   4102:  *
                   4103:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
                   4104:  *  [17]   Argument ::=   Expr 
                   4105:  *
1.5       daniel   4106:  * Parse and evaluate a function call, the evaluation of all arguments are
                   4107:  * pushed on the stack
1.1       daniel   4108:  */
                   4109: void
                   4110: xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
1.29      daniel   4111:     xmlChar *name;
                   4112:     xmlChar *prefix;
1.4       daniel   4113:     xmlXPathFunction func;
1.8       daniel   4114:     int nbargs = 0;
1.4       daniel   4115: 
                   4116:     name = xmlXPathParseQName(ctxt, &prefix);
                   4117:     if (name == NULL) {
1.49      daniel   4118:        XP_ERROR(XPATH_EXPR_ERROR);
1.4       daniel   4119:     }
1.30      daniel   4120:     SKIP_BLANKS;
1.4       daniel   4121:     func = xmlXPathIsFunction(ctxt, name);
                   4122:     if (func == NULL) {
1.25      daniel   4123:         xmlFree(name);
1.49      daniel   4124:        XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
1.4       daniel   4125:     }
1.6       daniel   4126: #ifdef DEBUG_EXPR
1.9       daniel   4127:     fprintf(xmlXPathDebug, "Calling function %s\n", name);
1.6       daniel   4128: #endif
                   4129: 
1.5       daniel   4130:     if (CUR != '(') {
1.25      daniel   4131:         xmlFree(name);
1.49      daniel   4132:        XP_ERROR(XPATH_EXPR_ERROR);
1.5       daniel   4133:     }
                   4134:     NEXT;
1.30      daniel   4135:     SKIP_BLANKS;
1.8       daniel   4136: 
1.5       daniel   4137:     while (CUR != ')') {
                   4138:         xmlXPathEvalExpr(ctxt);
1.8       daniel   4139:        nbargs++;
1.5       daniel   4140:        if (CUR == ')') break;
                   4141:        if (CUR != ',') {
1.25      daniel   4142:            xmlFree(name);
1.49      daniel   4143:            XP_ERROR(XPATH_EXPR_ERROR);
1.5       daniel   4144:        }
1.9       daniel   4145:        NEXT;
1.30      daniel   4146:        SKIP_BLANKS;
1.5       daniel   4147:     }
                   4148:     NEXT;
1.30      daniel   4149:     SKIP_BLANKS;
1.25      daniel   4150:     xmlFree(name);
1.8       daniel   4151:     func(ctxt, nbargs);
1.1       daniel   4152: }
                   4153: 
                   4154: /**
                   4155:  * xmlXPathEvalPrimaryExpr:
                   4156:  * @ctxt:  the XPath Parser context
                   4157:  *
                   4158:  *  [15]   PrimaryExpr ::=   VariableReference 
                   4159:  *                | '(' Expr ')'
                   4160:  *                | Literal 
                   4161:  *                | Number 
                   4162:  *                | FunctionCall 
                   4163:  *
                   4164:  * Parse and evaluate a primary expression, then push the result on the stack
                   4165:  */
                   4166: void
                   4167: xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
1.30      daniel   4168:     SKIP_BLANKS;
1.1       daniel   4169:     if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
                   4170:     else if (CUR == '(') {
1.65      veillard 4171:        NEXT;
1.30      daniel   4172:        SKIP_BLANKS;
1.65      veillard 4173:        xmlXPathEvalExpr(ctxt);
1.1       daniel   4174:        if (CUR != ')') {
1.49      daniel   4175:            XP_ERROR(XPATH_EXPR_ERROR);
1.1       daniel   4176:        }
                   4177:        NEXT;
1.30      daniel   4178:        SKIP_BLANKS;
1.1       daniel   4179:     } else if (IS_DIGIT(CUR)) {
1.65      veillard 4180:        xmlXPathEvalNumber(ctxt);
1.1       daniel   4181:     } else if ((CUR == '\'') || (CUR == '"')) {
1.65      veillard 4182:        xmlXPathEvalLiteral(ctxt);
1.1       daniel   4183:     } else {
1.65      veillard 4184:        xmlXPathEvalFunctionCall(ctxt);
1.1       daniel   4185:     }
1.68      veillard 4186:     SKIP_BLANKS;
1.1       daniel   4187: }
                   4188: 
                   4189: /**
1.4       daniel   4190:  * xmlXPathEvalFilterExpr:
                   4191:  * @ctxt:  the XPath Parser context
                   4192:  *
                   4193:  *  [20]   FilterExpr ::=   PrimaryExpr 
                   4194:  *               | FilterExpr Predicate 
                   4195:  *
                   4196:  * Parse and evaluate a filter expression, then push the result on the stack
1.8       daniel   4197:  * Square brackets are used to filter expressions in the same way that
                   4198:  * they are used in location paths. It is an error if the expression to
                   4199:  * be filtered does not evaluate to a node-set. The context node list
                   4200:  * used for evaluating the expression in square brackets is the node-set
                   4201:  * to be filtered listed in document order.
1.4       daniel   4202:  */
                   4203: 
                   4204: void
                   4205: xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
                   4206:     xmlXPathEvalPrimaryExpr(ctxt);
                   4207:     CHECK_ERROR;
1.30      daniel   4208:     SKIP_BLANKS;
1.8       daniel   4209:     
                   4210:     if (CUR != '[') return;
                   4211: 
                   4212:     CHECK_TYPE(XPATH_NODESET);
                   4213: 
1.4       daniel   4214:     while (CUR == '[') {
                   4215:        xmlXPathEvalPredicate(ctxt);
1.30      daniel   4216:        SKIP_BLANKS;
1.8       daniel   4217:     }
1.4       daniel   4218: 
1.8       daniel   4219:     
1.4       daniel   4220: }
                   4221: 
                   4222: /**
1.19      daniel   4223:  * xmlXPathScanName:
                   4224:  * @ctxt:  the XPath Parser context
                   4225:  *
                   4226:  * Trickery: parse an XML name but without consuming the input flow
1.66      veillard 4227:  * Needed to avoid insanity in the parser state.
1.19      daniel   4228:  *
                   4229:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                   4230:  *                  CombiningChar | Extender
                   4231:  *
                   4232:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                   4233:  *
                   4234:  * [6] Names ::= Name (S Name)*
                   4235:  *
                   4236:  * Returns the Name parsed or NULL
                   4237:  */
                   4238: 
1.29      daniel   4239: xmlChar *
1.19      daniel   4240: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
1.29      daniel   4241:     xmlChar buf[XML_MAX_NAMELEN];
1.19      daniel   4242:     int len = 0;
                   4243: 
1.30      daniel   4244:     SKIP_BLANKS;
1.19      daniel   4245:     if (!IS_LETTER(CUR) && (CUR != '_') &&
                   4246:         (CUR != ':')) {
                   4247:        return(NULL);
                   4248:     }
                   4249: 
                   4250:     while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
                   4251:            (NXT(len) == '.') || (NXT(len) == '-') ||
                   4252:           (NXT(len) == '_') || (NXT(len) == ':') || 
                   4253:           (IS_COMBINING(NXT(len))) ||
                   4254:           (IS_EXTENDER(NXT(len)))) {
                   4255:        buf[len] = NXT(len);
                   4256:        len++;
                   4257:        if (len >= XML_MAX_NAMELEN) {
                   4258:            fprintf(stderr, 
                   4259:               "xmlScanName: reached XML_MAX_NAMELEN limit\n");
                   4260:            while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
                   4261:                   (NXT(len) == '.') || (NXT(len) == '-') ||
                   4262:                   (NXT(len) == '_') || (NXT(len) == ':') || 
                   4263:                   (IS_COMBINING(NXT(len))) ||
                   4264:                   (IS_EXTENDER(NXT(len))))
                   4265:                 len++;
                   4266:            break;
                   4267:        }
                   4268:     }
                   4269:     return(xmlStrndup(buf, len));
                   4270: }
                   4271: 
                   4272: /**
1.4       daniel   4273:  * xmlXPathEvalPathExpr:
                   4274:  * @ctxt:  the XPath Parser context
                   4275:  *
                   4276:  *  [19]   PathExpr ::=   LocationPath 
                   4277:  *               | FilterExpr 
                   4278:  *               | FilterExpr '/' RelativeLocationPath 
                   4279:  *               | FilterExpr '//' RelativeLocationPath 
                   4280:  *
                   4281:  * Parse and evaluate a path expression, then push the result on the stack
1.8       daniel   4282:  * The / operator and // operators combine an arbitrary expression
                   4283:  * and a relative location path. It is an error if the expression
                   4284:  * does not evaluate to a node-set.
                   4285:  * The / operator does composition in the same way as when / is
                   4286:  * used in a location path. As in location paths, // is short for
                   4287:  * /descendant-or-self::node()/.
1.4       daniel   4288:  */
                   4289: 
                   4290: void
                   4291: xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
1.65      veillard 4292:     int lc = 1;           /* Should we branch to LocationPath ?         */
                   4293:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
                   4294: 
1.30      daniel   4295:     SKIP_BLANKS;
1.4       daniel   4296:     if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
                   4297:         (CUR == '\'') || (CUR == '"')) {
1.65      veillard 4298:        lc = 0;
                   4299:     } else if (CUR == '/') {
1.66      veillard 4300:        /* relative or absolute location path */
                   4301:        lc = 1;
                   4302:     } else if (CUR == '@') {
                   4303:        /* relative abbreviated attribute location path */
1.65      veillard 4304:        lc = 1;
1.68      veillard 4305:     } else if (CUR == '.') {
                   4306:        /* relative abbreviated attribute location path */
                   4307:        lc = 1;
1.65      veillard 4308:     } else {
                   4309:        /*
                   4310:         * Problem is finding if we have a name here whether it's:
                   4311:         *   - a nodetype
                   4312:         *   - a function call in which case it's followed by '('
                   4313:         *   - an axis in which case it's followed by ':'
                   4314:         *   - a element name
                   4315:         * We do an a priori analysis here rather than having to
                   4316:         * maintain parsed token content through the recursive function
                   4317:         * calls. This looks uglier but makes the code quite easier to
                   4318:         * read/write/debug.
                   4319:         */
                   4320:        SKIP_BLANKS;
                   4321:        name = xmlXPathScanName(ctxt);
                   4322:        if (name != NULL) {
                   4323:            int len =xmlStrlen(name);
                   4324:            int blank = 0;
                   4325: 
                   4326:            while (NXT(len) != 0) {
                   4327:                if (NXT(len) == '/') {
                   4328:                    /* element name */
                   4329: #ifdef DEBUG_STEP
                   4330:                    fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
                   4331: #endif
                   4332:                    lc = 1;
                   4333:                    break;
                   4334:                } else if (IS_BLANK(NXT(len))) {
                   4335:                    /* skip to next */
                   4336:                    blank = 1;
                   4337:                } else if (NXT(len) == ':') {
                   4338: #ifdef DEBUG_STEP
                   4339:                    fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
                   4340: #endif
                   4341:                    lc = 1;
                   4342:                    break;
                   4343:                } else if ((NXT(len) == '(')) {
                   4344:                    /* Note Type or Function */
                   4345:                    if (xmlXPathIsNodeType(name)) {
                   4346: #ifdef DEBUG_STEP
                   4347:                        fprintf(xmlXPathDebug, "PathExpr: Type search\n");
                   4348: #endif
                   4349:                        lc = 1;
                   4350:                    } else {
                   4351: #ifdef DEBUG_STEP
                   4352:                        fprintf(xmlXPathDebug, "PathExpr: function call\n");
                   4353: #endif
                   4354:                        lc = 0;
                   4355:                    }
                   4356:                     break;
1.68      veillard 4357:                } else if ((NXT(len) == '[')) {
                   4358:                    /* element name */
                   4359: #ifdef DEBUG_STEP
                   4360:                    fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
                   4361: #endif
                   4362:                    lc = 1;
                   4363:                    break;
1.65      veillard 4364:                } else {
                   4365:                    XP_ERROR(XPATH_EXPR_ERROR);
                   4366:                }
                   4367:                len++;
                   4368:            }
                   4369:            if (NXT(len) == 0) {
                   4370: #ifdef DEBUG_STEP
                   4371:                fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
                   4372: #endif
                   4373:                /* element name */
                   4374:                lc = 1;
                   4375:            }
                   4376:            xmlFree(name);
                   4377:        } else {
1.66      veillard 4378:            /* make sure all cases are covered explicitely */
1.65      veillard 4379:            XP_ERROR(XPATH_EXPR_ERROR);
                   4380:        }
                   4381:     } 
1.66      veillard 4382: 
1.65      veillard 4383:     if (lc) {
                   4384:        xmlXPathEvalLocationPath(ctxt);
                   4385:     } else {
1.4       daniel   4386:        xmlXPathEvalFilterExpr(ctxt);
                   4387:        CHECK_ERROR;
                   4388:        if ((CUR == '/') && (NXT(1) == '/')) {
1.8       daniel   4389:            SKIP(2);
1.30      daniel   4390:            SKIP_BLANKS;
1.59      veillard 4391:            xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
1.8       daniel   4392:                             NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
                   4393:            ctxt->context->node = NULL;
1.4       daniel   4394:            xmlXPathEvalRelativeLocationPath(ctxt);
                   4395:        } else if (CUR == '/') {
                   4396:            xmlXPathEvalRelativeLocationPath(ctxt);
                   4397:        }
1.65      veillard 4398:     }
1.68      veillard 4399:     SKIP_BLANKS;
1.4       daniel   4400: }
                   4401: 
                   4402: /**
                   4403:  * xmlXPathEvalUnionExpr:
                   4404:  * @ctxt:  the XPath Parser context
                   4405:  *
                   4406:  *  [18]   UnionExpr ::=   PathExpr 
                   4407:  *               | UnionExpr '|' PathExpr 
                   4408:  *
                   4409:  * Parse and evaluate an union expression, then push the result on the stack
                   4410:  */
                   4411: 
                   4412: void
                   4413: xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
                   4414:     xmlXPathEvalPathExpr(ctxt);
                   4415:     CHECK_ERROR;
1.30      daniel   4416:     SKIP_BLANKS;
1.4       daniel   4417:     if (CUR == '|') {
1.59      veillard 4418:        xmlXPathObjectPtr obj1,obj2;
                   4419: 
                   4420:        CHECK_TYPE(XPATH_NODESET);
                   4421:        obj1 = valuePop(ctxt);
                   4422:        valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
1.4       daniel   4423: 
1.30      daniel   4424:        NEXT;
                   4425:        SKIP_BLANKS;
1.4       daniel   4426:        xmlXPathEvalPathExpr(ctxt);
                   4427: 
1.59      veillard 4428:        CHECK_TYPE(XPATH_NODESET);
                   4429:        obj2 = valuePop(ctxt);
                   4430:        obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
                   4431:                                                obj2->nodesetval);
                   4432:        xmlXPathFreeObject(obj2);
1.68      veillard 4433:        SKIP_BLANKS;
1.4       daniel   4434:     }
                   4435: }
                   4436: 
                   4437: /**
1.1       daniel   4438:  * xmlXPathEvalUnaryExpr:
                   4439:  * @ctxt:  the XPath Parser context
                   4440:  *
                   4441:  *  [27]   UnaryExpr ::=   UnionExpr 
                   4442:  *                   | '-' UnaryExpr 
                   4443:  *
                   4444:  * Parse and evaluate an unary expression, then push the result on the stack
                   4445:  */
                   4446: 
                   4447: void
                   4448: xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
                   4449:     int minus = 0;
                   4450: 
1.30      daniel   4451:     SKIP_BLANKS;
1.1       daniel   4452:     if (CUR == '-') {
                   4453:         minus = 1;
                   4454:        NEXT;
1.30      daniel   4455:        SKIP_BLANKS;
1.1       daniel   4456:     }
1.19      daniel   4457:     xmlXPathEvalUnionExpr(ctxt);
1.1       daniel   4458:     CHECK_ERROR;
                   4459:     if (minus) {
1.6       daniel   4460:         xmlXPathValueFlipSign(ctxt);
1.1       daniel   4461:     }
                   4462: }
                   4463: 
                   4464: /**
                   4465:  * xmlXPathEvalMultiplicativeExpr:
                   4466:  * @ctxt:  the XPath Parser context
                   4467:  *
                   4468:  *  [26]   MultiplicativeExpr ::=   UnaryExpr 
                   4469:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr 
                   4470:  *                   | MultiplicativeExpr 'div' UnaryExpr 
                   4471:  *                   | MultiplicativeExpr 'mod' UnaryExpr 
                   4472:  *  [34]   MultiplyOperator ::=   '*'
                   4473:  *
                   4474:  * Parse and evaluate an Additive expression, then push the result on the stack
                   4475:  */
                   4476: 
                   4477: void
                   4478: xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
                   4479:     xmlXPathEvalUnaryExpr(ctxt);
                   4480:     CHECK_ERROR;
1.30      daniel   4481:     SKIP_BLANKS;
1.1       daniel   4482:     while ((CUR == '*') || 
                   4483:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
                   4484:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
                   4485:        int op = -1;
                   4486: 
                   4487:         if (CUR == '*') {
                   4488:            op = 0;
                   4489:            NEXT;
                   4490:        } else if (CUR == 'd') {
                   4491:            op = 1;
                   4492:            SKIP(3);
                   4493:        } else if (CUR == 'm') {
                   4494:            op = 2;
                   4495:            SKIP(3);
                   4496:        }
1.30      daniel   4497:        SKIP_BLANKS;
1.1       daniel   4498:         xmlXPathEvalUnaryExpr(ctxt);
                   4499:        CHECK_ERROR;
                   4500:        switch (op) {
                   4501:            case 0:
1.6       daniel   4502:                xmlXPathMultValues(ctxt);
1.1       daniel   4503:                break;
                   4504:            case 1:
1.6       daniel   4505:                xmlXPathDivValues(ctxt);
1.1       daniel   4506:                break;
                   4507:            case 2:
1.6       daniel   4508:                xmlXPathModValues(ctxt);
1.1       daniel   4509:                break;
                   4510:        }
1.68      veillard 4511:        SKIP_BLANKS;
1.1       daniel   4512:     }
                   4513: }
                   4514: 
                   4515: /**
                   4516:  * xmlXPathEvalAdditiveExpr:
                   4517:  * @ctxt:  the XPath Parser context
                   4518:  *
                   4519:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr 
                   4520:  *                   | AdditiveExpr '+' MultiplicativeExpr 
                   4521:  *                   | AdditiveExpr '-' MultiplicativeExpr 
                   4522:  *
                   4523:  * Parse and evaluate an Additive expression, then push the result on the stack
                   4524:  */
                   4525: 
                   4526: void
                   4527: xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
                   4528:     xmlXPathEvalMultiplicativeExpr(ctxt);
                   4529:     CHECK_ERROR;
1.30      daniel   4530:     SKIP_BLANKS;
1.1       daniel   4531:     while ((CUR == '+') || (CUR == '-')) {
                   4532:        int plus;
                   4533: 
                   4534:         if (CUR == '+') plus = 1;
                   4535:        else plus = 0;
                   4536:        NEXT;
1.30      daniel   4537:        SKIP_BLANKS;
1.1       daniel   4538:         xmlXPathEvalMultiplicativeExpr(ctxt);
                   4539:        CHECK_ERROR;
1.6       daniel   4540:        if (plus) xmlXPathAddValues(ctxt);
                   4541:        else xmlXPathSubValues(ctxt);
1.68      veillard 4542:        SKIP_BLANKS;
1.1       daniel   4543:     }
                   4544: }
                   4545: 
                   4546: /**
                   4547:  * xmlXPathEvalRelationalExpr:
                   4548:  * @ctxt:  the XPath Parser context
                   4549:  *
                   4550:  *  [24]   RelationalExpr ::=   AdditiveExpr 
                   4551:  *                 | RelationalExpr '<' AdditiveExpr 
                   4552:  *                 | RelationalExpr '>' AdditiveExpr 
                   4553:  *                 | RelationalExpr '<=' AdditiveExpr 
                   4554:  *                 | RelationalExpr '>=' AdditiveExpr 
                   4555:  *
1.8       daniel   4556:  *  A <= B > C is allowed ? Answer from James, yes with
                   4557:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
                   4558:  *  which is basically what got implemented.
                   4559:  *
                   4560:  * Parse and evaluate a Relational expression, then push the result
                   4561:  * on the stack
1.1       daniel   4562:  */
                   4563: 
                   4564: void
                   4565: xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
                   4566:     xmlXPathEvalAdditiveExpr(ctxt);
                   4567:     CHECK_ERROR;
1.30      daniel   4568:     SKIP_BLANKS;
1.1       daniel   4569:     while ((CUR == '<') ||
                   4570:            (CUR == '>') ||
                   4571:            ((CUR == '<') && (NXT(1) == '=')) ||
                   4572:            ((CUR == '>') && (NXT(1) == '='))) {
1.18      daniel   4573:        int inf, strict, ret;
1.1       daniel   4574: 
                   4575:         if (CUR == '<') inf = 1;
                   4576:        else inf = 0;
                   4577:        if (NXT(1) == '=') strict = 0;
                   4578:        else strict = 1;
                   4579:        NEXT;
                   4580:        if (!strict) NEXT;
1.30      daniel   4581:        SKIP_BLANKS;
1.1       daniel   4582:         xmlXPathEvalAdditiveExpr(ctxt);
                   4583:        CHECK_ERROR;
1.18      daniel   4584:        ret = xmlXPathCompareValues(ctxt, inf, strict);
                   4585:        valuePush(ctxt, xmlXPathNewBoolean(ret));
1.68      veillard 4586:        SKIP_BLANKS;
1.1       daniel   4587:     }
                   4588: }
                   4589: 
                   4590: /**
                   4591:  * xmlXPathEvalEqualityExpr:
                   4592:  * @ctxt:  the XPath Parser context
                   4593:  *
                   4594:  *  [23]   EqualityExpr ::=   RelationalExpr 
                   4595:  *                 | EqualityExpr '=' RelationalExpr 
                   4596:  *                 | EqualityExpr '!=' RelationalExpr 
                   4597:  *
1.8       daniel   4598:  *  A != B != C is allowed ? Answer from James, yes with
                   4599:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
                   4600:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
                   4601:  *  which is basically what got implemented.
1.1       daniel   4602:  *
                   4603:  * Parse and evaluate an Equality expression, then push the result on the stack
                   4604:  *
                   4605:  */
                   4606: void
                   4607: xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
                   4608:     xmlXPathEvalRelationalExpr(ctxt);
                   4609:     CHECK_ERROR;
1.30      daniel   4610:     SKIP_BLANKS;
1.1       daniel   4611:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
1.18      daniel   4612:        xmlXPathObjectPtr res;
1.1       daniel   4613:        int eq, equal;
                   4614: 
                   4615:         if (CUR == '=') eq = 1;
                   4616:        else eq = 0;
                   4617:        NEXT;
                   4618:        if (!eq) NEXT;
1.30      daniel   4619:        SKIP_BLANKS;
1.1       daniel   4620:         xmlXPathEvalRelationalExpr(ctxt);
                   4621:        CHECK_ERROR;
1.18      daniel   4622:        equal = xmlXPathEqualValues(ctxt);
1.1       daniel   4623:        if (eq) res = xmlXPathNewBoolean(equal);
                   4624:        else res = xmlXPathNewBoolean(!equal);
                   4625:        valuePush(ctxt, res);
1.68      veillard 4626:        SKIP_BLANKS;
1.1       daniel   4627:     }
                   4628: }
                   4629: 
                   4630: /**
                   4631:  * xmlXPathEvalAndExpr:
                   4632:  * @ctxt:  the XPath Parser context
                   4633:  *
                   4634:  *  [22]   AndExpr ::=   EqualityExpr 
                   4635:  *                 | AndExpr 'and' EqualityExpr 
                   4636:  *
                   4637:  * Parse and evaluate an AND expression, then push the result on the stack
                   4638:  *
                   4639:  */
                   4640: void
                   4641: xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
                   4642:     xmlXPathEvalEqualityExpr(ctxt);
                   4643:     CHECK_ERROR;
1.30      daniel   4644:     SKIP_BLANKS;
1.48      daniel   4645:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
1.1       daniel   4646:        xmlXPathObjectPtr arg1, arg2;
                   4647: 
                   4648:         SKIP(3);
1.30      daniel   4649:        SKIP_BLANKS;
1.1       daniel   4650:         xmlXPathEvalEqualityExpr(ctxt);
                   4651:        CHECK_ERROR;
                   4652:        arg2 = valuePop(ctxt);
                   4653:        arg1 = valuePop(ctxt);
                   4654:        arg1->boolval &= arg2->boolval;
                   4655:        valuePush(ctxt, arg1);
                   4656:        xmlXPathFreeObject(arg2);
1.68      veillard 4657:        SKIP_BLANKS;
1.1       daniel   4658:     }
                   4659: }
                   4660: 
                   4661: /**
                   4662:  * xmlXPathEvalExpr:
                   4663:  * @ctxt:  the XPath Parser context
                   4664:  *
                   4665:  *  [14]   Expr ::=   OrExpr 
                   4666:  *  [21]   OrExpr ::=   AndExpr 
                   4667:  *                 | OrExpr 'or' AndExpr 
                   4668:  *
                   4669:  * Parse and evaluate an expression, then push the result on the stack
                   4670:  *
                   4671:  */
                   4672: void
                   4673: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
                   4674:     xmlXPathEvalAndExpr(ctxt);
                   4675:     CHECK_ERROR;
1.30      daniel   4676:     SKIP_BLANKS;
1.1       daniel   4677:     while ((CUR == 'o') && (NXT(1) == 'r')) {
                   4678:        xmlXPathObjectPtr arg1, arg2;
                   4679: 
                   4680:         SKIP(2);
1.30      daniel   4681:        SKIP_BLANKS;
1.1       daniel   4682:         xmlXPathEvalAndExpr(ctxt);
                   4683:        CHECK_ERROR;
                   4684:        arg2 = valuePop(ctxt);
                   4685:        arg1 = valuePop(ctxt);
                   4686:        arg1->boolval |= arg2->boolval;
                   4687:        valuePush(ctxt, arg1);
                   4688:        xmlXPathFreeObject(arg2);
1.68      veillard 4689:        SKIP_BLANKS;
1.1       daniel   4690:     }
                   4691: }
                   4692: 
                   4693: /**
1.5       daniel   4694:  * xmlXPathEvaluatePredicateResult:
                   4695:  * @ctxt:  the XPath Parser context
                   4696:  * @res:  the Predicate Expression evaluation result
                   4697:  * @index:  index of the current node in the current list
                   4698:  *
                   4699:  * Evaluate a predicate result for the current node.
                   4700:  * A PredicateExpr is evaluated by evaluating the Expr and converting
                   4701:  * the result to a boolean. If the result is a number, the result will
                   4702:  * be converted to true if the number is equal to the position of the
                   4703:  * context node in the context node list (as returned by the position
                   4704:  * function) and will be converted to false otherwise; if the result
                   4705:  * is not a number, then the result will be converted as if by a call
                   4706:  * to the boolean function. 
                   4707:  */
                   4708: int
                   4709: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
1.57      veillard 4710:                                 xmlXPathObjectPtr res) {
1.5       daniel   4711:     if (res == NULL) return(0);
                   4712:     switch (res->type) {
                   4713:         case XPATH_BOOLEAN:
                   4714:            return(res->boolval);
                   4715:         case XPATH_NUMBER:
1.57      veillard 4716:            return(res->floatval == ctxt->context->proximityPosition);
1.5       daniel   4717:         case XPATH_NODESET:
                   4718:            return(res->nodesetval->nodeNr != 0);
                   4719:         case XPATH_STRING:
                   4720:            return((res->stringval != NULL) &&
                   4721:                   (xmlStrlen(res->stringval) != 0));
                   4722:         default:
1.6       daniel   4723:            STRANGE
1.5       daniel   4724:     }
                   4725:     return(0);
                   4726: }
                   4727: 
                   4728: /**
1.1       daniel   4729:  * xmlXPathEvalPredicate:
                   4730:  * @ctxt:  the XPath Parser context
                   4731:  *
                   4732:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
                   4733:  *  [9]   PredicateExpr ::=   Expr 
                   4734:  *
1.57      veillard 4735:  * ---------------------
                   4736:  * For each node in the node-set to be filtered, the PredicateExpr is
                   4737:  * evaluated with that node as the context node, with the number of nodes
                   4738:  * in the node-set as the context size, and with the proximity position
                   4739:  * of the node in the node-set with respect to the axis as the context
                   4740:  * position; if PredicateExpr evaluates to true for that node, the node
                   4741:  * is included in the new node-set; otherwise, it is not included.
                   4742:  * ---------------------
                   4743:  *
1.4       daniel   4744:  * Parse and evaluate a predicate for all the elements of the
                   4745:  * current node list. Then refine the list by removing all
                   4746:  * nodes where the predicate is false.
1.1       daniel   4747:  */
                   4748: void
                   4749: xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
1.29      daniel   4750:     const xmlChar *cur;
1.57      veillard 4751:     xmlXPathObjectPtr res;
1.59      veillard 4752:     xmlXPathObjectPtr obj, tmp;
1.5       daniel   4753:     xmlNodeSetPtr newset = NULL;
1.57      veillard 4754:     xmlNodeSetPtr oldset;
1.4       daniel   4755:     int i;
                   4756: 
1.30      daniel   4757:     SKIP_BLANKS;
1.1       daniel   4758:     if (CUR != '[') {
1.49      daniel   4759:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
1.1       daniel   4760:     }
                   4761:     NEXT;
1.30      daniel   4762:     SKIP_BLANKS;
1.57      veillard 4763: 
                   4764:     /*
                   4765:      * Extract the old set, and then evaluate the result of the
                   4766:      * expression for all the element in the set. use it to grow
                   4767:      * up a new set.
                   4768:      */
1.59      veillard 4769:     CHECK_TYPE(XPATH_NODESET);
                   4770:     obj = valuePop(ctxt);
                   4771:     oldset = obj->nodesetval;
1.57      veillard 4772:     ctxt->context->node = NULL;
                   4773: 
                   4774:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
1.4       daniel   4775:        xmlXPathEvalExpr(ctxt);
                   4776:        CHECK_ERROR;
1.57      veillard 4777:        ctxt->context->contextSize = 0;
                   4778:        ctxt->context->proximityPosition = 0;
1.4       daniel   4779:        res = valuePop(ctxt);
1.5       daniel   4780:        if (res != NULL)
                   4781:            xmlXPathFreeObject(res);
1.59      veillard 4782:        valuePush(ctxt, obj);
1.4       daniel   4783:     } else {
1.57      veillard 4784:        /*
                   4785:         * Save the expression pointer since we will have to evaluate
                   4786:         * it multiple times. Initialize the new set.
                   4787:         */
1.4       daniel   4788:         cur = ctxt->cur;
1.5       daniel   4789:        newset = xmlXPathNodeSetCreate(NULL);
1.47      daniel   4790:        
1.57      veillard 4791:         for (i = 0; i < oldset->nodeNr; i++) {
1.4       daniel   4792:            ctxt->cur = cur;
1.47      daniel   4793: 
1.57      veillard 4794:            /*
                   4795:             * Run the evaluation with a node list made of a single item
                   4796:             * in the nodeset.
                   4797:             */
                   4798:            ctxt->context->node = oldset->nodeTab[i];
1.59      veillard 4799:            tmp = xmlXPathNewNodeSet(ctxt->context->node);
                   4800:            valuePush(ctxt, tmp);
1.57      veillard 4801:            ctxt->context->contextSize = oldset->nodeNr;
                   4802:            ctxt->context->proximityPosition = i + 1;
1.47      daniel   4803: 
1.4       daniel   4804:            xmlXPathEvalExpr(ctxt);
                   4805:            CHECK_ERROR;
1.57      veillard 4806: 
                   4807:            /*
                   4808:             * The result of the evaluation need to be tested to
                   4809:             * decided whether the filter succeeded or not
                   4810:             */
1.4       daniel   4811:            res = valuePop(ctxt);
1.57      veillard 4812:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   4813:                xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
                   4814:            }
1.59      veillard 4815: 
                   4816:            /*
                   4817:             * Cleanup
                   4818:             */
1.5       daniel   4819:            if (res != NULL)
1.57      veillard 4820:                xmlXPathFreeObject(res);
1.59      veillard 4821:            if (ctxt->value == tmp) {
                   4822:                res = valuePop(ctxt);
                   4823:                xmlXPathFreeObject(res);
                   4824:            }
1.47      daniel   4825:            
1.57      veillard 4826:            ctxt->context->node = NULL;
1.4       daniel   4827:        }
1.57      veillard 4828: 
                   4829:        /*
                   4830:         * The result is used as the new evaluation set.
                   4831:         */
1.59      veillard 4832:        xmlXPathFreeObject(obj);
1.5       daniel   4833:        ctxt->context->node = NULL;
1.57      veillard 4834:        ctxt->context->contextSize = -1;
                   4835:        ctxt->context->proximityPosition = -1;
1.59      veillard 4836:        valuePush(ctxt, xmlXPathWrapNodeSet(newset));
1.4       daniel   4837:     }
1.1       daniel   4838:     if (CUR != ']') {
1.49      daniel   4839:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
1.1       daniel   4840:     }
1.57      veillard 4841: 
1.1       daniel   4842:     NEXT;
1.30      daniel   4843:     SKIP_BLANKS;
1.4       daniel   4844: #ifdef DEBUG_STEP
1.9       daniel   4845:     fprintf(xmlXPathDebug, "After predicate : ");
1.66      veillard 4846:     xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->value->nodesetval);
1.4       daniel   4847: #endif
1.1       daniel   4848: }
                   4849: 
                   4850: /**
1.65      veillard 4851:  * xmlXPathEvalNodeTest:
1.2       daniel   4852:  * @ctxt:  the XPath Parser context
1.65      veillard 4853:  * @test:  pointer to a xmlXPathTestVal
                   4854:  * @type:  pointer to a xmlXPathTypeVal
                   4855:  * @prefix:  placeholder for a possible name prefix
                   4856:  *
                   4857:  * [7] NodeTest ::=   NameTest
                   4858:  *                 | NodeType '(' ')'
                   4859:  *                 | 'processing-instruction' '(' Literal ')'
                   4860:  *
                   4861:  * [37] NameTest ::=  '*'
                   4862:  *                 | NCName ':' '*'
                   4863:  *                 | QName
                   4864:  * [38] NodeType ::= 'comment'
                   4865:  *                | 'text'
                   4866:  *                | 'processing-instruction'
                   4867:  *                | 'node'
1.2       daniel   4868:  *
1.65      veillard 4869:  * Returns the name found and update @test, @type and @prefix appropriately
1.2       daniel   4870:  */
1.65      veillard 4871: xmlChar *
                   4872: xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
                   4873:                     xmlXPathTypeVal *type, xmlChar **prefix, xmlChar *name) {
                   4874:     int blanks;
                   4875: 
                   4876:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
                   4877:        STRANGE;
                   4878:        return(NULL);
                   4879:     }
                   4880:     *type = 0;
                   4881:     *test = 0;
                   4882:     *prefix = NULL;
                   4883:     SKIP_BLANKS;
                   4884: 
                   4885:     if ((name == NULL) && (CUR == '*')) {
                   4886:        /*
                   4887:         * All elements
                   4888:         */
                   4889:        NEXT;
                   4890:        *test = NODE_TEST_ALL;
                   4891:        return(NULL);
                   4892:     }
1.2       daniel   4893: 
1.65      veillard 4894:     if (name == NULL)
                   4895:        name = xmlXPathParseNCName(ctxt);
                   4896:     if (name == NULL) {
                   4897:        XP_ERROR0(XPATH_EXPR_ERROR);
                   4898:     }
1.19      daniel   4899: 
1.65      veillard 4900:     blanks = IS_BLANK(CUR);
                   4901:     SKIP_BLANKS;
                   4902:     if (CUR == '(') {
                   4903:        NEXT;
                   4904:        /*
                   4905:         * NodeType or PI search
                   4906:         */
                   4907:        if (xmlStrEqual(name, BAD_CAST "comment"))
                   4908:            *type = NODE_TYPE_COMMENT;
                   4909:        else if (xmlStrEqual(name, BAD_CAST "node"))
                   4910:            *type = NODE_TYPE_NODE;
                   4911:        else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
                   4912:            *type = NODE_TYPE_PI;
                   4913:        else if (xmlStrEqual(name, BAD_CAST "text"))
                   4914:            *type = NODE_TYPE_TEXT;
                   4915:        else
                   4916:            XP_ERROR0(XPATH_EXPR_ERROR);
1.19      daniel   4917: 
1.65      veillard 4918:        *test = NODE_TEST_TYPE;
1.2       daniel   4919:        
1.65      veillard 4920:        SKIP_BLANKS;
                   4921:        if (*type == NODE_TYPE_PI) {
1.2       daniel   4922:            /*
1.65      veillard 4923:             * Specific case: search a PI by name.
1.2       daniel   4924:             */
1.65      veillard 4925:            xmlXPathObjectPtr cur;
                   4926: 
                   4927:            if (name != NULL)
                   4928:                xmlFree(name);
                   4929: 
                   4930:            xmlXPathEvalLiteral(ctxt);
                   4931:            CHECK_ERROR 0;
                   4932:            xmlXPathStringFunction(ctxt, 1);
                   4933:            CHECK_ERROR0;
                   4934:            cur = valuePop(ctxt);
                   4935:            name = xmlStrdup(cur->stringval);
                   4936:            xmlXPathFreeObject(cur);
                   4937:            SKIP_BLANKS;
                   4938:        }
                   4939:        if (CUR != ')')
                   4940:            XP_ERROR0(XPATH_UNCLOSED_ERROR);
                   4941:        NEXT;
                   4942:        return(name);
                   4943:     }
                   4944:     *test = NODE_TEST_NAME;
                   4945:     if ((!blanks) && (CUR == ':')) {
                   4946:        NEXT;
                   4947: 
                   4948:        *prefix = name;
                   4949: 
                   4950:        if (CUR == '*') {
1.3       daniel   4951:            /*
1.65      veillard 4952:             * All elements
1.3       daniel   4953:             */
1.65      veillard 4954:            NEXT;
                   4955:            *test = NODE_TEST_ALL;
                   4956:            return(NULL);
                   4957:        }
                   4958: 
                   4959:        name = xmlXPathParseNCName(ctxt);
                   4960:        if (name == NULL) {
                   4961:            XP_ERROR0(XPATH_EXPR_ERROR);
1.3       daniel   4962:        }
1.4       daniel   4963:     }
1.65      veillard 4964:     return(name);
                   4965: }
                   4966: 
                   4967: /**
                   4968:  * xmlXPathIsAxisName:
                   4969:  * @name:  a preparsed name token
                   4970:  *
                   4971:  * [6] AxisName ::=   'ancestor'
                   4972:  *                  | 'ancestor-or-self'
                   4973:  *                  | 'attribute'
                   4974:  *                  | 'child'
                   4975:  *                  | 'descendant'
                   4976:  *                  | 'descendant-or-self'
                   4977:  *                  | 'following'
                   4978:  *                  | 'following-sibling'
                   4979:  *                  | 'namespace'
                   4980:  *                  | 'parent'
                   4981:  *                  | 'preceding'
                   4982:  *                  | 'preceding-sibling'
                   4983:  *                  | 'self'
                   4984:  *
                   4985:  * Returns the axis or 0
                   4986:  */
                   4987: xmlXPathAxisVal
                   4988: xmlXPathIsAxisName(const xmlChar *name) {
                   4989:     xmlXPathAxisVal ret = 0;
                   4990:     switch (name[0]) {
                   4991:        case 'a':
                   4992:            if (xmlStrEqual(name, BAD_CAST "ancestor"))
                   4993:                ret = AXIS_ANCESTOR;
                   4994:            if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
                   4995:                ret = AXIS_ANCESTOR_OR_SELF;
                   4996:            if (xmlStrEqual(name, BAD_CAST "attribute"))
                   4997:                ret = AXIS_ATTRIBUTE;
                   4998:            break;
                   4999:        case 'c':
                   5000:            if (xmlStrEqual(name, BAD_CAST "child"))
                   5001:                ret = AXIS_CHILD;
                   5002:            break;
                   5003:        case 'd':
                   5004:            if (xmlStrEqual(name, BAD_CAST "descendant"))
                   5005:                ret = AXIS_DESCENDANT;
                   5006:            if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
                   5007:                ret = AXIS_DESCENDANT_OR_SELF;
                   5008:            break;
                   5009:        case 'f':
                   5010:            if (xmlStrEqual(name, BAD_CAST "following"))
                   5011:                ret = AXIS_FOLLOWING;
                   5012:            if (xmlStrEqual(name, BAD_CAST "following-sibling"))
                   5013:                ret = AXIS_FOLLOWING_SIBLING;
                   5014:            break;
                   5015:        case 'n':
                   5016:            if (xmlStrEqual(name, BAD_CAST "namespace"))
                   5017:                ret = AXIS_NAMESPACE;
                   5018:            break;
                   5019:        case 'p':
                   5020:            if (xmlStrEqual(name, BAD_CAST "parent"))
                   5021:                ret = AXIS_PARENT;
                   5022:            if (xmlStrEqual(name, BAD_CAST "preceding"))
                   5023:                ret = AXIS_PRECEDING;
                   5024:            if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
                   5025:                ret = AXIS_PRECEDING_SIBLING;
                   5026:            break;
                   5027:        case 's':
                   5028:            if (xmlStrEqual(name, BAD_CAST "self"))
                   5029:                ret = AXIS_SELF;
                   5030:            break;
                   5031:     }
                   5032:     return(ret);
                   5033: }
                   5034: 
                   5035: /**
                   5036:  * xmlXPathEvalAxisSpecifier:
                   5037:  * @ctxt:  the XPath Parser context
                   5038:  *
                   5039:  *
                   5040:  * Returns the axis found
                   5041:  */
                   5042: xmlXPathAxisVal
                   5043: xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
                   5044:     xmlXPathAxisVal ret = AXIS_CHILD;
                   5045:     int blank = 0;
                   5046:     xmlChar *name;
                   5047: 
                   5048:     if (CUR == '@') {
                   5049:        NEXT;
                   5050:        return(AXIS_ATTRIBUTE);
                   5051:     } else {
                   5052:        name = xmlXPathParseNCName(ctxt);
                   5053:        if (name == NULL) {
                   5054:            XP_ERROR0(XPATH_EXPR_ERROR);
                   5055:        }
                   5056:        if (IS_BLANK(CUR))
                   5057:            blank = 1;
                   5058:        SKIP_BLANKS;
                   5059:        if ((CUR == ':') && (NXT(1) == ':')) {
                   5060:            ret = xmlXPathIsAxisName(name);
                   5061:        } else if ((blank) && (CUR == ':'))
                   5062:            XP_ERROR0(XPATH_EXPR_ERROR);
1.2       daniel   5063: 
1.65      veillard 5064:        xmlFree(name);
                   5065:     }
                   5066:     return(ret);
1.2       daniel   5067: }
                   5068: 
                   5069: /**
                   5070:  * xmlXPathEvalStep:
                   5071:  * @ctxt:  the XPath Parser context
                   5072:  *
1.65      veillard 5073:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
                   5074:  *                  | AbbreviatedStep 
1.61      veillard 5075:  *
1.65      veillard 5076:  * [12] AbbreviatedStep ::=   '.' | '..'
                   5077:  *
                   5078:  * [5] AxisSpecifier ::= AxisName '::'
                   5079:  *                  | AbbreviatedAxisSpecifier
                   5080:  *
                   5081:  * [13] AbbreviatedAxisSpecifier ::= '@'?
1.61      veillard 5082:  *
1.62      veillard 5083:  * Modified for XPtr range support as:
1.61      veillard 5084:  *
                   5085:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
                   5086:  *                     | AbbreviatedStep
1.63      veillard 5087:  *                     | 'range-to' '(' Expr ')' Predicate*
1.2       daniel   5088:  *
                   5089:  * Evaluate one step in a Location Path
1.7       daniel   5090:  * A location step of . is short for self::node(). This is
                   5091:  * particularly useful in conjunction with //. For example, the
                   5092:  * location path .//para is short for
                   5093:  * self::node()/descendant-or-self::node()/child::para
                   5094:  * and so will select all para descendant elements of the context
                   5095:  * node.
                   5096:  * Similarly, a location step of .. is short for parent::node().
                   5097:  * For example, ../title is short for parent::node()/child::title
                   5098:  * and so will select the title children of the parent of the context
                   5099:  * node.
1.2       daniel   5100:  */
                   5101: void
                   5102: xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
1.30      daniel   5103:     SKIP_BLANKS;
1.2       daniel   5104:     if ((CUR == '.') && (NXT(1) == '.')) {
1.7       daniel   5105:        SKIP(2);
1.30      daniel   5106:        SKIP_BLANKS;
1.59      veillard 5107:        xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
1.7       daniel   5108:                         NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
1.2       daniel   5109:     } else if (CUR == '.') {
1.6       daniel   5110:        NEXT;
1.30      daniel   5111:        SKIP_BLANKS;
1.2       daniel   5112:     } else {
1.65      veillard 5113:        xmlChar *name = NULL;
                   5114:        xmlChar *prefix = NULL;
                   5115:        xmlXPathTestVal test;
                   5116:        xmlXPathAxisVal axis;
                   5117:        xmlXPathTypeVal type;
                   5118: 
1.67      veillard 5119:        /*
                   5120:         * The modification needed for XPointer change to the production
                   5121:         */
1.61      veillard 5122: #ifdef LIBXML_XPTR_ENABLED
1.65      veillard 5123:        if (ctxt->context->xptr) {
                   5124:            name = xmlXPathParseNCName(ctxt);
                   5125:            if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
                   5126:                xmlFree(name);
                   5127:                SKIP_BLANKS;
                   5128:                if (CUR != '(') {
                   5129:                    XP_ERROR(XPATH_EXPR_ERROR);
                   5130:                }
                   5131:                NEXT;
                   5132:                SKIP_BLANKS;
1.61      veillard 5133: 
1.65      veillard 5134:                xmlXPtrRangeToFunction(ctxt, 1);
1.61      veillard 5135:                CHECK_ERROR;
                   5136: 
1.65      veillard 5137:                SKIP_BLANKS;
                   5138:                if (CUR != ')') {
                   5139:                    XP_ERROR(XPATH_EXPR_ERROR);
1.61      veillard 5140:                }
1.65      veillard 5141:                NEXT;
                   5142:                goto eval_predicates;
                   5143:            }
                   5144:        }
                   5145: #endif
                   5146:        if (name == NULL)
                   5147:            name = xmlXPathParseNCName(ctxt);
                   5148:        if (name != NULL) {
                   5149:            axis = xmlXPathIsAxisName(name);
                   5150:            if (axis != 0) {
                   5151:                SKIP_BLANKS;
                   5152:                if ((CUR == ':') && (NXT(1) == ':')) {
                   5153:                    SKIP(2);
                   5154:                    xmlFree(name);
                   5155:                    name = NULL;
                   5156:                } else {
                   5157:                    /* an element name can conflict with an axis one :-\ */
                   5158:                    axis = AXIS_CHILD;
1.61      veillard 5159:                }
1.65      veillard 5160:            } else {
                   5161:                axis = AXIS_CHILD;
1.61      veillard 5162:            }
1.65      veillard 5163:        } else if (CUR == '@') {
                   5164:            NEXT;
                   5165:            axis = AXIS_ATTRIBUTE;
                   5166:        } else {
                   5167:            axis = AXIS_CHILD;
                   5168:        }
                   5169: 
                   5170:        CHECK_ERROR;
1.61      veillard 5171: 
1.65      veillard 5172:        name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
                   5173:        if (test == 0)
                   5174:            return;
1.61      veillard 5175: 
1.65      veillard 5176: #ifdef DEBUG_STEP
                   5177:        fprintf(xmlXPathDebug, "Basis : computing new set\n");
                   5178: #endif
                   5179:        xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
                   5180: #ifdef DEBUG_STEP
                   5181:        fprintf(xmlXPathDebug, "Basis : ");
1.66      veillard 5182:        xmlXPathDebugNodeSet(stdout, ctxt->value->nodesetval);
1.61      veillard 5183: #endif
1.65      veillard 5184:        if (name != NULL)
                   5185:            xmlFree(name);
                   5186:        if (prefix != NULL)
                   5187:            xmlFree(prefix);
                   5188: 
                   5189: eval_predicates:
1.30      daniel   5190:        SKIP_BLANKS;
1.2       daniel   5191:        while (CUR == '[') {
                   5192:            xmlXPathEvalPredicate(ctxt);
                   5193:        }
                   5194:     }
1.4       daniel   5195: #ifdef DEBUG_STEP
1.9       daniel   5196:     fprintf(xmlXPathDebug, "Step : ");
1.66      veillard 5197:     xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->value->nodesetval);
1.4       daniel   5198: #endif
1.2       daniel   5199: }
                   5200: 
                   5201: /**
1.1       daniel   5202:  * xmlXPathEvalRelativeLocationPath:
                   5203:  * @ctxt:  the XPath Parser context
                   5204:  *
                   5205:  *  [3]   RelativeLocationPath ::=   Step 
                   5206:  *                     | RelativeLocationPath '/' Step 
                   5207:  *                     | AbbreviatedRelativeLocationPath 
                   5208:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step 
                   5209:  *
                   5210:  */
                   5211: void
1.2       daniel   5212: xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
1.30      daniel   5213:     SKIP_BLANKS;
1.73      veillard 5214:     if ((CUR == '/') && (NXT(1) == '/')) {
                   5215:        SKIP(2);
                   5216:        SKIP_BLANKS;
                   5217:        xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
                   5218:                         NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
                   5219:     } else if (CUR == '/') {
                   5220:            NEXT;
                   5221:        SKIP_BLANKS;
                   5222:     }
1.2       daniel   5223:     xmlXPathEvalStep(ctxt);
1.30      daniel   5224:     SKIP_BLANKS;
1.7       daniel   5225:     while (CUR == '/') {
                   5226:        if ((CUR == '/') && (NXT(1) == '/')) {
                   5227:            SKIP(2);
1.30      daniel   5228:            SKIP_BLANKS;
1.59      veillard 5229:            xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
1.7       daniel   5230:                             NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
                   5231:            xmlXPathEvalStep(ctxt);
                   5232:        } else if (CUR == '/') {
                   5233:            NEXT;
1.30      daniel   5234:            SKIP_BLANKS;
1.7       daniel   5235:            xmlXPathEvalStep(ctxt);
                   5236:        }
1.30      daniel   5237:        SKIP_BLANKS;
1.1       daniel   5238:     }
                   5239: }
                   5240: 
                   5241: /**
                   5242:  * xmlXPathEvalLocationPath:
                   5243:  * @ctxt:  the XPath Parser context
                   5244:  *
                   5245:  *  [1]   LocationPath ::=   RelativeLocationPath 
                   5246:  *                     | AbsoluteLocationPath 
                   5247:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
                   5248:  *                     | AbbreviatedAbsoluteLocationPath 
                   5249:  *  [10]   AbbreviatedAbsoluteLocationPath ::=   
                   5250:  *                           '//' RelativeLocationPath 
1.7       daniel   5251:  *
                   5252:  * // is short for /descendant-or-self::node()/. For example,
                   5253:  * //para is short for /descendant-or-self::node()/child::para and
                   5254:  * so will select any para element in the document (even a para element
                   5255:  * that is a document element will be selected by //para since the
                   5256:  * document element node is a child of the root node); div//para is
                   5257:  * short for div/descendant-or-self::node()/child::para and so will
                   5258:  * select all para descendants of div children.
1.1       daniel   5259:  */
                   5260: void
                   5261: xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
1.30      daniel   5262:     SKIP_BLANKS;
                   5263:     if (CUR != '/') {
                   5264:         xmlXPathEvalRelativeLocationPath(ctxt);
                   5265:     } else {
                   5266:        while (CUR == '/') {
                   5267:            if ((CUR == '/') && (NXT(1) == '/')) {
                   5268:                SKIP(2);
                   5269:                SKIP_BLANKS;
1.59      veillard 5270:                xmlXPathNodeCollectAndTest(ctxt,
1.30      daniel   5271:                                 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
                   5272:                                 XML_ELEMENT_NODE, NULL, NULL);
                   5273:                xmlXPathEvalRelativeLocationPath(ctxt);
                   5274:            } else if (CUR == '/') {
                   5275:                NEXT;
                   5276:                SKIP_BLANKS;
1.7       daniel   5277:                xmlXPathRoot(ctxt);
1.30      daniel   5278:                if (CUR != 0)
                   5279:                    xmlXPathEvalRelativeLocationPath(ctxt);
                   5280:            }
1.7       daniel   5281:        }
1.1       daniel   5282:     }
                   5283: }
                   5284: 
                   5285: /**
                   5286:  * xmlXPathEval:
                   5287:  * @str:  the XPath expression
1.59      veillard 5288:  * @ctx:  the XPath context
1.1       daniel   5289:  *
1.9       daniel   5290:  * Evaluate the XPath Location Path in the given context.
1.1       daniel   5291:  *
                   5292:  * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
                   5293:  *         the caller has to free the object.
                   5294:  */
                   5295: xmlXPathObjectPtr
1.59      veillard 5296: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
                   5297:     xmlXPathParserContextPtr ctxt;
1.19      daniel   5298:     xmlXPathObjectPtr res = NULL, tmp;
1.68      veillard 5299:     xmlXPathObjectPtr init = NULL;
1.35      daniel   5300:     int stack = 0;
1.2       daniel   5301: 
1.10      daniel   5302:     xmlXPathInit();
                   5303: 
1.59      veillard 5304:     CHECK_CONTEXT(ctx)
1.1       daniel   5305: 
1.9       daniel   5306:     if (xmlXPathDebug == NULL)
                   5307:         xmlXPathDebug = stderr;
1.59      veillard 5308:     ctxt = xmlXPathNewParserContext(str, ctx);
1.68      veillard 5309:     if (ctx->node != NULL) {
                   5310:        init = xmlXPathNewNodeSet(ctx->node);
                   5311:        valuePush(ctxt, init);
                   5312:     }
1.35      daniel   5313:     if (str[0] == '/')
1.68      veillard 5314:        xmlXPathRoot(ctxt);
1.65      veillard 5315:     xmlXPathEvalExpr(ctxt);
1.59      veillard 5316: 
                   5317:     if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
1.63      veillard 5318:        fprintf(xmlXPathDebug,
                   5319:                "xmlXPathEval: evaluation failed to return a node set\n");
                   5320:     } else {
                   5321:        res = valuePop(ctxt);
                   5322:     }
                   5323: 
                   5324:     do {
                   5325:         tmp = valuePop(ctxt);
                   5326:        if (tmp != NULL) {
                   5327:            xmlXPathFreeObject(tmp);
1.68      veillard 5328:            if (tmp != init)
                   5329:                stack++;    
1.63      veillard 5330:         }
                   5331:     } while (tmp != NULL);
                   5332:     if (stack != 0) {
                   5333:        fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
1.35      daniel   5334:                stack);
                   5335:     }
1.59      veillard 5336:     if (ctxt->error != XPATH_EXPRESSION_OK) {
                   5337:        xmlXPathFreeObject(res);
                   5338:        res = NULL;
                   5339:     }
1.48      daniel   5340:         
1.59      veillard 5341:     xmlXPathFreeParserContext(ctxt);
1.9       daniel   5342:     return(res);
                   5343: }
                   5344: 
                   5345: /**
                   5346:  * xmlXPathEvalExpression:
                   5347:  * @str:  the XPath expression
                   5348:  * @ctxt:  the XPath context
                   5349:  *
                   5350:  * Evaluate the XPath expression in the given context.
                   5351:  *
1.19      daniel   5352:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
1.9       daniel   5353:  *         the caller has to free the object.
                   5354:  */
                   5355: xmlXPathObjectPtr
1.29      daniel   5356: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
1.9       daniel   5357:     xmlXPathParserContextPtr pctxt;
                   5358:     xmlXPathObjectPtr res, tmp;
1.35      daniel   5359:     int stack = 0;
1.10      daniel   5360: 
                   5361:     xmlXPathInit();
1.9       daniel   5362: 
1.59      veillard 5363:     CHECK_CONTEXT(ctxt)
1.9       daniel   5364: 
                   5365:     if (xmlXPathDebug == NULL)
                   5366:         xmlXPathDebug = stderr;
                   5367:     pctxt = xmlXPathNewParserContext(str, ctxt);
                   5368:     xmlXPathEvalExpr(pctxt);
                   5369: 
                   5370:     res = valuePop(pctxt);
                   5371:     do {
                   5372:         tmp = valuePop(pctxt);
1.35      daniel   5373:        if (tmp != NULL) {
1.11      veillard 5374:            xmlXPathFreeObject(tmp);
1.35      daniel   5375:            stack++;
                   5376:        }
1.9       daniel   5377:     } while (tmp != NULL);
1.35      daniel   5378:     if (stack != 0) {
1.64      veillard 5379:        fprintf(xmlXPathDebug, "xmlXPathEvalExpression: %d object left on the stack\n",
1.35      daniel   5380:                stack);
                   5381:     }
1.1       daniel   5382:     xmlXPathFreeParserContext(pctxt);
                   5383:     return(res);
                   5384: }
                   5385: 
1.45      daniel   5386: #endif /* LIBXML_XPATH_ENABLED */

Webmaster