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