Annotation of embedaddon/libxml2/xpointer.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * xpointer.c : Code to handle XML Pointer
                      3:  *
                      4:  * Base implementation was made accordingly to
                      5:  * W3C Candidate Recommendation 7 June 2000
                      6:  * http://www.w3.org/TR/2000/CR-xptr-20000607
                      7:  *
                      8:  * Added support for the element() scheme described in:
                      9:  * W3C Proposed Recommendation 13 November 2002
                     10:  * http://www.w3.org/TR/2002/PR-xptr-element-20021113/  
                     11:  *
                     12:  * See Copyright for the status of this software.
                     13:  *
                     14:  * daniel@veillard.com
                     15:  */
                     16: 
                     17: #define IN_LIBXML
                     18: #include "libxml.h"
                     19: 
                     20: /*
                     21:  * TODO: better handling of error cases, the full expression should
                     22:  *       be parsed beforehand instead of a progressive evaluation
                     23:  * TODO: Access into entities references are not supported now ...
                     24:  *       need a start to be able to pop out of entities refs since
                     25:  *       parent is the endity declaration, not the ref.
                     26:  */
                     27: 
                     28: #include <string.h>
                     29: #include <libxml/xpointer.h>
                     30: #include <libxml/xmlmemory.h>
                     31: #include <libxml/parserInternals.h>
                     32: #include <libxml/uri.h>
                     33: #include <libxml/xpath.h>
                     34: #include <libxml/xpathInternals.h>
                     35: #include <libxml/xmlerror.h>
                     36: #include <libxml/globals.h>
                     37: 
                     38: #ifdef LIBXML_XPTR_ENABLED
                     39: 
                     40: /* Add support of the xmlns() xpointer scheme to initialize the namespaces */
                     41: #define XPTR_XMLNS_SCHEME
                     42: 
                     43: /* #define DEBUG_RANGES */
                     44: #ifdef DEBUG_RANGES
                     45: #ifdef LIBXML_DEBUG_ENABLED
                     46: #include <libxml/debugXML.h>
                     47: #endif
                     48: #endif
                     49: 
                     50: #define TODO                                                           \
                     51:     xmlGenericError(xmlGenericErrorContext,                            \
                     52:            "Unimplemented block at %s:%d\n",                           \
                     53:             __FILE__, __LINE__);
                     54: 
                     55: #define STRANGE                                                        \
                     56:     xmlGenericError(xmlGenericErrorContext,                            \
                     57:            "Internal error at %s:%d\n",                                \
                     58:             __FILE__, __LINE__);
                     59: 
                     60: /************************************************************************
                     61:  *                                                                     *
                     62:  *             Some factorized error routines                          *
                     63:  *                                                                     *
                     64:  ************************************************************************/
                     65: 
                     66: /**
                     67:  * xmlXPtrErrMemory:
                     68:  * @extra:  extra informations
                     69:  *
                     70:  * Handle a redefinition of attribute error
                     71:  */
                     72: static void
                     73: xmlXPtrErrMemory(const char *extra)
                     74: {
                     75:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER,
                     76:                    XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
                     77:                    NULL, NULL, 0, 0,
                     78:                    "Memory allocation failed : %s\n", extra);
                     79: }
                     80: 
                     81: /**
                     82:  * xmlXPtrErr:
                     83:  * @ctxt:  an XPTR evaluation context
                     84:  * @extra:  extra informations
                     85:  *
                     86:  * Handle a redefinition of attribute error
                     87:  */
                     88: static void
                     89: xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error,
                     90:            const char * msg, const xmlChar *extra)
                     91: {
                     92:     if (ctxt != NULL)
                     93:         ctxt->error = error;
                     94:     if ((ctxt == NULL) || (ctxt->context == NULL)) {
                     95:        __xmlRaiseError(NULL, NULL, NULL,
                     96:                        NULL, NULL, XML_FROM_XPOINTER, error,
                     97:                        XML_ERR_ERROR, NULL, 0,
                     98:                        (const char *) extra, NULL, NULL, 0, 0,
                     99:                        msg, extra);
                    100:        return;
                    101:     }
                    102:     ctxt->context->lastError.domain = XML_FROM_XPOINTER;
                    103:     ctxt->context->lastError.code = error;
                    104:     ctxt->context->lastError.level = XML_ERR_ERROR;
                    105:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
                    106:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
                    107:     ctxt->context->lastError.node = ctxt->context->debugNode;
                    108:     if (ctxt->context->error != NULL) {
                    109:        ctxt->context->error(ctxt->context->userData,
                    110:                             &ctxt->context->lastError);
                    111:     } else {
                    112:        __xmlRaiseError(NULL, NULL, NULL,
                    113:                        NULL, ctxt->context->debugNode, XML_FROM_XPOINTER,
                    114:                        error, XML_ERR_ERROR, NULL, 0,
                    115:                        (const char *) extra, (const char *) ctxt->base, NULL,
                    116:                        ctxt->cur - ctxt->base, 0,
                    117:                        msg, extra);
                    118:     }
                    119: }
                    120: 
                    121: /************************************************************************
                    122:  *                                                                     *
                    123:  *             A few helper functions for child sequences              *
                    124:  *                                                                     *
                    125:  ************************************************************************/
                    126: /* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
                    127: xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level);
                    128: /**
                    129:  * xmlXPtrGetArity:
                    130:  * @cur:  the node
                    131:  *
                    132:  * Returns the number of child for an element, -1 in case of error
                    133:  */
                    134: static int
                    135: xmlXPtrGetArity(xmlNodePtr cur) {
                    136:     int i;
                    137:     if (cur == NULL) 
                    138:        return(-1);
                    139:     cur = cur->children;
                    140:     for (i = 0;cur != NULL;cur = cur->next) {
                    141:        if ((cur->type == XML_ELEMENT_NODE) ||
                    142:            (cur->type == XML_DOCUMENT_NODE) ||
                    143:            (cur->type == XML_HTML_DOCUMENT_NODE)) {
                    144:            i++;
                    145:        }
                    146:     }
                    147:     return(i);
                    148: }
                    149: 
                    150: /**
                    151:  * xmlXPtrGetIndex:
                    152:  * @cur:  the node
                    153:  *
                    154:  * Returns the index of the node in its parent children list, -1
                    155:  *         in case of error
                    156:  */
                    157: static int
                    158: xmlXPtrGetIndex(xmlNodePtr cur) {
                    159:     int i;
                    160:     if (cur == NULL) 
                    161:        return(-1);
                    162:     for (i = 1;cur != NULL;cur = cur->prev) {
                    163:        if ((cur->type == XML_ELEMENT_NODE) ||
                    164:            (cur->type == XML_DOCUMENT_NODE) ||
                    165:            (cur->type == XML_HTML_DOCUMENT_NODE)) {
                    166:            i++;
                    167:        }
                    168:     }
                    169:     return(i);
                    170: }
                    171: 
                    172: /**
                    173:  * xmlXPtrGetNthChild:
                    174:  * @cur:  the node
                    175:  * @no:  the child number
                    176:  *
                    177:  * Returns the @no'th element child of @cur or NULL
                    178:  */
                    179: static xmlNodePtr
                    180: xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
                    181:     int i;
                    182:     if (cur == NULL) 
                    183:        return(cur);
                    184:     cur = cur->children;
                    185:     for (i = 0;i <= no;cur = cur->next) {
                    186:        if (cur == NULL) 
                    187:            return(cur);
                    188:        if ((cur->type == XML_ELEMENT_NODE) ||
                    189:            (cur->type == XML_DOCUMENT_NODE) ||
                    190:            (cur->type == XML_HTML_DOCUMENT_NODE)) {
                    191:            i++;
                    192:            if (i == no)
                    193:                break;
                    194:        }
                    195:     }
                    196:     return(cur);
                    197: }
                    198: 
                    199: /************************************************************************
                    200:  *                                                                     *
                    201:  *             Handling of XPointer specific types                     *
                    202:  *                                                                     *
                    203:  ************************************************************************/
                    204: 
                    205: /**
                    206:  * xmlXPtrCmpPoints:
                    207:  * @node1:  the first node
                    208:  * @index1:  the first index
                    209:  * @node2:  the second node
                    210:  * @index2:  the second index
                    211:  *
                    212:  * Compare two points w.r.t document order
                    213:  *
                    214:  * Returns -2 in case of error 1 if first point < second point, 0 if
                    215:  *         that's the same point, -1 otherwise
                    216:  */
                    217: static int
                    218: xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
                    219:     if ((node1 == NULL) || (node2 == NULL))
                    220:        return(-2);
                    221:     /*
                    222:      * a couple of optimizations which will avoid computations in most cases
                    223:      */
                    224:     if (node1 == node2) {
                    225:        if (index1 < index2)
                    226:            return(1);
                    227:        if (index1 > index2)
                    228:            return(-1);
                    229:        return(0);
                    230:     }
                    231:     return(xmlXPathCmpNodes(node1, node2));
                    232: }
                    233: 
                    234: /**
                    235:  * xmlXPtrNewPoint:
                    236:  * @node:  the xmlNodePtr
                    237:  * @indx:  the indx within the node
                    238:  *
                    239:  * Create a new xmlXPathObjectPtr of type point
                    240:  *
                    241:  * Returns the newly created object.
                    242:  */
                    243: static xmlXPathObjectPtr
                    244: xmlXPtrNewPoint(xmlNodePtr node, int indx) {
                    245:     xmlXPathObjectPtr ret;
                    246: 
                    247:     if (node == NULL)
                    248:        return(NULL);
                    249:     if (indx < 0)
                    250:        return(NULL);
                    251: 
                    252:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    253:     if (ret == NULL) {
                    254:         xmlXPtrErrMemory("allocating point");
                    255:        return(NULL);
                    256:     }
                    257:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    258:     ret->type = XPATH_POINT;
                    259:     ret->user = (void *) node;
                    260:     ret->index = indx;
                    261:     return(ret);
                    262: }
                    263: 
                    264: /**
                    265:  * xmlXPtrRangeCheckOrder:
                    266:  * @range:  an object range
                    267:  *
                    268:  * Make sure the points in the range are in the right order
                    269:  */
                    270: static void
                    271: xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
                    272:     int tmp;
                    273:     xmlNodePtr tmp2;
                    274:     if (range == NULL)
                    275:        return;
                    276:     if (range->type != XPATH_RANGE)
                    277:        return;
                    278:     if (range->user2 == NULL)
                    279:        return;
                    280:     tmp = xmlXPtrCmpPoints(range->user, range->index,
                    281:                             range->user2, range->index2);
                    282:     if (tmp == -1) {
                    283:        tmp2 = range->user;
                    284:        range->user = range->user2;
                    285:        range->user2 = tmp2;
                    286:        tmp = range->index;
                    287:        range->index = range->index2;
                    288:        range->index2 = tmp;
                    289:     }
                    290: }
                    291: 
                    292: /**
                    293:  * xmlXPtrRangesEqual:
                    294:  * @range1:  the first range
                    295:  * @range2:  the second range
                    296:  *
                    297:  * Compare two ranges
                    298:  *
                    299:  * Returns 1 if equal, 0 otherwise
                    300:  */
                    301: static int
                    302: xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
                    303:     if (range1 == range2)
                    304:        return(1);
                    305:     if ((range1 == NULL) || (range2 == NULL))
                    306:        return(0);
                    307:     if (range1->type != range2->type)
                    308:        return(0);
                    309:     if (range1->type != XPATH_RANGE)
                    310:        return(0);
                    311:     if (range1->user != range2->user)
                    312:        return(0);
                    313:     if (range1->index != range2->index)
                    314:        return(0);
                    315:     if (range1->user2 != range2->user2)
                    316:        return(0);
                    317:     if (range1->index2 != range2->index2)
                    318:        return(0);
                    319:     return(1);
                    320: }
                    321: 
                    322: /**
                    323:  * xmlXPtrNewRange:
                    324:  * @start:  the starting node
                    325:  * @startindex:  the start index
                    326:  * @end:  the ending point
                    327:  * @endindex:  the ending index
                    328:  *
                    329:  * Create a new xmlXPathObjectPtr of type range
                    330:  *
                    331:  * Returns the newly created object.
                    332:  */
                    333: xmlXPathObjectPtr
                    334: xmlXPtrNewRange(xmlNodePtr start, int startindex,
                    335:                xmlNodePtr end, int endindex) {
                    336:     xmlXPathObjectPtr ret;
                    337: 
                    338:     if (start == NULL)
                    339:        return(NULL);
                    340:     if (end == NULL)
                    341:        return(NULL);
                    342:     if (startindex < 0)
                    343:        return(NULL);
                    344:     if (endindex < 0)
                    345:        return(NULL);
                    346: 
                    347:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    348:     if (ret == NULL) {
                    349:         xmlXPtrErrMemory("allocating range");
                    350:        return(NULL);
                    351:     }
                    352:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    353:     ret->type = XPATH_RANGE;
                    354:     ret->user = start;
                    355:     ret->index = startindex;
                    356:     ret->user2 = end;
                    357:     ret->index2 = endindex;
                    358:     xmlXPtrRangeCheckOrder(ret);
                    359:     return(ret);
                    360: }
                    361: 
                    362: /**
                    363:  * xmlXPtrNewRangePoints:
                    364:  * @start:  the starting point
                    365:  * @end:  the ending point
                    366:  *
                    367:  * Create a new xmlXPathObjectPtr of type range using 2 Points
                    368:  *
                    369:  * Returns the newly created object.
                    370:  */
                    371: xmlXPathObjectPtr
                    372: xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
                    373:     xmlXPathObjectPtr ret;
                    374: 
                    375:     if (start == NULL)
                    376:        return(NULL);
                    377:     if (end == NULL)
                    378:        return(NULL);
                    379:     if (start->type != XPATH_POINT)
                    380:        return(NULL);
                    381:     if (end->type != XPATH_POINT)
                    382:        return(NULL);
                    383: 
                    384:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    385:     if (ret == NULL) {
                    386:         xmlXPtrErrMemory("allocating range");
                    387:        return(NULL);
                    388:     }
                    389:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    390:     ret->type = XPATH_RANGE;
                    391:     ret->user = start->user;
                    392:     ret->index = start->index;
                    393:     ret->user2 = end->user;
                    394:     ret->index2 = end->index;
                    395:     xmlXPtrRangeCheckOrder(ret);
                    396:     return(ret);
                    397: }
                    398: 
                    399: /**
                    400:  * xmlXPtrNewRangePointNode:
                    401:  * @start:  the starting point
                    402:  * @end:  the ending node
                    403:  *
                    404:  * Create a new xmlXPathObjectPtr of type range from a point to a node
                    405:  *
                    406:  * Returns the newly created object.
                    407:  */
                    408: xmlXPathObjectPtr
                    409: xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
                    410:     xmlXPathObjectPtr ret;
                    411: 
                    412:     if (start == NULL)
                    413:        return(NULL);
                    414:     if (end == NULL)
                    415:        return(NULL);
                    416:     if (start->type != XPATH_POINT)
                    417:        return(NULL);
                    418: 
                    419:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    420:     if (ret == NULL) {
                    421:         xmlXPtrErrMemory("allocating range");
                    422:        return(NULL);
                    423:     }
                    424:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    425:     ret->type = XPATH_RANGE;
                    426:     ret->user = start->user;
                    427:     ret->index = start->index;
                    428:     ret->user2 = end;
                    429:     ret->index2 = -1;
                    430:     xmlXPtrRangeCheckOrder(ret);
                    431:     return(ret);
                    432: }
                    433: 
                    434: /**
                    435:  * xmlXPtrNewRangeNodePoint:
                    436:  * @start:  the starting node
                    437:  * @end:  the ending point
                    438:  *
                    439:  * Create a new xmlXPathObjectPtr of type range from a node to a point
                    440:  *
                    441:  * Returns the newly created object.
                    442:  */
                    443: xmlXPathObjectPtr
                    444: xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
                    445:     xmlXPathObjectPtr ret;
                    446: 
                    447:     if (start == NULL)
                    448:        return(NULL);
                    449:     if (end == NULL)
                    450:        return(NULL);
                    451:     if (start->type != XPATH_POINT)
                    452:        return(NULL);
                    453:     if (end->type != XPATH_POINT)
                    454:        return(NULL);
                    455: 
                    456:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    457:     if (ret == NULL) {
                    458:         xmlXPtrErrMemory("allocating range");
                    459:        return(NULL);
                    460:     }
                    461:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    462:     ret->type = XPATH_RANGE;
                    463:     ret->user = start;
                    464:     ret->index = -1;
                    465:     ret->user2 = end->user;
                    466:     ret->index2 = end->index;
                    467:     xmlXPtrRangeCheckOrder(ret);
                    468:     return(ret);
                    469: }
                    470: 
                    471: /**
                    472:  * xmlXPtrNewRangeNodes:
                    473:  * @start:  the starting node
                    474:  * @end:  the ending node
                    475:  *
                    476:  * Create a new xmlXPathObjectPtr of type range using 2 nodes
                    477:  *
                    478:  * Returns the newly created object.
                    479:  */
                    480: xmlXPathObjectPtr
                    481: xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
                    482:     xmlXPathObjectPtr ret;
                    483: 
                    484:     if (start == NULL)
                    485:        return(NULL);
                    486:     if (end == NULL)
                    487:        return(NULL);
                    488: 
                    489:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    490:     if (ret == NULL) {
                    491:         xmlXPtrErrMemory("allocating range");
                    492:        return(NULL);
                    493:     }
                    494:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    495:     ret->type = XPATH_RANGE;
                    496:     ret->user = start;
                    497:     ret->index = -1;
                    498:     ret->user2 = end;
                    499:     ret->index2 = -1;
                    500:     xmlXPtrRangeCheckOrder(ret);
                    501:     return(ret);
                    502: }
                    503: 
                    504: /**
                    505:  * xmlXPtrNewCollapsedRange:
                    506:  * @start:  the starting and ending node
                    507:  *
                    508:  * Create a new xmlXPathObjectPtr of type range using a single nodes
                    509:  *
                    510:  * Returns the newly created object.
                    511:  */
                    512: xmlXPathObjectPtr
                    513: xmlXPtrNewCollapsedRange(xmlNodePtr start) {
                    514:     xmlXPathObjectPtr ret;
                    515: 
                    516:     if (start == NULL)
                    517:        return(NULL);
                    518: 
                    519:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    520:     if (ret == NULL) {
                    521:         xmlXPtrErrMemory("allocating range");
                    522:        return(NULL);
                    523:     }
                    524:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    525:     ret->type = XPATH_RANGE;
                    526:     ret->user = start;
                    527:     ret->index = -1;
                    528:     ret->user2 = NULL;
                    529:     ret->index2 = -1;
                    530:     return(ret);
                    531: }
                    532: 
                    533: /**
                    534:  * xmlXPtrNewRangeNodeObject:
                    535:  * @start:  the starting node
                    536:  * @end:  the ending object
                    537:  *
                    538:  * Create a new xmlXPathObjectPtr of type range from a not to an object
                    539:  *
                    540:  * Returns the newly created object.
                    541:  */
                    542: xmlXPathObjectPtr
                    543: xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
                    544:     xmlXPathObjectPtr ret;
                    545: 
                    546:     if (start == NULL)
                    547:        return(NULL);
                    548:     if (end == NULL)
                    549:        return(NULL);
                    550:     switch (end->type) {
                    551:        case XPATH_POINT:
                    552:        case XPATH_RANGE:
                    553:            break;
                    554:        case XPATH_NODESET:
                    555:            /*
                    556:             * Empty set ... 
                    557:             */
                    558:            if (end->nodesetval->nodeNr <= 0)
                    559:                return(NULL);
                    560:            break;
                    561:        default:
                    562:            /* TODO */
                    563:            return(NULL);
                    564:     }
                    565: 
                    566:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    567:     if (ret == NULL) {
                    568:         xmlXPtrErrMemory("allocating range");
                    569:        return(NULL);
                    570:     }
                    571:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    572:     ret->type = XPATH_RANGE;
                    573:     ret->user = start;
                    574:     ret->index = -1;
                    575:     switch (end->type) {
                    576:        case XPATH_POINT:
                    577:            ret->user2 = end->user;
                    578:            ret->index2 = end->index;
                    579:            break;
                    580:        case XPATH_RANGE:
                    581:            ret->user2 = end->user2;
                    582:            ret->index2 = end->index2;
                    583:            break;
                    584:        case XPATH_NODESET: {
                    585:            ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
                    586:            ret->index2 = -1;
                    587:            break;
                    588:        }
                    589:        default:
                    590:            STRANGE
                    591:            return(NULL);
                    592:     }
                    593:     xmlXPtrRangeCheckOrder(ret);
                    594:     return(ret);
                    595: }
                    596: 
                    597: #define XML_RANGESET_DEFAULT   10
                    598: 
                    599: /**
                    600:  * xmlXPtrLocationSetCreate:
                    601:  * @val:  an initial xmlXPathObjectPtr, or NULL
                    602:  *
                    603:  * Create a new xmlLocationSetPtr of type double and of value @val
                    604:  *
                    605:  * Returns the newly created object.
                    606:  */
                    607: xmlLocationSetPtr
                    608: xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) {
                    609:     xmlLocationSetPtr ret;
                    610: 
                    611:     ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet));
                    612:     if (ret == NULL) {
                    613:         xmlXPtrErrMemory("allocating locationset");
                    614:        return(NULL);
                    615:     }
                    616:     memset(ret, 0 , (size_t) sizeof(xmlLocationSet));
                    617:     if (val != NULL) {
                    618:         ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
                    619:                                             sizeof(xmlXPathObjectPtr));
                    620:        if (ret->locTab == NULL) {
                    621:            xmlXPtrErrMemory("allocating locationset");
                    622:            xmlFree(ret);
                    623:            return(NULL);
                    624:        }
                    625:        memset(ret->locTab, 0 ,
                    626:               XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
                    627:         ret->locMax = XML_RANGESET_DEFAULT;
                    628:        ret->locTab[ret->locNr++] = val;
                    629:     }
                    630:     return(ret);
                    631: }
                    632: 
                    633: /**
                    634:  * xmlXPtrLocationSetAdd:
                    635:  * @cur:  the initial range set
                    636:  * @val:  a new xmlXPathObjectPtr
                    637:  *
                    638:  * add a new xmlXPathObjectPtr to an existing LocationSet
                    639:  * If the location already exist in the set @val is freed.
                    640:  */
                    641: void
                    642: xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
                    643:     int i;
                    644: 
                    645:     if ((cur == NULL) || (val == NULL)) return;
                    646: 
                    647:     /*
                    648:      * check against doublons
                    649:      */
                    650:     for (i = 0;i < cur->locNr;i++) {
                    651:        if (xmlXPtrRangesEqual(cur->locTab[i], val)) {
                    652:            xmlXPathFreeObject(val);
                    653:            return;
                    654:        }
                    655:     }
                    656: 
                    657:     /*
                    658:      * grow the locTab if needed
                    659:      */
                    660:     if (cur->locMax == 0) {
                    661:         cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
                    662:                                             sizeof(xmlXPathObjectPtr));
                    663:        if (cur->locTab == NULL) {
                    664:            xmlXPtrErrMemory("adding location to set");
                    665:            return;
                    666:        }
                    667:        memset(cur->locTab, 0 ,
                    668:               XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
                    669:         cur->locMax = XML_RANGESET_DEFAULT;
                    670:     } else if (cur->locNr == cur->locMax) {
                    671:         xmlXPathObjectPtr *temp;
                    672: 
                    673:         cur->locMax *= 2;
                    674:        temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax *
                    675:                                      sizeof(xmlXPathObjectPtr));
                    676:        if (temp == NULL) {
                    677:            xmlXPtrErrMemory("adding location to set");
                    678:            return;
                    679:        }
                    680:        cur->locTab = temp;
                    681:     }
                    682:     cur->locTab[cur->locNr++] = val;
                    683: }
                    684: 
                    685: /**
                    686:  * xmlXPtrLocationSetMerge:
                    687:  * @val1:  the first LocationSet
                    688:  * @val2:  the second LocationSet
                    689:  *
                    690:  * Merges two rangesets, all ranges from @val2 are added to @val1
                    691:  *
                    692:  * Returns val1 once extended or NULL in case of error.
                    693:  */
                    694: xmlLocationSetPtr
                    695: xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
                    696:     int i;
                    697: 
                    698:     if (val1 == NULL) return(NULL);
                    699:     if (val2 == NULL) return(val1);
                    700: 
                    701:     /*
                    702:      * !!!!! this can be optimized a lot, knowing that both
                    703:      *       val1 and val2 already have unicity of their values.
                    704:      */
                    705: 
                    706:     for (i = 0;i < val2->locNr;i++)
                    707:         xmlXPtrLocationSetAdd(val1, val2->locTab[i]);
                    708: 
                    709:     return(val1);
                    710: }
                    711: 
                    712: /**
                    713:  * xmlXPtrLocationSetDel:
                    714:  * @cur:  the initial range set
                    715:  * @val:  an xmlXPathObjectPtr
                    716:  *
                    717:  * Removes an xmlXPathObjectPtr from an existing LocationSet
                    718:  */
                    719: void
                    720: xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
                    721:     int i;
                    722: 
                    723:     if (cur == NULL) return;
                    724:     if (val == NULL) return;
                    725: 
                    726:     /*
                    727:      * check against doublons
                    728:      */
                    729:     for (i = 0;i < cur->locNr;i++)
                    730:         if (cur->locTab[i] == val) break;
                    731: 
                    732:     if (i >= cur->locNr) {
                    733: #ifdef DEBUG
                    734:         xmlGenericError(xmlGenericErrorContext, 
                    735:                "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n");
                    736: #endif
                    737:         return;
                    738:     }
                    739:     cur->locNr--;
                    740:     for (;i < cur->locNr;i++)
                    741:         cur->locTab[i] = cur->locTab[i + 1];
                    742:     cur->locTab[cur->locNr] = NULL;
                    743: }
                    744: 
                    745: /**
                    746:  * xmlXPtrLocationSetRemove:
                    747:  * @cur:  the initial range set
                    748:  * @val:  the index to remove
                    749:  *
                    750:  * Removes an entry from an existing LocationSet list.
                    751:  */
                    752: void
                    753: xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) {
                    754:     if (cur == NULL) return;
                    755:     if (val >= cur->locNr) return;
                    756:     cur->locNr--;
                    757:     for (;val < cur->locNr;val++)
                    758:         cur->locTab[val] = cur->locTab[val + 1];
                    759:     cur->locTab[cur->locNr] = NULL;
                    760: }
                    761: 
                    762: /**
                    763:  * xmlXPtrFreeLocationSet:
                    764:  * @obj:  the xmlLocationSetPtr to free
                    765:  *
                    766:  * Free the LocationSet compound (not the actual ranges !).
                    767:  */
                    768: void
                    769: xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) {
                    770:     int i;
                    771: 
                    772:     if (obj == NULL) return;
                    773:     if (obj->locTab != NULL) {
                    774:        for (i = 0;i < obj->locNr; i++) {
                    775:             xmlXPathFreeObject(obj->locTab[i]);
                    776:        }
                    777:        xmlFree(obj->locTab);
                    778:     }
                    779:     xmlFree(obj);
                    780: }
                    781: 
                    782: /**
                    783:  * xmlXPtrNewLocationSetNodes:
                    784:  * @start:  the start NodePtr value
                    785:  * @end:  the end NodePtr value or NULL
                    786:  *
                    787:  * Create a new xmlXPathObjectPtr of type LocationSet and initialize
                    788:  * it with the single range made of the two nodes @start and @end
                    789:  *
                    790:  * Returns the newly created object.
                    791:  */
                    792: xmlXPathObjectPtr
                    793: xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) {
                    794:     xmlXPathObjectPtr ret;
                    795: 
                    796:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    797:     if (ret == NULL) {
                    798:         xmlXPtrErrMemory("allocating locationset");
                    799:        return(NULL);
                    800:     }
                    801:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    802:     ret->type = XPATH_LOCATIONSET;
                    803:     if (end == NULL)
                    804:        ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start));
                    805:     else
                    806:        ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end));
                    807:     return(ret);
                    808: }
                    809: 
                    810: /**
                    811:  * xmlXPtrNewLocationSetNodeSet:
                    812:  * @set:  a node set
                    813:  *
                    814:  * Create a new xmlXPathObjectPtr of type LocationSet and initialize
                    815:  * it with all the nodes from @set
                    816:  *
                    817:  * Returns the newly created object.
                    818:  */
                    819: xmlXPathObjectPtr
                    820: xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) {
                    821:     xmlXPathObjectPtr ret;
                    822: 
                    823:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    824:     if (ret == NULL) {
                    825:         xmlXPtrErrMemory("allocating locationset");
                    826:        return(NULL);
                    827:     }
                    828:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    829:     ret->type = XPATH_LOCATIONSET;
                    830:     if (set != NULL) {
                    831:        int i;
                    832:        xmlLocationSetPtr newset;
                    833: 
                    834:        newset = xmlXPtrLocationSetCreate(NULL);
                    835:        if (newset == NULL)
                    836:            return(ret);
                    837: 
                    838:        for (i = 0;i < set->nodeNr;i++)
                    839:            xmlXPtrLocationSetAdd(newset,
                    840:                        xmlXPtrNewCollapsedRange(set->nodeTab[i]));
                    841: 
                    842:        ret->user = (void *) newset;
                    843:     }
                    844:     return(ret);
                    845: }
                    846: 
                    847: /**
                    848:  * xmlXPtrWrapLocationSet:
                    849:  * @val:  the LocationSet value
                    850:  *
                    851:  * Wrap the LocationSet @val in a new xmlXPathObjectPtr
                    852:  *
                    853:  * Returns the newly created object.
                    854:  */
                    855: xmlXPathObjectPtr
                    856: xmlXPtrWrapLocationSet(xmlLocationSetPtr val) {
                    857:     xmlXPathObjectPtr ret;
                    858: 
                    859:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
                    860:     if (ret == NULL) {
                    861:         xmlXPtrErrMemory("allocating locationset");
                    862:        return(NULL);
                    863:     }
                    864:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
                    865:     ret->type = XPATH_LOCATIONSET;
                    866:     ret->user = (void *) val;
                    867:     return(ret);
                    868: }
                    869: 
                    870: /************************************************************************
                    871:  *                                                                     *
                    872:  *                     The parser                                      *
                    873:  *                                                                     *
                    874:  ************************************************************************/
                    875: 
                    876: static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name);
                    877: 
                    878: /*
                    879:  * Macros for accessing the content. Those should be used only by the parser,
                    880:  * and not exported.
                    881:  *
                    882:  * Dirty macros, i.e. one need to make assumption on the context to use them
                    883:  *
                    884:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
                    885:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
                    886:  *           in ISO-Latin or UTF-8.
                    887:  *           This should be used internally by the parser
                    888:  *           only to compare to ASCII values otherwise it would break when
                    889:  *           running with UTF-8 encoding.
                    890:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
                    891:  *           to compare on ASCII based substring.
                    892:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
                    893:  *           strings within the parser.
                    894:  *   CURRENT Returns the current char value, with the full decoding of
                    895:  *           UTF-8 if we are using this mode. It returns an int.
                    896:  *   NEXT    Skip to the next character, this does the proper decoding
                    897:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
                    898:  *           It returns the pointer to the current xmlChar.
                    899:  */
                    900: 
                    901: #define CUR (*ctxt->cur)
                    902: #define SKIP(val) ctxt->cur += (val)
                    903: #define NXT(val) ctxt->cur[(val)]
                    904: #define CUR_PTR ctxt->cur
                    905: 
                    906: #define SKIP_BLANKS                                                    \
                    907:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
                    908: 
                    909: #define CURRENT (*ctxt->cur)
                    910: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
                    911: 
                    912: /*
                    913:  * xmlXPtrGetChildNo:
                    914:  * @ctxt:  the XPointer Parser context
                    915:  * @index:  the child number
                    916:  *
                    917:  * Move the current node of the nodeset on the stack to the
                    918:  * given child if found
                    919:  */
                    920: static void
                    921: xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) {
                    922:     xmlNodePtr cur = NULL;
                    923:     xmlXPathObjectPtr obj;
                    924:     xmlNodeSetPtr oldset;
                    925: 
                    926:     CHECK_TYPE(XPATH_NODESET);
                    927:     obj = valuePop(ctxt);
                    928:     oldset = obj->nodesetval;
                    929:     if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
                    930:        xmlXPathFreeObject(obj);
                    931:        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
                    932:        return;
                    933:     }
                    934:     cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx);
                    935:     if (cur == NULL) {
                    936:        xmlXPathFreeObject(obj);
                    937:        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
                    938:        return;
                    939:     }
                    940:     oldset->nodeTab[0] = cur;
                    941:     valuePush(ctxt, obj);
                    942: }
                    943: 
                    944: /**
                    945:  * xmlXPtrEvalXPtrPart:
                    946:  * @ctxt:  the XPointer Parser context
                    947:  * @name:  the preparsed Scheme for the XPtrPart
                    948:  * 
                    949:  * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
                    950:  *            | Scheme '(' SchemeSpecificExpr ')'
                    951:  *
                    952:  * Scheme   ::=  NCName - 'xpointer' [VC: Non-XPointer schemes]
                    953:  *
                    954:  * SchemeSpecificExpr ::= StringWithBalancedParens
                    955:  *
                    956:  * StringWithBalancedParens ::=  
                    957:  *              [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
                    958:  *              [VC: Parenthesis escaping]
                    959:  *
                    960:  * XPtrExpr ::= Expr [VC: Parenthesis escaping]
                    961:  *
                    962:  * VC: Parenthesis escaping:
                    963:  *   The end of an XPointer part is signaled by the right parenthesis ")"
                    964:  *   character that is balanced with the left parenthesis "(" character
                    965:  *   that began the part. Any unbalanced parenthesis character inside the
                    966:  *   expression, even within literals, must be escaped with a circumflex (^)
                    967:  *   character preceding it. If the expression contains any literal
                    968:  *   occurrences of the circumflex, each must be escaped with an additional
                    969:  *   circumflex (that is, ^^). If the unescaped parentheses in the expression
                    970:  *   are not balanced, a syntax error results.
                    971:  *
                    972:  * Parse and evaluate an XPtrPart. Basically it generates the unescaped
                    973:  * string and if the scheme is 'xpointer' it will call the XPath interpreter.
                    974:  * 
                    975:  * TODO: there is no new scheme registration mechanism
                    976:  */
                    977: 
                    978: static void
                    979: xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
                    980:     xmlChar *buffer, *cur;
                    981:     int len;
                    982:     int level;
                    983: 
                    984:     if (name == NULL)
                    985:     name = xmlXPathParseName(ctxt);
                    986:     if (name == NULL)
                    987:        XP_ERROR(XPATH_EXPR_ERROR);
                    988: 
                    989:     if (CUR != '(')
                    990:        XP_ERROR(XPATH_EXPR_ERROR);
                    991:     NEXT;
                    992:     level = 1;
                    993: 
                    994:     len = xmlStrlen(ctxt->cur);
                    995:     len++;
                    996:     buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar));
                    997:     if (buffer == NULL) {
                    998:         xmlXPtrErrMemory("allocating buffer");
                    999:        return;
                   1000:     }
                   1001: 
                   1002:     cur = buffer;
                   1003:     while (CUR != 0) {
                   1004:        if (CUR == ')') {
                   1005:            level--;
                   1006:            if (level == 0) {
                   1007:                NEXT;
                   1008:                break;
                   1009:            }
                   1010:            *cur++ = CUR;
                   1011:        } else if (CUR == '(') {
                   1012:            level++;
                   1013:            *cur++ = CUR;
                   1014:        } else if (CUR == '^') {
                   1015:            NEXT;
                   1016:            if ((CUR == ')') || (CUR == '(') || (CUR == '^')) {
                   1017:                *cur++ = CUR;
                   1018:            } else {
                   1019:                *cur++ = '^';
                   1020:                *cur++ = CUR;
                   1021:            }
                   1022:        } else {
                   1023:            *cur++ = CUR;
                   1024:        }
                   1025:        NEXT;
                   1026:     }
                   1027:     *cur = 0;
                   1028: 
                   1029:     if ((level != 0) && (CUR == 0)) {
                   1030:        xmlFree(buffer);
                   1031:        XP_ERROR(XPTR_SYNTAX_ERROR);
                   1032:     }
                   1033: 
                   1034:     if (xmlStrEqual(name, (xmlChar *) "xpointer")) {
                   1035:        const xmlChar *left = CUR_PTR;
                   1036: 
                   1037:        CUR_PTR = buffer;
                   1038:        /*
                   1039:         * To evaluate an xpointer scheme element (4.3) we need:
                   1040:         *   context initialized to the root
                   1041:         *   context position initalized to 1
                   1042:         *   context size initialized to 1
                   1043:         */
                   1044:        ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
                   1045:        ctxt->context->proximityPosition = 1;
                   1046:        ctxt->context->contextSize = 1;
                   1047:        xmlXPathEvalExpr(ctxt);
                   1048:        CUR_PTR=left;
                   1049:     } else if (xmlStrEqual(name, (xmlChar *) "element")) {
                   1050:        const xmlChar *left = CUR_PTR;
                   1051:        xmlChar *name2;
                   1052: 
                   1053:        CUR_PTR = buffer;
                   1054:        if (buffer[0] == '/') {
                   1055:            xmlXPathRoot(ctxt);
                   1056:            xmlXPtrEvalChildSeq(ctxt, NULL);
                   1057:        } else {
                   1058:            name2 = xmlXPathParseName(ctxt);
                   1059:            if (name2 == NULL) {
                   1060:                CUR_PTR = left;
                   1061:                xmlFree(buffer);
                   1062:                XP_ERROR(XPATH_EXPR_ERROR);
                   1063:            }
                   1064:            xmlXPtrEvalChildSeq(ctxt, name2);
                   1065:        }
                   1066:        CUR_PTR = left;
                   1067: #ifdef XPTR_XMLNS_SCHEME
                   1068:     } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
                   1069:        const xmlChar *left = CUR_PTR;
                   1070:        xmlChar *prefix;
                   1071:        xmlChar *URI;
                   1072:        xmlURIPtr value;
                   1073: 
                   1074:        CUR_PTR = buffer;
                   1075:         prefix = xmlXPathParseNCName(ctxt);
                   1076:        if (prefix == NULL) {
                   1077:            xmlFree(buffer);
                   1078:            xmlFree(name);
                   1079:            XP_ERROR(XPTR_SYNTAX_ERROR);
                   1080:        }
                   1081:        SKIP_BLANKS;
                   1082:        if (CUR != '=') {
                   1083:            xmlFree(prefix);
                   1084:            xmlFree(buffer);
                   1085:            xmlFree(name);
                   1086:            XP_ERROR(XPTR_SYNTAX_ERROR);
                   1087:        }
                   1088:        NEXT;
                   1089:        SKIP_BLANKS;
                   1090:        /* @@ check escaping in the XPointer WD */
                   1091: 
                   1092:        value = xmlParseURI((const char *)ctxt->cur);
                   1093:        if (value == NULL) {
                   1094:            xmlFree(prefix);
                   1095:            xmlFree(buffer);
                   1096:            xmlFree(name);
                   1097:            XP_ERROR(XPTR_SYNTAX_ERROR);
                   1098:        }
                   1099:        URI = xmlSaveUri(value);
                   1100:        xmlFreeURI(value);
                   1101:        if (URI == NULL) {
                   1102:            xmlFree(prefix);
                   1103:            xmlFree(buffer);
                   1104:            xmlFree(name);
                   1105:            XP_ERROR(XPATH_MEMORY_ERROR);
                   1106:        }
                   1107:        
                   1108:        xmlXPathRegisterNs(ctxt->context, prefix, URI);
                   1109:        CUR_PTR = left;
                   1110:        xmlFree(URI);
                   1111:        xmlFree(prefix);
                   1112: #endif /* XPTR_XMLNS_SCHEME */
                   1113:     } else {
                   1114:         xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
                   1115:                   "unsupported scheme '%s'\n", name);
                   1116:     }
                   1117:     xmlFree(buffer);
                   1118:     xmlFree(name);
                   1119: }
                   1120: 
                   1121: /**
                   1122:  * xmlXPtrEvalFullXPtr:
                   1123:  * @ctxt:  the XPointer Parser context
                   1124:  * @name:  the preparsed Scheme for the first XPtrPart
                   1125:  *
                   1126:  * FullXPtr ::= XPtrPart (S? XPtrPart)*
                   1127:  *
                   1128:  * As the specs says:
                   1129:  * -----------
                   1130:  * When multiple XPtrParts are provided, they must be evaluated in
                   1131:  * left-to-right order. If evaluation of one part fails, the nexti
                   1132:  * is evaluated. The following conditions cause XPointer part failure:
                   1133:  *
                   1134:  * - An unknown scheme
                   1135:  * - A scheme that does not locate any sub-resource present in the resource
                   1136:  * - A scheme that is not applicable to the media type of the resource
                   1137:  *
                   1138:  * The XPointer application must consume a failed XPointer part and
                   1139:  * attempt to evaluate the next one, if any. The result of the first
                   1140:  * XPointer part whose evaluation succeeds is taken to be the fragment
                   1141:  * located by the XPointer as a whole. If all the parts fail, the result
                   1142:  * for the XPointer as a whole is a sub-resource error.
                   1143:  * -----------
                   1144:  *
                   1145:  * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
                   1146:  * expressions or other schemes.
                   1147:  */
                   1148: static void
                   1149: xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
                   1150:     if (name == NULL)
                   1151:     name = xmlXPathParseName(ctxt);
                   1152:     if (name == NULL)
                   1153:        XP_ERROR(XPATH_EXPR_ERROR);
                   1154:     while (name != NULL) {
                   1155:        ctxt->error = XPATH_EXPRESSION_OK;
                   1156:        xmlXPtrEvalXPtrPart(ctxt, name);
                   1157: 
                   1158:        /* in case of syntax error, break here */
                   1159:        if ((ctxt->error != XPATH_EXPRESSION_OK) &&
                   1160:             (ctxt->error != XML_XPTR_UNKNOWN_SCHEME))
                   1161:            return;
                   1162: 
                   1163:        /*
                   1164:         * If the returned value is a non-empty nodeset
                   1165:         * or location set, return here.
                   1166:         */
                   1167:        if (ctxt->value != NULL) {
                   1168:            xmlXPathObjectPtr obj = ctxt->value;
                   1169: 
                   1170:            switch (obj->type) {
                   1171:                case XPATH_LOCATIONSET: {
                   1172:                    xmlLocationSetPtr loc = ctxt->value->user;
                   1173:                    if ((loc != NULL) && (loc->locNr > 0))
                   1174:                        return;
                   1175:                    break;
                   1176:                }
                   1177:                case XPATH_NODESET: {
                   1178:                    xmlNodeSetPtr loc = ctxt->value->nodesetval;
                   1179:                    if ((loc != NULL) && (loc->nodeNr > 0))
                   1180:                        return;
                   1181:                    break;
                   1182:                }
                   1183:                default:
                   1184:                    break;
                   1185:            }
                   1186: 
                   1187:            /*
                   1188:             * Evaluating to improper values is equivalent to
                   1189:             * a sub-resource error, clean-up the stack
                   1190:             */
                   1191:            do {
                   1192:                obj = valuePop(ctxt);
                   1193:                if (obj != NULL) {
                   1194:                    xmlXPathFreeObject(obj);
                   1195:                }
                   1196:            } while (obj != NULL);
                   1197:        }
                   1198: 
                   1199:        /*
                   1200:         * Is there another XPointer part.
                   1201:         */
                   1202:        SKIP_BLANKS;
                   1203:        name = xmlXPathParseName(ctxt);
                   1204:     }
                   1205: }
                   1206: 
                   1207: /**
                   1208:  * xmlXPtrEvalChildSeq:
                   1209:  * @ctxt:  the XPointer Parser context
                   1210:  * @name:  a possible ID name of the child sequence
                   1211:  *
                   1212:  *  ChildSeq ::= '/1' ('/' [0-9]*)*
                   1213:  *             | Name ('/' [0-9]*)+
                   1214:  *
                   1215:  * Parse and evaluate a Child Sequence. This routine also handle the
                   1216:  * case of a Bare Name used to get a document ID.
                   1217:  */
                   1218: static void
                   1219: xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
                   1220:     /*
                   1221:      * XPointer don't allow by syntax to address in mutirooted trees
                   1222:      * this might prove useful in some cases, warn about it.
                   1223:      */
                   1224:     if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
                   1225:         xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
                   1226:                   "warning: ChildSeq not starting by /1\n", NULL);
                   1227:     }
                   1228: 
                   1229:     if (name != NULL) {
                   1230:        valuePush(ctxt, xmlXPathNewString(name));
                   1231:        xmlFree(name);
                   1232:        xmlXPathIdFunction(ctxt, 1);
                   1233:        CHECK_ERROR;
                   1234:     }
                   1235: 
                   1236:     while (CUR == '/') {
                   1237:        int child = 0;
                   1238:        NEXT;
                   1239:         
                   1240:        while ((CUR >= '0') && (CUR <= '9')) {
                   1241:            child = child * 10 + (CUR - '0');
                   1242:            NEXT;
                   1243:        }
                   1244:        xmlXPtrGetChildNo(ctxt, child);
                   1245:     }
                   1246: }
                   1247: 
                   1248: 
                   1249: /**
                   1250:  * xmlXPtrEvalXPointer:
                   1251:  * @ctxt:  the XPointer Parser context
                   1252:  *
                   1253:  *  XPointer ::= Name
                   1254:  *             | ChildSeq
                   1255:  *             | FullXPtr
                   1256:  *
                   1257:  * Parse and evaluate an XPointer
                   1258:  */
                   1259: static void
                   1260: xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
                   1261:     if (ctxt->valueTab == NULL) {
                   1262:        /* Allocate the value stack */
                   1263:        ctxt->valueTab = (xmlXPathObjectPtr *) 
                   1264:                         xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
                   1265:        if (ctxt->valueTab == NULL) {
                   1266:            xmlXPtrErrMemory("allocating evaluation context");
                   1267:            return;
                   1268:        }
                   1269:        ctxt->valueNr = 0;
                   1270:        ctxt->valueMax = 10;
                   1271:        ctxt->value = NULL;
                   1272:     }
                   1273:     SKIP_BLANKS;
                   1274:     if (CUR == '/') {
                   1275:        xmlXPathRoot(ctxt);
                   1276:         xmlXPtrEvalChildSeq(ctxt, NULL);
                   1277:     } else {
                   1278:        xmlChar *name;
                   1279: 
                   1280:        name = xmlXPathParseName(ctxt);
                   1281:        if (name == NULL)
                   1282:            XP_ERROR(XPATH_EXPR_ERROR);
                   1283:        if (CUR == '(') {
                   1284:            xmlXPtrEvalFullXPtr(ctxt, name);
                   1285:            /* Short evaluation */
                   1286:            return;
                   1287:        } else {
                   1288:            /* this handle both Bare Names and Child Sequences */
                   1289:            xmlXPtrEvalChildSeq(ctxt, name);
                   1290:        }
                   1291:     }
                   1292:     SKIP_BLANKS;
                   1293:     if (CUR != 0)
                   1294:        XP_ERROR(XPATH_EXPR_ERROR);
                   1295: }
                   1296: 
                   1297: 
                   1298: /************************************************************************
                   1299:  *                                                                     *
                   1300:  *                     General routines                                *
                   1301:  *                                                                     *
                   1302:  ************************************************************************/
                   1303: 
                   1304: static
                   1305: void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1306: static
                   1307: void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1308: static
                   1309: void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1310: static
                   1311: void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1312: static
                   1313: void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1314: static
                   1315: void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1316: static
                   1317: void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
                   1318: 
                   1319: /**
                   1320:  * xmlXPtrNewContext:
                   1321:  * @doc:  the XML document
                   1322:  * @here:  the node that directly contains the XPointer being evaluated or NULL
                   1323:  * @origin:  the element from which a user or program initiated traversal of
                   1324:  *           the link, or NULL.
                   1325:  *
                   1326:  * Create a new XPointer context
                   1327:  *
                   1328:  * Returns the xmlXPathContext just allocated.
                   1329:  */
                   1330: xmlXPathContextPtr
                   1331: xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
                   1332:     xmlXPathContextPtr ret;
                   1333: 
                   1334:     ret = xmlXPathNewContext(doc);
                   1335:     if (ret == NULL)
                   1336:        return(ret);
                   1337:     ret->xptr = 1;
                   1338:     ret->here = here;
                   1339:     ret->origin = origin;
                   1340: 
                   1341:     xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
                   1342:                         xmlXPtrRangeToFunction);
                   1343:     xmlXPathRegisterFunc(ret, (xmlChar *)"range",
                   1344:                         xmlXPtrRangeFunction);
                   1345:     xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
                   1346:                         xmlXPtrRangeInsideFunction);
                   1347:     xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
                   1348:                         xmlXPtrStringRangeFunction);
                   1349:     xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
                   1350:                         xmlXPtrStartPointFunction);
                   1351:     xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
                   1352:                         xmlXPtrEndPointFunction);
                   1353:     xmlXPathRegisterFunc(ret, (xmlChar *)"here",
                   1354:                         xmlXPtrHereFunction);
                   1355:     xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
                   1356:                         xmlXPtrOriginFunction);
                   1357: 
                   1358:     return(ret);
                   1359: }
                   1360: 
                   1361: /**
                   1362:  * xmlXPtrEval:
                   1363:  * @str:  the XPointer expression
                   1364:  * @ctx:  the XPointer context
                   1365:  *
                   1366:  * Evaluate the XPath Location Path in the given context.
                   1367:  *
                   1368:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
                   1369:  *         the caller has to free the object.
                   1370:  */
                   1371: xmlXPathObjectPtr
                   1372: xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
                   1373:     xmlXPathParserContextPtr ctxt;
                   1374:     xmlXPathObjectPtr res = NULL, tmp;
                   1375:     xmlXPathObjectPtr init = NULL;
                   1376:     int stack = 0;
                   1377: 
                   1378:     xmlXPathInit();
                   1379: 
                   1380:     if ((ctx == NULL) || (str == NULL))
                   1381:        return(NULL);
                   1382: 
                   1383:     ctxt = xmlXPathNewParserContext(str, ctx);
                   1384:     ctxt->xptr = 1;
                   1385:     xmlXPtrEvalXPointer(ctxt);
                   1386: 
                   1387:     if ((ctxt->value != NULL) &&
                   1388:        (ctxt->value->type != XPATH_NODESET) &&
                   1389:        (ctxt->value->type != XPATH_LOCATIONSET)) {
                   1390:         xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
                   1391:                "xmlXPtrEval: evaluation failed to return a node set\n",
                   1392:                   NULL);
                   1393:     } else {
                   1394:        res = valuePop(ctxt);
                   1395:     }
                   1396: 
                   1397:     do {
                   1398:         tmp = valuePop(ctxt);
                   1399:        if (tmp != NULL) {
                   1400:            if (tmp != init) {
                   1401:                if (tmp->type == XPATH_NODESET) {
                   1402:                    /*
                   1403:                     * Evaluation may push a root nodeset which is unused
                   1404:                     */
                   1405:                    xmlNodeSetPtr set; 
                   1406:                    set = tmp->nodesetval;
                   1407:                    if ((set->nodeNr != 1) ||
                   1408:                        (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
                   1409:                        stack++;
                   1410:                } else
                   1411:                    stack++;    
                   1412:            }
                   1413:            xmlXPathFreeObject(tmp);
                   1414:         }
                   1415:     } while (tmp != NULL);
                   1416:     if (stack != 0) {
                   1417:         xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
                   1418:                   "xmlXPtrEval: object(s) left on the eval stack\n",
                   1419:                   NULL);
                   1420:     }
                   1421:     if (ctxt->error != XPATH_EXPRESSION_OK) {
                   1422:        xmlXPathFreeObject(res);
                   1423:        res = NULL;
                   1424:     }
                   1425:         
                   1426:     xmlXPathFreeParserContext(ctxt);
                   1427:     return(res);
                   1428: }
                   1429: 
                   1430: /**
                   1431:  * xmlXPtrBuildRangeNodeList:
                   1432:  * @range:  a range object
                   1433:  *
                   1434:  * Build a node list tree copy of the range
                   1435:  *
                   1436:  * Returns an xmlNodePtr list or NULL.
                   1437:  *         the caller has to free the node tree.
                   1438:  */
                   1439: static xmlNodePtr
                   1440: xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
                   1441:     /* pointers to generated nodes */
                   1442:     xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
                   1443:     /* pointers to traversal nodes */
                   1444:     xmlNodePtr start, cur, end;
                   1445:     int index1, index2;
                   1446: 
                   1447:     if (range == NULL)
                   1448:        return(NULL);
                   1449:     if (range->type != XPATH_RANGE)
                   1450:        return(NULL);
                   1451:     start = (xmlNodePtr) range->user;
                   1452: 
                   1453:     if (start == NULL)
                   1454:        return(NULL);
                   1455:     end = range->user2;
                   1456:     if (end == NULL)
                   1457:        return(xmlCopyNode(start, 1));
                   1458: 
                   1459:     cur = start;
                   1460:     index1 = range->index;
                   1461:     index2 = range->index2;
                   1462:     while (cur != NULL) {
                   1463:        if (cur == end) {
                   1464:            if (cur->type == XML_TEXT_NODE) {
                   1465:                const xmlChar *content = cur->content;
                   1466:                int len;
                   1467: 
                   1468:                if (content == NULL) {
                   1469:                    tmp = xmlNewTextLen(NULL, 0);
                   1470:                } else {
                   1471:                    len = index2;
                   1472:                    if ((cur == start) && (index1 > 1)) {
                   1473:                        content += (index1 - 1);
                   1474:                        len -= (index1 - 1);
                   1475:                        index1 = 0;
                   1476:                    } else {
                   1477:                        len = index2;
                   1478:                    }
                   1479:                    tmp = xmlNewTextLen(content, len);
                   1480:                }
                   1481:                /* single sub text node selection */
                   1482:                if (list == NULL)
                   1483:                    return(tmp);
                   1484:                /* prune and return full set */
                   1485:                if (last != NULL)
                   1486:                    xmlAddNextSibling(last, tmp);
                   1487:                else 
                   1488:                    xmlAddChild(parent, tmp);
                   1489:                return(list);
                   1490:            } else {
                   1491:                tmp = xmlCopyNode(cur, 0);
                   1492:                if (list == NULL)
                   1493:                    list = tmp;
                   1494:                else {
                   1495:                    if (last != NULL)
                   1496:                        xmlAddNextSibling(last, tmp);
                   1497:                    else
                   1498:                        xmlAddChild(parent, tmp);
                   1499:                }
                   1500:                last = NULL;
                   1501:                parent = tmp;
                   1502: 
                   1503:                if (index2 > 1) {
                   1504:                    end = xmlXPtrGetNthChild(cur, index2 - 1);
                   1505:                    index2 = 0;
                   1506:                }
                   1507:                if ((cur == start) && (index1 > 1)) {
                   1508:                    cur = xmlXPtrGetNthChild(cur, index1 - 1);
                   1509:                    index1 = 0;
                   1510:                } else {
                   1511:                    cur = cur->children;
                   1512:                }
                   1513:                /*
                   1514:                 * Now gather the remaining nodes from cur to end
                   1515:                 */
                   1516:                continue; /* while */
                   1517:            }
                   1518:        } else if ((cur == start) &&
                   1519:                   (list == NULL) /* looks superfluous but ... */ ) {
                   1520:            if ((cur->type == XML_TEXT_NODE) ||
                   1521:                (cur->type == XML_CDATA_SECTION_NODE)) {
                   1522:                const xmlChar *content = cur->content;
                   1523: 
                   1524:                if (content == NULL) {
                   1525:                    tmp = xmlNewTextLen(NULL, 0);
                   1526:                } else {
                   1527:                    if (index1 > 1) {
                   1528:                        content += (index1 - 1);
                   1529:                    }
                   1530:                    tmp = xmlNewText(content);
                   1531:                }
                   1532:                last = list = tmp;
                   1533:            } else {
                   1534:                if ((cur == start) && (index1 > 1)) {
                   1535:                    tmp = xmlCopyNode(cur, 0);
                   1536:                    list = tmp;
                   1537:                    parent = tmp;
                   1538:                    last = NULL;
                   1539:                    cur = xmlXPtrGetNthChild(cur, index1 - 1);
                   1540:                    index1 = 0;
                   1541:                    /*
                   1542:                     * Now gather the remaining nodes from cur to end
                   1543:                     */
                   1544:                    continue; /* while */
                   1545:                }
                   1546:                tmp = xmlCopyNode(cur, 1);
                   1547:                list = tmp;
                   1548:                parent = NULL;
                   1549:                last = tmp;
                   1550:            }
                   1551:        } else {
                   1552:            tmp = NULL;
                   1553:            switch (cur->type) {
                   1554:                case XML_DTD_NODE:
                   1555:                case XML_ELEMENT_DECL:
                   1556:                case XML_ATTRIBUTE_DECL:
                   1557:                case XML_ENTITY_NODE:
                   1558:                    /* Do not copy DTD informations */
                   1559:                    break;
                   1560:                case XML_ENTITY_DECL:
                   1561:                    TODO /* handle crossing entities -> stack needed */
                   1562:                    break;
                   1563:                case XML_XINCLUDE_START:
                   1564:                case XML_XINCLUDE_END:
                   1565:                    /* don't consider it part of the tree content */
                   1566:                    break;
                   1567:                case XML_ATTRIBUTE_NODE:
                   1568:                    /* Humm, should not happen ! */
                   1569:                    STRANGE
                   1570:                    break;
                   1571:                default:
                   1572:                    tmp = xmlCopyNode(cur, 1);
                   1573:                    break;
                   1574:            }
                   1575:            if (tmp != NULL) {
                   1576:                if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
                   1577:                    STRANGE
                   1578:                    return(NULL);
                   1579:                }
                   1580:                if (last != NULL)
                   1581:                    xmlAddNextSibling(last, tmp);
                   1582:                else {
                   1583:                    xmlAddChild(parent, tmp);
                   1584:                    last = tmp;
                   1585:                }
                   1586:            }
                   1587:        }
                   1588:        /*
                   1589:         * Skip to next node in document order
                   1590:         */
                   1591:        if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
                   1592:            STRANGE
                   1593:            return(NULL);
                   1594:        }
                   1595:        cur = xmlXPtrAdvanceNode(cur, NULL);
                   1596:     }
                   1597:     return(list);
                   1598: }
                   1599: 
                   1600: /**
                   1601:  * xmlXPtrBuildNodeList:
                   1602:  * @obj:  the XPointer result from the evaluation.
                   1603:  *
                   1604:  * Build a node list tree copy of the XPointer result.
                   1605:  * This will drop Attributes and Namespace declarations.
                   1606:  *
                   1607:  * Returns an xmlNodePtr list or NULL.
                   1608:  *         the caller has to free the node tree.
                   1609:  */
                   1610: xmlNodePtr
                   1611: xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
                   1612:     xmlNodePtr list = NULL, last = NULL;
                   1613:     int i;
                   1614: 
                   1615:     if (obj == NULL)
                   1616:        return(NULL);
                   1617:     switch (obj->type) {
                   1618:         case XPATH_NODESET: {
                   1619:            xmlNodeSetPtr set = obj->nodesetval;
                   1620:            if (set == NULL)
                   1621:                return(NULL);
                   1622:            for (i = 0;i < set->nodeNr;i++) {
                   1623:                if (set->nodeTab[i] == NULL)
                   1624:                    continue;
                   1625:                switch (set->nodeTab[i]->type) {
                   1626:                    case XML_TEXT_NODE:
                   1627:                    case XML_CDATA_SECTION_NODE:
                   1628:                    case XML_ELEMENT_NODE:
                   1629:                    case XML_ENTITY_REF_NODE:
                   1630:                    case XML_ENTITY_NODE:
                   1631:                    case XML_PI_NODE:
                   1632:                    case XML_COMMENT_NODE:
                   1633:                    case XML_DOCUMENT_NODE:
                   1634:                    case XML_HTML_DOCUMENT_NODE:
                   1635: #ifdef LIBXML_DOCB_ENABLED
                   1636:                    case XML_DOCB_DOCUMENT_NODE:
                   1637: #endif
                   1638:                    case XML_XINCLUDE_START:
                   1639:                    case XML_XINCLUDE_END:
                   1640:                        break;
                   1641:                    case XML_ATTRIBUTE_NODE:
                   1642:                    case XML_NAMESPACE_DECL:
                   1643:                    case XML_DOCUMENT_TYPE_NODE:
                   1644:                    case XML_DOCUMENT_FRAG_NODE:
                   1645:                    case XML_NOTATION_NODE:
                   1646:                    case XML_DTD_NODE:
                   1647:                    case XML_ELEMENT_DECL:
                   1648:                    case XML_ATTRIBUTE_DECL:
                   1649:                    case XML_ENTITY_DECL:
                   1650:                        continue; /* for */
                   1651:                }
                   1652:                if (last == NULL)
                   1653:                    list = last = xmlCopyNode(set->nodeTab[i], 1);
                   1654:                else {
                   1655:                    xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
                   1656:                    if (last->next != NULL)
                   1657:                        last = last->next;
                   1658:                }
                   1659:            }
                   1660:            break;
                   1661:        }
                   1662:        case XPATH_LOCATIONSET: {
                   1663:            xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
                   1664:            if (set == NULL)
                   1665:                return(NULL);
                   1666:            for (i = 0;i < set->locNr;i++) {
                   1667:                if (last == NULL)
                   1668:                    list = last = xmlXPtrBuildNodeList(set->locTab[i]);
                   1669:                else
                   1670:                    xmlAddNextSibling(last,
                   1671:                            xmlXPtrBuildNodeList(set->locTab[i]));
                   1672:                if (last != NULL) {
                   1673:                    while (last->next != NULL)
                   1674:                        last = last->next;
                   1675:                }
                   1676:            }
                   1677:            break;
                   1678:        }
                   1679:        case XPATH_RANGE:
                   1680:            return(xmlXPtrBuildRangeNodeList(obj));
                   1681:        case XPATH_POINT:
                   1682:            return(xmlCopyNode(obj->user, 0));
                   1683:        default:
                   1684:            break;
                   1685:     }
                   1686:     return(list);
                   1687: }
                   1688: 
                   1689: /************************************************************************
                   1690:  *                                                                     *
                   1691:  *                     XPointer functions                              *
                   1692:  *                                                                     *
                   1693:  ************************************************************************/
                   1694: 
                   1695: /**
                   1696:  * xmlXPtrNbLocChildren:
                   1697:  * @node:  an xmlNodePtr
                   1698:  *
                   1699:  * Count the number of location children of @node or the length of the
                   1700:  * string value in case of text/PI/Comments nodes
                   1701:  *
                   1702:  * Returns the number of location children
                   1703:  */
                   1704: static int
                   1705: xmlXPtrNbLocChildren(xmlNodePtr node) {
                   1706:     int ret = 0;
                   1707:     if (node == NULL)
                   1708:        return(-1);
                   1709:     switch (node->type) {
                   1710:         case XML_HTML_DOCUMENT_NODE:
                   1711:         case XML_DOCUMENT_NODE:
                   1712:         case XML_ELEMENT_NODE:
                   1713:            node = node->children;
                   1714:            while (node != NULL) {
                   1715:                if (node->type == XML_ELEMENT_NODE)
                   1716:                    ret++;
                   1717:                node = node->next;
                   1718:            }
                   1719:            break;
                   1720:         case XML_ATTRIBUTE_NODE:
                   1721:            return(-1);
                   1722: 
                   1723:         case XML_PI_NODE:
                   1724:         case XML_COMMENT_NODE:
                   1725:         case XML_TEXT_NODE:
                   1726:         case XML_CDATA_SECTION_NODE:
                   1727:         case XML_ENTITY_REF_NODE:
                   1728:            ret = xmlStrlen(node->content);
                   1729:            break;
                   1730:        default:
                   1731:            return(-1);
                   1732:     }
                   1733:     return(ret);
                   1734: }
                   1735: 
                   1736: /**
                   1737:  * xmlXPtrHereFunction:
                   1738:  * @ctxt:  the XPointer Parser context
                   1739:  * @nargs:  the number of args
                   1740:  *
                   1741:  * Function implementing here() operation 
                   1742:  * as described in 5.4.3
                   1743:  */
                   1744: static void
                   1745: xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   1746:     CHECK_ARITY(0);
                   1747: 
                   1748:     if (ctxt->context->here == NULL)
                   1749:        XP_ERROR(XPTR_SYNTAX_ERROR);
                   1750:     
                   1751:     valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
                   1752: }
                   1753: 
                   1754: /**
                   1755:  * xmlXPtrOriginFunction:
                   1756:  * @ctxt:  the XPointer Parser context
                   1757:  * @nargs:  the number of args
                   1758:  *
                   1759:  * Function implementing origin() operation 
                   1760:  * as described in 5.4.3
                   1761:  */
                   1762: static void
                   1763: xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   1764:     CHECK_ARITY(0);
                   1765: 
                   1766:     if (ctxt->context->origin == NULL)
                   1767:        XP_ERROR(XPTR_SYNTAX_ERROR);
                   1768:     
                   1769:     valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
                   1770: }
                   1771: 
                   1772: /**
                   1773:  * xmlXPtrStartPointFunction:
                   1774:  * @ctxt:  the XPointer Parser context
                   1775:  * @nargs:  the number of args
                   1776:  *
                   1777:  * Function implementing start-point() operation 
                   1778:  * as described in 5.4.3
                   1779:  * ----------------
                   1780:  * location-set start-point(location-set)
                   1781:  *
                   1782:  * For each location x in the argument location-set, start-point adds a
                   1783:  * location of type point to the result location-set. That point represents
                   1784:  * the start point of location x and is determined by the following rules:
                   1785:  *
                   1786:  * - If x is of type point, the start point is x.
                   1787:  * - If x is of type range, the start point is the start point of x.
                   1788:  * - If x is of type root, element, text, comment, or processing instruction,
                   1789:  * - the container node of the start point is x and the index is 0.
                   1790:  * - If x is of type attribute or namespace, the function must signal a
                   1791:  *   syntax error.
                   1792:  * ----------------
                   1793:  *
                   1794:  */
                   1795: static void
                   1796: xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   1797:     xmlXPathObjectPtr tmp, obj, point;
                   1798:     xmlLocationSetPtr newset = NULL;
                   1799:     xmlLocationSetPtr oldset = NULL;
                   1800: 
                   1801:     CHECK_ARITY(1);
                   1802:     if ((ctxt->value == NULL) ||
                   1803:        ((ctxt->value->type != XPATH_LOCATIONSET) &&
                   1804:         (ctxt->value->type != XPATH_NODESET)))
                   1805:         XP_ERROR(XPATH_INVALID_TYPE)
                   1806: 
                   1807:     obj = valuePop(ctxt);
                   1808:     if (obj->type == XPATH_NODESET) {
                   1809:        /*
                   1810:         * First convert to a location set
                   1811:         */
                   1812:        tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
                   1813:        xmlXPathFreeObject(obj);
                   1814:        obj = tmp;
                   1815:     }
                   1816: 
                   1817:     newset = xmlXPtrLocationSetCreate(NULL);
                   1818:     if (newset == NULL) {
                   1819:        xmlXPathFreeObject(obj);
                   1820:         XP_ERROR(XPATH_MEMORY_ERROR);
                   1821:     }
                   1822:     oldset = (xmlLocationSetPtr) obj->user;
                   1823:     if (oldset != NULL) {
                   1824:        int i;
                   1825: 
                   1826:        for (i = 0; i < oldset->locNr; i++) {
                   1827:            tmp = oldset->locTab[i];
                   1828:            if (tmp == NULL)
                   1829:                continue;
                   1830:            point = NULL;
                   1831:            switch (tmp->type) {
                   1832:                case XPATH_POINT:
                   1833:                    point = xmlXPtrNewPoint(tmp->user, tmp->index);
                   1834:                    break;
                   1835:                case XPATH_RANGE: {
                   1836:                    xmlNodePtr node = tmp->user;
                   1837:                    if (node != NULL) {
                   1838:                        if (node->type == XML_ATTRIBUTE_NODE) {
                   1839:                            /* TODO: Namespace Nodes ??? */
                   1840:                            xmlXPathFreeObject(obj);
                   1841:                            xmlXPtrFreeLocationSet(newset);
                   1842:                            XP_ERROR(XPTR_SYNTAX_ERROR);
                   1843:                        }
                   1844:                        point = xmlXPtrNewPoint(node, tmp->index);
                   1845:                    }
                   1846:                    break;
                   1847:                }
                   1848:                default:
                   1849:                    /*** Should we raise an error ?
                   1850:                    xmlXPathFreeObject(obj);
                   1851:                    xmlXPathFreeObject(newset);
                   1852:                    XP_ERROR(XPATH_INVALID_TYPE)
                   1853:                    ***/
                   1854:                    break;
                   1855:            }
                   1856:             if (point != NULL)
                   1857:                xmlXPtrLocationSetAdd(newset, point);
                   1858:        }
                   1859:     }
                   1860:     xmlXPathFreeObject(obj);
                   1861:     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   1862: }
                   1863: 
                   1864: /**
                   1865:  * xmlXPtrEndPointFunction:
                   1866:  * @ctxt:  the XPointer Parser context
                   1867:  * @nargs:  the number of args
                   1868:  *
                   1869:  * Function implementing end-point() operation 
                   1870:  * as described in 5.4.3
                   1871:  * ----------------------------
                   1872:  * location-set end-point(location-set)
                   1873:  *
                   1874:  * For each location x in the argument location-set, end-point adds a
                   1875:  * location of type point to the result location-set. That point represents
                   1876:  * the end point of location x and is determined by the following rules:
                   1877:  *
                   1878:  * - If x is of type point, the resulting point is x.
                   1879:  * - If x is of type range, the resulting point is the end point of x.
                   1880:  * - If x is of type root or element, the container node of the resulting
                   1881:  *   point is x and the index is the number of location children of x.
                   1882:  * - If x is of type text, comment, or processing instruction, the container
                   1883:  *   node of the resulting point is x and the index is the length of the
                   1884:  *   string-value of x.
                   1885:  * - If x is of type attribute or namespace, the function must signal a
                   1886:  *   syntax error.
                   1887:  * ----------------------------
                   1888:  */
                   1889: static void
                   1890: xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   1891:     xmlXPathObjectPtr tmp, obj, point;
                   1892:     xmlLocationSetPtr newset = NULL;
                   1893:     xmlLocationSetPtr oldset = NULL;
                   1894: 
                   1895:     CHECK_ARITY(1);
                   1896:     if ((ctxt->value == NULL) ||
                   1897:        ((ctxt->value->type != XPATH_LOCATIONSET) &&
                   1898:         (ctxt->value->type != XPATH_NODESET)))
                   1899:         XP_ERROR(XPATH_INVALID_TYPE)
                   1900: 
                   1901:     obj = valuePop(ctxt);
                   1902:     if (obj->type == XPATH_NODESET) {
                   1903:        /*
                   1904:         * First convert to a location set
                   1905:         */
                   1906:        tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
                   1907:        xmlXPathFreeObject(obj);
                   1908:        obj = tmp;
                   1909:     }
                   1910: 
                   1911:     newset = xmlXPtrLocationSetCreate(NULL);
                   1912:     oldset = (xmlLocationSetPtr) obj->user;
                   1913:     if (oldset != NULL) {
                   1914:        int i;
                   1915: 
                   1916:        for (i = 0; i < oldset->locNr; i++) {
                   1917:            tmp = oldset->locTab[i];
                   1918:            if (tmp == NULL)
                   1919:                continue;
                   1920:            point = NULL;
                   1921:            switch (tmp->type) {
                   1922:                case XPATH_POINT:
                   1923:                    point = xmlXPtrNewPoint(tmp->user, tmp->index);
                   1924:                    break;
                   1925:                case XPATH_RANGE: {
                   1926:                    xmlNodePtr node = tmp->user2;
                   1927:                    if (node != NULL) {
                   1928:                        if (node->type == XML_ATTRIBUTE_NODE) {
                   1929:                            /* TODO: Namespace Nodes ??? */
                   1930:                            xmlXPathFreeObject(obj);
                   1931:                            xmlXPtrFreeLocationSet(newset);
                   1932:                            XP_ERROR(XPTR_SYNTAX_ERROR);
                   1933:                        }
                   1934:                        point = xmlXPtrNewPoint(node, tmp->index2);
                   1935:                    } else if (tmp->user == NULL) {
                   1936:                        point = xmlXPtrNewPoint(node,
                   1937:                                       xmlXPtrNbLocChildren(node));
                   1938:                    }
                   1939:                    break;
                   1940:                }
                   1941:                default:
                   1942:                    /*** Should we raise an error ?
                   1943:                    xmlXPathFreeObject(obj);
                   1944:                    xmlXPathFreeObject(newset);
                   1945:                    XP_ERROR(XPATH_INVALID_TYPE)
                   1946:                    ***/
                   1947:                    break;
                   1948:            }
                   1949:             if (point != NULL)
                   1950:                xmlXPtrLocationSetAdd(newset, point);
                   1951:        }
                   1952:     }
                   1953:     xmlXPathFreeObject(obj);
                   1954:     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   1955: }
                   1956: 
                   1957: 
                   1958: /**
                   1959:  * xmlXPtrCoveringRange:
                   1960:  * @ctxt:  the XPointer Parser context
                   1961:  * @loc:  the location for which the covering range must be computed
                   1962:  *
                   1963:  * A covering range is a range that wholly encompasses a location
                   1964:  * Section 5.3.3. Covering Ranges for All Location Types
                   1965:  *        http://www.w3.org/TR/xptr#N2267
                   1966:  *
                   1967:  * Returns a new location or NULL in case of error
                   1968:  */
                   1969: static xmlXPathObjectPtr
                   1970: xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
                   1971:     if (loc == NULL)
                   1972:        return(NULL);
                   1973:     if ((ctxt == NULL) || (ctxt->context == NULL) ||
                   1974:        (ctxt->context->doc == NULL))
                   1975:        return(NULL);
                   1976:     switch (loc->type) {
                   1977:         case XPATH_POINT:
                   1978:            return(xmlXPtrNewRange(loc->user, loc->index,
                   1979:                                   loc->user, loc->index));
                   1980:         case XPATH_RANGE:
                   1981:            if (loc->user2 != NULL) {
                   1982:                return(xmlXPtrNewRange(loc->user, loc->index,
                   1983:                                      loc->user2, loc->index2));
                   1984:            } else {
                   1985:                xmlNodePtr node = (xmlNodePtr) loc->user;
                   1986:                if (node == (xmlNodePtr) ctxt->context->doc) {
                   1987:                    return(xmlXPtrNewRange(node, 0, node,
                   1988:                                           xmlXPtrGetArity(node)));
                   1989:                } else {
                   1990:                    switch (node->type) {
                   1991:                        case XML_ATTRIBUTE_NODE:
                   1992:                        /* !!! our model is slightly different than XPath */
                   1993:                            return(xmlXPtrNewRange(node, 0, node,
                   1994:                                                   xmlXPtrGetArity(node)));
                   1995:                        case XML_ELEMENT_NODE:
                   1996:                        case XML_TEXT_NODE:
                   1997:                        case XML_CDATA_SECTION_NODE:
                   1998:                        case XML_ENTITY_REF_NODE:
                   1999:                        case XML_PI_NODE:
                   2000:                        case XML_COMMENT_NODE:
                   2001:                        case XML_DOCUMENT_NODE:
                   2002:                        case XML_NOTATION_NODE:
                   2003:                        case XML_HTML_DOCUMENT_NODE: {
                   2004:                            int indx = xmlXPtrGetIndex(node);
                   2005:                             
                   2006:                            node = node->parent;
                   2007:                            return(xmlXPtrNewRange(node, indx - 1,
                   2008:                                                   node, indx + 1));
                   2009:                        }
                   2010:                        default:
                   2011:                            return(NULL);
                   2012:                    }
                   2013:                }
                   2014:            }
                   2015:        default:
                   2016:            TODO /* missed one case ??? */
                   2017:     }
                   2018:     return(NULL);
                   2019: }
                   2020: 
                   2021: /**
                   2022:  * xmlXPtrRangeFunction:
                   2023:  * @ctxt:  the XPointer Parser context
                   2024:  * @nargs:  the number of args
                   2025:  *
                   2026:  * Function implementing the range() function 5.4.3
                   2027:  *  location-set range(location-set )
                   2028:  *
                   2029:  *  The range function returns ranges covering the locations in
                   2030:  *  the argument location-set. For each location x in the argument
                   2031:  *  location-set, a range location representing the covering range of
                   2032:  *  x is added to the result location-set.
                   2033:  */
                   2034: static void
                   2035: xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   2036:     int i;
                   2037:     xmlXPathObjectPtr set;
                   2038:     xmlLocationSetPtr oldset;
                   2039:     xmlLocationSetPtr newset;
                   2040: 
                   2041:     CHECK_ARITY(1);
                   2042:     if ((ctxt->value == NULL) ||
                   2043:        ((ctxt->value->type != XPATH_LOCATIONSET) &&
                   2044:         (ctxt->value->type != XPATH_NODESET)))
                   2045:         XP_ERROR(XPATH_INVALID_TYPE)
                   2046: 
                   2047:     set = valuePop(ctxt);
                   2048:     if (set->type == XPATH_NODESET) {
                   2049:        xmlXPathObjectPtr tmp;
                   2050: 
                   2051:        /*
                   2052:         * First convert to a location set
                   2053:         */
                   2054:        tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
                   2055:        xmlXPathFreeObject(set);
                   2056:        set = tmp;
                   2057:     }
                   2058:     oldset = (xmlLocationSetPtr) set->user;
                   2059: 
                   2060:     /*
                   2061:      * The loop is to compute the covering range for each item and add it
                   2062:      */
                   2063:     newset = xmlXPtrLocationSetCreate(NULL);
                   2064:     for (i = 0;i < oldset->locNr;i++) {
                   2065:        xmlXPtrLocationSetAdd(newset,
                   2066:                xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
                   2067:     }
                   2068: 
                   2069:     /*
                   2070:      * Save the new value and cleanup
                   2071:      */
                   2072:     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   2073:     xmlXPathFreeObject(set);
                   2074: }
                   2075: 
                   2076: /**
                   2077:  * xmlXPtrInsideRange:
                   2078:  * @ctxt:  the XPointer Parser context
                   2079:  * @loc:  the location for which the inside range must be computed
                   2080:  *
                   2081:  * A inside range is a range described in the range-inside() description
                   2082:  *
                   2083:  * Returns a new location or NULL in case of error
                   2084:  */
                   2085: static xmlXPathObjectPtr
                   2086: xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
                   2087:     if (loc == NULL)
                   2088:        return(NULL);
                   2089:     if ((ctxt == NULL) || (ctxt->context == NULL) ||
                   2090:        (ctxt->context->doc == NULL))
                   2091:        return(NULL);
                   2092:     switch (loc->type) {
                   2093:         case XPATH_POINT: {
                   2094:            xmlNodePtr node = (xmlNodePtr) loc->user;
                   2095:            switch (node->type) {
                   2096:                case XML_PI_NODE:
                   2097:                case XML_COMMENT_NODE:
                   2098:                case XML_TEXT_NODE:
                   2099:                case XML_CDATA_SECTION_NODE: {
                   2100:                    if (node->content == NULL) {
                   2101:                        return(xmlXPtrNewRange(node, 0, node, 0));
                   2102:                    } else {
                   2103:                        return(xmlXPtrNewRange(node, 0, node,
                   2104:                                               xmlStrlen(node->content)));
                   2105:                    }
                   2106:                }
                   2107:                case XML_ATTRIBUTE_NODE:
                   2108:                case XML_ELEMENT_NODE:
                   2109:                case XML_ENTITY_REF_NODE:
                   2110:                case XML_DOCUMENT_NODE:
                   2111:                case XML_NOTATION_NODE:
                   2112:                case XML_HTML_DOCUMENT_NODE: {
                   2113:                    return(xmlXPtrNewRange(node, 0, node,
                   2114:                                           xmlXPtrGetArity(node)));
                   2115:                }
                   2116:                default:
                   2117:                    break;
                   2118:            }
                   2119:            return(NULL);
                   2120:        }
                   2121:         case XPATH_RANGE: {
                   2122:            xmlNodePtr node = (xmlNodePtr) loc->user;
                   2123:            if (loc->user2 != NULL) {
                   2124:                return(xmlXPtrNewRange(node, loc->index,
                   2125:                                       loc->user2, loc->index2));
                   2126:            } else {
                   2127:                switch (node->type) {
                   2128:                    case XML_PI_NODE:
                   2129:                    case XML_COMMENT_NODE:
                   2130:                    case XML_TEXT_NODE:
                   2131:                    case XML_CDATA_SECTION_NODE: {
                   2132:                        if (node->content == NULL) {
                   2133:                            return(xmlXPtrNewRange(node, 0, node, 0));
                   2134:                        } else {
                   2135:                            return(xmlXPtrNewRange(node, 0, node,
                   2136:                                                   xmlStrlen(node->content)));
                   2137:                        }
                   2138:                    }
                   2139:                    case XML_ATTRIBUTE_NODE:
                   2140:                    case XML_ELEMENT_NODE:
                   2141:                    case XML_ENTITY_REF_NODE:
                   2142:                    case XML_DOCUMENT_NODE:
                   2143:                    case XML_NOTATION_NODE:
                   2144:                    case XML_HTML_DOCUMENT_NODE: {
                   2145:                        return(xmlXPtrNewRange(node, 0, node,
                   2146:                                               xmlXPtrGetArity(node)));
                   2147:                    }
                   2148:                    default:
                   2149:                        break;
                   2150:                }
                   2151:                return(NULL);
                   2152:            }
                   2153:         }
                   2154:        default:
                   2155:            TODO /* missed one case ??? */
                   2156:     }
                   2157:     return(NULL);
                   2158: }
                   2159: 
                   2160: /**
                   2161:  * xmlXPtrRangeInsideFunction:
                   2162:  * @ctxt:  the XPointer Parser context
                   2163:  * @nargs:  the number of args
                   2164:  *
                   2165:  * Function implementing the range-inside() function 5.4.3
                   2166:  *  location-set range-inside(location-set )
                   2167:  *
                   2168:  *  The range-inside function returns ranges covering the contents of
                   2169:  *  the locations in the argument location-set. For each location x in
                   2170:  *  the argument location-set, a range location is added to the result
                   2171:  *  location-set. If x is a range location, then x is added to the
                   2172:  *  result location-set. If x is not a range location, then x is used
                   2173:  *  as the container location of the start and end points of the range
                   2174:  *  location to be added; the index of the start point of the range is
                   2175:  *  zero; if the end point is a character point then its index is the
                   2176:  *  length of the string-value of x, and otherwise is the number of
                   2177:  *  location children of x.
                   2178:  *
                   2179:  */
                   2180: static void
                   2181: xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   2182:     int i;
                   2183:     xmlXPathObjectPtr set;
                   2184:     xmlLocationSetPtr oldset;
                   2185:     xmlLocationSetPtr newset;
                   2186: 
                   2187:     CHECK_ARITY(1);
                   2188:     if ((ctxt->value == NULL) ||
                   2189:        ((ctxt->value->type != XPATH_LOCATIONSET) &&
                   2190:         (ctxt->value->type != XPATH_NODESET)))
                   2191:         XP_ERROR(XPATH_INVALID_TYPE)
                   2192: 
                   2193:     set = valuePop(ctxt);
                   2194:     if (set->type == XPATH_NODESET) {
                   2195:        xmlXPathObjectPtr tmp;
                   2196: 
                   2197:        /*
                   2198:         * First convert to a location set
                   2199:         */
                   2200:        tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
                   2201:        xmlXPathFreeObject(set);
                   2202:        set = tmp;
                   2203:     }
                   2204:     oldset = (xmlLocationSetPtr) set->user;
                   2205: 
                   2206:     /*
                   2207:      * The loop is to compute the covering range for each item and add it
                   2208:      */
                   2209:     newset = xmlXPtrLocationSetCreate(NULL);
                   2210:     for (i = 0;i < oldset->locNr;i++) {
                   2211:        xmlXPtrLocationSetAdd(newset,
                   2212:                xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
                   2213:     }
                   2214: 
                   2215:     /*
                   2216:      * Save the new value and cleanup
                   2217:      */
                   2218:     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   2219:     xmlXPathFreeObject(set);
                   2220: }
                   2221: 
                   2222: /**
                   2223:  * xmlXPtrRangeToFunction:
                   2224:  * @ctxt:  the XPointer Parser context
                   2225:  * @nargs:  the number of args
                   2226:  *
                   2227:  * Implement the range-to() XPointer function
                   2228:  */
                   2229: void
                   2230: xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   2231:     xmlXPathObjectPtr range;
                   2232:     const xmlChar *cur;
                   2233:     xmlXPathObjectPtr res, obj;
                   2234:     xmlXPathObjectPtr tmp;
                   2235:     xmlLocationSetPtr newset = NULL;
                   2236:     xmlNodeSetPtr oldset;
                   2237:     int i;
                   2238: 
                   2239:     if (ctxt == NULL) return;
                   2240:     CHECK_ARITY(1);
                   2241:     /*
                   2242:      * Save the expression pointer since we will have to evaluate
                   2243:      * it multiple times. Initialize the new set.
                   2244:      */
                   2245:     CHECK_TYPE(XPATH_NODESET);
                   2246:     obj = valuePop(ctxt);
                   2247:     oldset = obj->nodesetval;
                   2248:     ctxt->context->node = NULL;
                   2249: 
                   2250:     cur = ctxt->cur;
                   2251:     newset = xmlXPtrLocationSetCreate(NULL);
                   2252:     
                   2253:     for (i = 0; i < oldset->nodeNr; i++) {
                   2254:        ctxt->cur = cur;
                   2255: 
                   2256:        /*
                   2257:         * Run the evaluation with a node list made of a single item
                   2258:         * in the nodeset.
                   2259:         */
                   2260:        ctxt->context->node = oldset->nodeTab[i];
                   2261:        tmp = xmlXPathNewNodeSet(ctxt->context->node);
                   2262:        valuePush(ctxt, tmp);
                   2263: 
                   2264:        xmlXPathEvalExpr(ctxt);
                   2265:        CHECK_ERROR;
                   2266: 
                   2267:        /*
                   2268:         * The result of the evaluation need to be tested to
                   2269:         * decided whether the filter succeeded or not
                   2270:         */
                   2271:        res = valuePop(ctxt);
                   2272:        range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
                   2273:        if (range != NULL) {
                   2274:            xmlXPtrLocationSetAdd(newset, range);
                   2275:        }
                   2276: 
                   2277:        /*
                   2278:         * Cleanup
                   2279:         */
                   2280:        if (res != NULL)
                   2281:            xmlXPathFreeObject(res);
                   2282:        if (ctxt->value == tmp) {
                   2283:            res = valuePop(ctxt);
                   2284:            xmlXPathFreeObject(res);
                   2285:        }
                   2286:        
                   2287:        ctxt->context->node = NULL;
                   2288:     }
                   2289: 
                   2290:     /*
                   2291:      * The result is used as the new evaluation set.
                   2292:      */
                   2293:     xmlXPathFreeObject(obj);
                   2294:     ctxt->context->node = NULL;
                   2295:     ctxt->context->contextSize = -1;
                   2296:     ctxt->context->proximityPosition = -1;
                   2297:     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   2298: }
                   2299: 
                   2300: /**
                   2301:  * xmlXPtrAdvanceNode:
                   2302:  * @cur:  the node
                   2303:  * @level: incremented/decremented to show level in tree
                   2304:  *
                   2305:  * Advance to the next element or text node in document order
                   2306:  * TODO: add a stack for entering/exiting entities 
                   2307:  *
                   2308:  * Returns -1 in case of failure, 0 otherwise
                   2309:  */
                   2310: xmlNodePtr
                   2311: xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
                   2312: next:
                   2313:     if (cur == NULL)
                   2314:        return(NULL);
                   2315:     if (cur->children != NULL) {
                   2316:         cur = cur->children ;
                   2317:        if (level != NULL)
                   2318:            (*level)++;
                   2319:        goto found;
                   2320:     }
                   2321: skip:          /* This label should only be needed if something is wrong! */
                   2322:     if (cur->next != NULL) {
                   2323:        cur = cur->next;
                   2324:        goto found;
                   2325:     }
                   2326:     do {
                   2327:         cur = cur->parent;
                   2328:        if (level != NULL)
                   2329:            (*level)--;
                   2330:         if (cur == NULL) return(NULL);
                   2331:         if (cur->next != NULL) {
                   2332:            cur = cur->next;
                   2333:            goto found;
                   2334:        }
                   2335:     } while (cur != NULL);
                   2336: 
                   2337: found:
                   2338:     if ((cur->type != XML_ELEMENT_NODE) &&
                   2339:        (cur->type != XML_TEXT_NODE) &&
                   2340:        (cur->type != XML_DOCUMENT_NODE) &&
                   2341:        (cur->type != XML_HTML_DOCUMENT_NODE) &&
                   2342:        (cur->type != XML_CDATA_SECTION_NODE)) {
                   2343:            if (cur->type == XML_ENTITY_REF_NODE) {     /* Shouldn't happen */
                   2344:                TODO
                   2345:                goto skip;
                   2346:            }
                   2347:            goto next;
                   2348:        }
                   2349:     return(cur);
                   2350: }
                   2351: 
                   2352: /**
                   2353:  * xmlXPtrAdvanceChar:
                   2354:  * @node:  the node
                   2355:  * @indx:  the indx
                   2356:  * @bytes:  the number of bytes
                   2357:  *
                   2358:  * Advance a point of the associated number of bytes (not UTF8 chars)
                   2359:  *
                   2360:  * Returns -1 in case of failure, 0 otherwise
                   2361:  */
                   2362: static int
                   2363: xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
                   2364:     xmlNodePtr cur;
                   2365:     int pos;
                   2366:     int len;
                   2367: 
                   2368:     if ((node == NULL) || (indx == NULL))
                   2369:        return(-1);
                   2370:     cur = *node;
                   2371:     if (cur == NULL)
                   2372:        return(-1);
                   2373:     pos = *indx;
                   2374: 
                   2375:     while (bytes >= 0) {
                   2376:        /*
                   2377:         * First position to the beginning of the first text node
                   2378:         * corresponding to this point
                   2379:         */
                   2380:        while ((cur != NULL) &&
                   2381:               ((cur->type == XML_ELEMENT_NODE) ||
                   2382:                (cur->type == XML_DOCUMENT_NODE) ||
                   2383:                (cur->type == XML_HTML_DOCUMENT_NODE))) {
                   2384:            if (pos > 0) {
                   2385:                cur = xmlXPtrGetNthChild(cur, pos);
                   2386:                pos = 0;
                   2387:            } else {
                   2388:                cur = xmlXPtrAdvanceNode(cur, NULL);
                   2389:                pos = 0;
                   2390:            }
                   2391:        }
                   2392: 
                   2393:        if (cur == NULL) {
                   2394:            *node = NULL;
                   2395:            *indx = 0;
                   2396:            return(-1);
                   2397:        }
                   2398: 
                   2399:        /*
                   2400:         * if there is no move needed return the current value.
                   2401:         */
                   2402:        if (pos == 0) pos = 1;
                   2403:        if (bytes == 0) {
                   2404:            *node = cur;
                   2405:            *indx = pos;
                   2406:            return(0);
                   2407:        }
                   2408:        /*
                   2409:         * We should have a text (or cdata) node ... 
                   2410:         */
                   2411:        len = 0;
                   2412:        if ((cur->type != XML_ELEMENT_NODE) &&
                   2413:             (cur->content != NULL)) {
                   2414:            len = xmlStrlen(cur->content);
                   2415:        }
                   2416:        if (pos > len) {
                   2417:            /* Strange, the indx in the text node is greater than it's len */
                   2418:            STRANGE
                   2419:            pos = len;
                   2420:        }
                   2421:        if (pos + bytes >= len) {
                   2422:            bytes -= (len - pos);
                   2423:            cur = xmlXPtrAdvanceNode(cur, NULL);
                   2424:            pos = 0;
                   2425:        } else if (pos + bytes < len) {
                   2426:            pos += bytes;
                   2427:            *node = cur;
                   2428:            *indx = pos;
                   2429:            return(0);
                   2430:        }
                   2431:     }
                   2432:     return(-1);
                   2433: }
                   2434: 
                   2435: /**
                   2436:  * xmlXPtrMatchString:
                   2437:  * @string:  the string to search
                   2438:  * @start:  the start textnode
                   2439:  * @startindex:  the start index
                   2440:  * @end:  the end textnode IN/OUT
                   2441:  * @endindex:  the end index IN/OUT
                   2442:  *
                   2443:  * Check whether the document contains @string at the position
                   2444:  * (@start, @startindex) and limited by the (@end, @endindex) point
                   2445:  *
                   2446:  * Returns -1 in case of failure, 0 if not found, 1 if found in which case
                   2447:  *            (@start, @startindex) will indicate the position of the beginning
                   2448:  *            of the range and (@end, @endindex) will indicate the end
                   2449:  *            of the range
                   2450:  */
                   2451: static int
                   2452: xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
                   2453:                    xmlNodePtr *end, int *endindex) {
                   2454:     xmlNodePtr cur;
                   2455:     int pos; /* 0 based */
                   2456:     int len; /* in bytes */
                   2457:     int stringlen; /* in bytes */
                   2458:     int match;
                   2459: 
                   2460:     if (string == NULL)
                   2461:        return(-1);
                   2462:     if (start == NULL)
                   2463:        return(-1);
                   2464:     if ((end == NULL) || (endindex == NULL))
                   2465:        return(-1);
                   2466:     cur = start;
                   2467:     if (cur == NULL)
                   2468:        return(-1);
                   2469:     pos = startindex - 1;
                   2470:     stringlen = xmlStrlen(string);
                   2471: 
                   2472:     while (stringlen > 0) {
                   2473:        if ((cur == *end) && (pos + stringlen > *endindex))
                   2474:            return(0);
                   2475: 
                   2476:        if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
                   2477:            len = xmlStrlen(cur->content);
                   2478:            if (len >= pos + stringlen) {
                   2479:                match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
                   2480:                if (match) {
                   2481: #ifdef DEBUG_RANGES
                   2482:                    xmlGenericError(xmlGenericErrorContext,
                   2483:                            "found range %d bytes at index %d of ->",
                   2484:                            stringlen, pos + 1);
                   2485:                    xmlDebugDumpString(stdout, cur->content);
                   2486:                    xmlGenericError(xmlGenericErrorContext, "\n");
                   2487: #endif
                   2488:                    *end = cur;
                   2489:                    *endindex = pos + stringlen;
                   2490:                    return(1);
                   2491:                } else {
                   2492:                    return(0);
                   2493:                }
                   2494:            } else {
                   2495:                 int sub = len - pos;
                   2496:                match = (!xmlStrncmp(&cur->content[pos], string, sub));
                   2497:                if (match) {
                   2498: #ifdef DEBUG_RANGES
                   2499:                    xmlGenericError(xmlGenericErrorContext,
                   2500:                            "found subrange %d bytes at index %d of ->",
                   2501:                            sub, pos + 1);
                   2502:                    xmlDebugDumpString(stdout, cur->content);
                   2503:                    xmlGenericError(xmlGenericErrorContext, "\n");
                   2504: #endif
                   2505:                     string = &string[sub];
                   2506:                    stringlen -= sub;
                   2507:                } else {
                   2508:                    return(0);
                   2509:                }
                   2510:            }
                   2511:        }
                   2512:        cur = xmlXPtrAdvanceNode(cur, NULL);
                   2513:        if (cur == NULL)
                   2514:            return(0);
                   2515:        pos = 0;
                   2516:     }
                   2517:     return(1);
                   2518: }
                   2519: 
                   2520: /**
                   2521:  * xmlXPtrSearchString:
                   2522:  * @string:  the string to search
                   2523:  * @start:  the start textnode IN/OUT
                   2524:  * @startindex:  the start index IN/OUT
                   2525:  * @end:  the end textnode
                   2526:  * @endindex:  the end index
                   2527:  *
                   2528:  * Search the next occurrence of @string within the document content
                   2529:  * until the (@end, @endindex) point is reached
                   2530:  *
                   2531:  * Returns -1 in case of failure, 0 if not found, 1 if found in which case
                   2532:  *            (@start, @startindex) will indicate the position of the beginning
                   2533:  *            of the range and (@end, @endindex) will indicate the end
                   2534:  *            of the range
                   2535:  */
                   2536: static int
                   2537: xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
                   2538:                    xmlNodePtr *end, int *endindex) {
                   2539:     xmlNodePtr cur;
                   2540:     const xmlChar *str;
                   2541:     int pos; /* 0 based */
                   2542:     int len; /* in bytes */
                   2543:     xmlChar first;
                   2544: 
                   2545:     if (string == NULL)
                   2546:        return(-1);
                   2547:     if ((start == NULL) || (startindex == NULL))
                   2548:        return(-1);
                   2549:     if ((end == NULL) || (endindex == NULL))
                   2550:        return(-1);
                   2551:     cur = *start;
                   2552:     if (cur == NULL)
                   2553:        return(-1);
                   2554:     pos = *startindex - 1;
                   2555:     first = string[0];
                   2556: 
                   2557:     while (cur != NULL) {
                   2558:        if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
                   2559:            len = xmlStrlen(cur->content);
                   2560:            while (pos <= len) {
                   2561:                if (first != 0) {
                   2562:                    str = xmlStrchr(&cur->content[pos], first);
                   2563:                    if (str != NULL) {
                   2564:                        pos = (str - (xmlChar *)(cur->content));
                   2565: #ifdef DEBUG_RANGES
                   2566:                        xmlGenericError(xmlGenericErrorContext,
                   2567:                                "found '%c' at index %d of ->",
                   2568:                                first, pos + 1);
                   2569:                        xmlDebugDumpString(stdout, cur->content);
                   2570:                        xmlGenericError(xmlGenericErrorContext, "\n");
                   2571: #endif
                   2572:                        if (xmlXPtrMatchString(string, cur, pos + 1,
                   2573:                                               end, endindex)) {
                   2574:                            *start = cur;
                   2575:                            *startindex = pos + 1;
                   2576:                            return(1);
                   2577:                        }
                   2578:                        pos++;
                   2579:                    } else {
                   2580:                        pos = len + 1;
                   2581:                    }
                   2582:                } else {
                   2583:                    /*
                   2584:                     * An empty string is considered to match before each
                   2585:                     * character of the string-value and after the final
                   2586:                     * character. 
                   2587:                     */
                   2588: #ifdef DEBUG_RANGES
                   2589:                    xmlGenericError(xmlGenericErrorContext,
                   2590:                            "found '' at index %d of ->",
                   2591:                            pos + 1);
                   2592:                    xmlDebugDumpString(stdout, cur->content);
                   2593:                    xmlGenericError(xmlGenericErrorContext, "\n");
                   2594: #endif
                   2595:                    *start = cur;
                   2596:                    *startindex = pos + 1;
                   2597:                    *end = cur;
                   2598:                    *endindex = pos + 1;
                   2599:                    return(1);
                   2600:                }
                   2601:            }
                   2602:        }
                   2603:        if ((cur == *end) && (pos >= *endindex))
                   2604:            return(0);
                   2605:        cur = xmlXPtrAdvanceNode(cur, NULL);
                   2606:        if (cur == NULL)
                   2607:            return(0);
                   2608:        pos = 1;
                   2609:     }
                   2610:     return(0);
                   2611: }
                   2612: 
                   2613: /**
                   2614:  * xmlXPtrGetLastChar:
                   2615:  * @node:  the node
                   2616:  * @index:  the index
                   2617:  *
                   2618:  * Computes the point coordinates of the last char of this point
                   2619:  *
                   2620:  * Returns -1 in case of failure, 0 otherwise
                   2621:  */
                   2622: static int
                   2623: xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) {
                   2624:     xmlNodePtr cur;
                   2625:     int pos, len = 0;
                   2626: 
                   2627:     if ((node == NULL) || (indx == NULL))
                   2628:        return(-1);
                   2629:     cur = *node;
                   2630:     pos = *indx;
                   2631: 
                   2632:     if (cur == NULL)
                   2633:        return(-1);
                   2634: 
                   2635:     if ((cur->type == XML_ELEMENT_NODE) ||
                   2636:        (cur->type == XML_DOCUMENT_NODE) ||
                   2637:        (cur->type == XML_HTML_DOCUMENT_NODE)) {
                   2638:        if (pos > 0) {
                   2639:            cur = xmlXPtrGetNthChild(cur, pos);
                   2640:        }
                   2641:     }
                   2642:     while (cur != NULL) {
                   2643:        if (cur->last != NULL)
                   2644:            cur = cur->last;
                   2645:        else if ((cur->type != XML_ELEMENT_NODE) &&
                   2646:                 (cur->content != NULL)) {
                   2647:            len = xmlStrlen(cur->content);
                   2648:            break;
                   2649:        } else {
                   2650:            return(-1);
                   2651:        }
                   2652:     }
                   2653:     if (cur == NULL)
                   2654:        return(-1);
                   2655:     *node = cur;
                   2656:     *indx = len;
                   2657:     return(0);
                   2658: }
                   2659: 
                   2660: /**
                   2661:  * xmlXPtrGetStartPoint:
                   2662:  * @obj:  an range
                   2663:  * @node:  the resulting node
                   2664:  * @indx:  the resulting index
                   2665:  *
                   2666:  * read the object and return the start point coordinates.
                   2667:  *
                   2668:  * Returns -1 in case of failure, 0 otherwise
                   2669:  */
                   2670: static int
                   2671: xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
                   2672:     if ((obj == NULL) || (node == NULL) || (indx == NULL))
                   2673:        return(-1);
                   2674: 
                   2675:     switch (obj->type) {
                   2676:         case XPATH_POINT:
                   2677:            *node = obj->user;
                   2678:            if (obj->index <= 0)
                   2679:                *indx = 0;
                   2680:            else
                   2681:                *indx = obj->index;
                   2682:            return(0);
                   2683:         case XPATH_RANGE:
                   2684:            *node = obj->user;
                   2685:            if (obj->index <= 0)
                   2686:                *indx = 0;
                   2687:            else
                   2688:                *indx = obj->index;
                   2689:            return(0);
                   2690:        default:
                   2691:            break;
                   2692:     }
                   2693:     return(-1);
                   2694: }
                   2695: 
                   2696: /**
                   2697:  * xmlXPtrGetEndPoint:
                   2698:  * @obj:  an range
                   2699:  * @node:  the resulting node
                   2700:  * @indx:  the resulting indx
                   2701:  *
                   2702:  * read the object and return the end point coordinates.
                   2703:  *
                   2704:  * Returns -1 in case of failure, 0 otherwise
                   2705:  */
                   2706: static int
                   2707: xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
                   2708:     if ((obj == NULL) || (node == NULL) || (indx == NULL))
                   2709:        return(-1);
                   2710: 
                   2711:     switch (obj->type) {
                   2712:         case XPATH_POINT:
                   2713:            *node = obj->user;
                   2714:            if (obj->index <= 0)
                   2715:                *indx = 0;
                   2716:            else
                   2717:                *indx = obj->index;
                   2718:            return(0);
                   2719:         case XPATH_RANGE:
                   2720:            *node = obj->user;
                   2721:            if (obj->index <= 0)
                   2722:                *indx = 0;
                   2723:            else
                   2724:                *indx = obj->index;
                   2725:            return(0);
                   2726:        default:
                   2727:            break;
                   2728:     }
                   2729:     return(-1);
                   2730: }
                   2731: 
                   2732: /**
                   2733:  * xmlXPtrStringRangeFunction:
                   2734:  * @ctxt:  the XPointer Parser context
                   2735:  * @nargs:  the number of args
                   2736:  *
                   2737:  * Function implementing the string-range() function
                   2738:  * range as described in 5.4.2 
                   2739:  *
                   2740:  * ------------------------------
                   2741:  * [Definition: For each location in the location-set argument,
                   2742:  * string-range returns a set of string ranges, a set of substrings in a
                   2743:  * string. Specifically, the string-value of the location is searched for
                   2744:  * substrings that match the string argument, and the resulting location-set
                   2745:  * will contain a range location for each non-overlapping match.]
                   2746:  * An empty string is considered to match before each character of the
                   2747:  * string-value and after the final character. Whitespace in a string
                   2748:  * is matched literally, with no normalization except that provided by
                   2749:  * XML for line ends. The third argument gives the position of the first
                   2750:  * character to be in the resulting range, relative to the start of the
                   2751:  * match. The default value is 1, which makes the range start immediately
                   2752:  * before the first character of the matched string. The fourth argument
                   2753:  * gives the number of characters in the range; the default is that the
                   2754:  * range extends to the end of the matched string.
                   2755:  *
                   2756:  * Element boundaries, as well as entire embedded nodes such as processing
                   2757:  * instructions and comments, are ignored as defined in [XPath].
                   2758:  *
                   2759:  * If the string in the second argument is not found in the string-value
                   2760:  * of the location, or if a value in the third or fourth argument indicates
                   2761:  * a string that is beyond the beginning or end of the document, the
                   2762:  * expression fails.
                   2763:  *
                   2764:  * The points of the range-locations in the returned location-set will
                   2765:  * all be character points.
                   2766:  * ------------------------------
                   2767:  */
                   2768: static void
                   2769: xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
                   2770:     int i, startindex, endindex = 0, fendindex;
                   2771:     xmlNodePtr start, end = 0, fend;
                   2772:     xmlXPathObjectPtr set;
                   2773:     xmlLocationSetPtr oldset;
                   2774:     xmlLocationSetPtr newset;
                   2775:     xmlXPathObjectPtr string;
                   2776:     xmlXPathObjectPtr position = NULL;
                   2777:     xmlXPathObjectPtr number = NULL;
                   2778:     int found, pos = 0, num = 0;
                   2779: 
                   2780:     /*
                   2781:      * Grab the arguments
                   2782:      */
                   2783:     if ((nargs < 2) || (nargs > 4))
                   2784:        XP_ERROR(XPATH_INVALID_ARITY);
                   2785: 
                   2786:     if (nargs >= 4) {
                   2787:        CHECK_TYPE(XPATH_NUMBER);
                   2788:        number = valuePop(ctxt);
                   2789:        if (number != NULL)
                   2790:            num = (int) number->floatval;
                   2791:     }
                   2792:     if (nargs >= 3) {
                   2793:        CHECK_TYPE(XPATH_NUMBER);
                   2794:        position = valuePop(ctxt);
                   2795:        if (position != NULL)
                   2796:            pos = (int) position->floatval;
                   2797:     }
                   2798:     CHECK_TYPE(XPATH_STRING);
                   2799:     string = valuePop(ctxt);
                   2800:     if ((ctxt->value == NULL) ||
                   2801:        ((ctxt->value->type != XPATH_LOCATIONSET) &&
                   2802:         (ctxt->value->type != XPATH_NODESET)))
                   2803:         XP_ERROR(XPATH_INVALID_TYPE)
                   2804: 
                   2805:     set = valuePop(ctxt);
                   2806:     newset = xmlXPtrLocationSetCreate(NULL);
                   2807:     if (set->nodesetval == NULL) {
                   2808:         goto error;
                   2809:     }
                   2810:     if (set->type == XPATH_NODESET) {
                   2811:        xmlXPathObjectPtr tmp;
                   2812: 
                   2813:        /*
                   2814:         * First convert to a location set
                   2815:         */
                   2816:        tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
                   2817:        xmlXPathFreeObject(set);
                   2818:        set = tmp;
                   2819:     }
                   2820:     oldset = (xmlLocationSetPtr) set->user;
                   2821: 
                   2822:     /*
                   2823:      * The loop is to search for each element in the location set
                   2824:      * the list of location set corresponding to that search
                   2825:      */
                   2826:     for (i = 0;i < oldset->locNr;i++) {
                   2827: #ifdef DEBUG_RANGES
                   2828:        xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0);
                   2829: #endif
                   2830: 
                   2831:        xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
                   2832:        xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
                   2833:        xmlXPtrAdvanceChar(&start, &startindex, 0);
                   2834:        xmlXPtrGetLastChar(&end, &endindex);
                   2835: 
                   2836: #ifdef DEBUG_RANGES
                   2837:        xmlGenericError(xmlGenericErrorContext,
                   2838:                "from index %d of ->", startindex);
                   2839:        xmlDebugDumpString(stdout, start->content);
                   2840:        xmlGenericError(xmlGenericErrorContext, "\n");
                   2841:        xmlGenericError(xmlGenericErrorContext,
                   2842:                "to index %d of ->", endindex);
                   2843:        xmlDebugDumpString(stdout, end->content);
                   2844:        xmlGenericError(xmlGenericErrorContext, "\n");
                   2845: #endif
                   2846:        do {
                   2847:             fend = end;
                   2848:             fendindex = endindex;
                   2849:            found = xmlXPtrSearchString(string->stringval, &start, &startindex,
                   2850:                                        &fend, &fendindex);
                   2851:            if (found == 1) {
                   2852:                if (position == NULL) {
                   2853:                    xmlXPtrLocationSetAdd(newset,
                   2854:                         xmlXPtrNewRange(start, startindex, fend, fendindex));
                   2855:                } else if (xmlXPtrAdvanceChar(&start, &startindex,
                   2856:                                              pos - 1) == 0) {
                   2857:                    if ((number != NULL) && (num > 0)) {
                   2858:                        int rindx;
                   2859:                        xmlNodePtr rend;
                   2860:                        rend = start;
                   2861:                        rindx = startindex - 1;
                   2862:                        if (xmlXPtrAdvanceChar(&rend, &rindx,
                   2863:                                               num) == 0) {
                   2864:                            xmlXPtrLocationSetAdd(newset,
                   2865:                                        xmlXPtrNewRange(start, startindex,
                   2866:                                                        rend, rindx));
                   2867:                        }
                   2868:                    } else if ((number != NULL) && (num <= 0)) {
                   2869:                        xmlXPtrLocationSetAdd(newset,
                   2870:                                    xmlXPtrNewRange(start, startindex,
                   2871:                                                    start, startindex));
                   2872:                    } else {
                   2873:                        xmlXPtrLocationSetAdd(newset,
                   2874:                                    xmlXPtrNewRange(start, startindex,
                   2875:                                                    fend, fendindex));
                   2876:                    }
                   2877:                }
                   2878:                start = fend;
                   2879:                startindex = fendindex;
                   2880:                if (string->stringval[0] == 0)
                   2881:                    startindex++;
                   2882:            }
                   2883:        } while (found == 1);
                   2884:     }
                   2885: 
                   2886:     /*
                   2887:      * Save the new value and cleanup
                   2888:      */
                   2889: error:
                   2890:     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   2891:     xmlXPathFreeObject(set);
                   2892:     xmlXPathFreeObject(string);
                   2893:     if (position) xmlXPathFreeObject(position);
                   2894:     if (number) xmlXPathFreeObject(number);
                   2895: }
                   2896: 
                   2897: /**
                   2898:  * xmlXPtrEvalRangePredicate:
                   2899:  * @ctxt:  the XPointer Parser context
                   2900:  *
                   2901:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
                   2902:  *  [9]   PredicateExpr ::=   Expr 
                   2903:  *
                   2904:  * Evaluate a predicate as in xmlXPathEvalPredicate() but for
                   2905:  * a Location Set instead of a node set
                   2906:  */
                   2907: void
                   2908: xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
                   2909:     const xmlChar *cur;
                   2910:     xmlXPathObjectPtr res;
                   2911:     xmlXPathObjectPtr obj, tmp;
                   2912:     xmlLocationSetPtr newset = NULL;
                   2913:     xmlLocationSetPtr oldset;
                   2914:     int i;
                   2915: 
                   2916:     if (ctxt == NULL) return;
                   2917: 
                   2918:     SKIP_BLANKS;
                   2919:     if (CUR != '[') {
                   2920:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
                   2921:     }
                   2922:     NEXT;
                   2923:     SKIP_BLANKS;
                   2924: 
                   2925:     /*
                   2926:      * Extract the old set, and then evaluate the result of the
                   2927:      * expression for all the element in the set. use it to grow
                   2928:      * up a new set.
                   2929:      */
                   2930:     CHECK_TYPE(XPATH_LOCATIONSET);
                   2931:     obj = valuePop(ctxt);
                   2932:     oldset = obj->user;
                   2933:     ctxt->context->node = NULL;
                   2934: 
                   2935:     if ((oldset == NULL) || (oldset->locNr == 0)) {
                   2936:        ctxt->context->contextSize = 0;
                   2937:        ctxt->context->proximityPosition = 0;
                   2938:        xmlXPathEvalExpr(ctxt);
                   2939:        res = valuePop(ctxt);
                   2940:        if (res != NULL)
                   2941:            xmlXPathFreeObject(res);
                   2942:        valuePush(ctxt, obj);
                   2943:        CHECK_ERROR;
                   2944:     } else {
                   2945:        /*
                   2946:         * Save the expression pointer since we will have to evaluate
                   2947:         * it multiple times. Initialize the new set.
                   2948:         */
                   2949:         cur = ctxt->cur;
                   2950:        newset = xmlXPtrLocationSetCreate(NULL);
                   2951:        
                   2952:         for (i = 0; i < oldset->locNr; i++) {
                   2953:            ctxt->cur = cur;
                   2954: 
                   2955:            /*
                   2956:             * Run the evaluation with a node list made of a single item
                   2957:             * in the nodeset.
                   2958:             */
                   2959:            ctxt->context->node = oldset->locTab[i]->user;
                   2960:            tmp = xmlXPathNewNodeSet(ctxt->context->node);
                   2961:            valuePush(ctxt, tmp);
                   2962:            ctxt->context->contextSize = oldset->locNr;
                   2963:            ctxt->context->proximityPosition = i + 1;
                   2964: 
                   2965:            xmlXPathEvalExpr(ctxt);
                   2966:            CHECK_ERROR;
                   2967: 
                   2968:            /*
                   2969:             * The result of the evaluation need to be tested to
                   2970:             * decided whether the filter succeeded or not
                   2971:             */
                   2972:            res = valuePop(ctxt);
                   2973:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
                   2974:                xmlXPtrLocationSetAdd(newset,
                   2975:                        xmlXPathObjectCopy(oldset->locTab[i]));
                   2976:            }
                   2977: 
                   2978:            /*
                   2979:             * Cleanup
                   2980:             */
                   2981:            if (res != NULL)
                   2982:                xmlXPathFreeObject(res);
                   2983:            if (ctxt->value == tmp) {
                   2984:                res = valuePop(ctxt);
                   2985:                xmlXPathFreeObject(res);
                   2986:            }
                   2987:            
                   2988:            ctxt->context->node = NULL;
                   2989:        }
                   2990: 
                   2991:        /*
                   2992:         * The result is used as the new evaluation set.
                   2993:         */
                   2994:        xmlXPathFreeObject(obj);
                   2995:        ctxt->context->node = NULL;
                   2996:        ctxt->context->contextSize = -1;
                   2997:        ctxt->context->proximityPosition = -1;
                   2998:        valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
                   2999:     }
                   3000:     if (CUR != ']') {
                   3001:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
                   3002:     }
                   3003: 
                   3004:     NEXT;
                   3005:     SKIP_BLANKS;
                   3006: }
                   3007: 
                   3008: #define bottom_xpointer
                   3009: #include "elfgcchack.h"
                   3010: #endif
                   3011: 

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