File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xpointer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:57 2012 UTC (12 years, 5 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_7_8, HEAD
libxml2

    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>