| /* | 
 |  * xpointer.c : Code to handle XML Pointer | 
 |  * | 
 |  * World Wide Web Consortium Working Draft 03-March-1998  | 
 |  * http://www.w3.org/TR/2000/CR-xptr-20000607 | 
 |  * | 
 |  * See Copyright for the status of this software. | 
 |  * | 
 |  * daniel@veillard.com | 
 |  */ | 
 |  | 
 | #include "libxml.h" | 
 |  | 
 | /* | 
 |  * TODO: better handling of error cases, the full expression should | 
 |  *       be parsed beforehand instead of a progressive evaluation | 
 |  * TODO: Access into entities references are not supported now ... | 
 |  *       need a start to be able to pop out of entities refs since | 
 |  *       parent is the endity declaration, not the ref. | 
 |  */ | 
 |  | 
 | #include <string.h> | 
 | #include <libxml/xpointer.h> | 
 | #include <libxml/xmlmemory.h> | 
 | #include <libxml/parserInternals.h> | 
 | #include <libxml/uri.h> | 
 | #include <libxml/xpath.h> | 
 | #include <libxml/xpathInternals.h> | 
 | #include <libxml/xmlerror.h> | 
 | #include <libxml/globals.h> | 
 |  | 
 | #ifdef LIBXML_XPTR_ENABLED | 
 |  | 
 | /* Add support of the xmlns() xpointer scheme to initialize the namespaces */ | 
 | #define XPTR_XMLNS_SCHEME | 
 |  | 
 | /* #define DEBUG_RANGES */ | 
 | #ifdef DEBUG_RANGES | 
 | #ifdef LIBXML_DEBUG_ENABLED | 
 | #include <libxml/debugXML.h> | 
 | #endif | 
 | #endif | 
 |  | 
 | #define TODO 								\ | 
 |     xmlGenericError(xmlGenericErrorContext,				\ | 
 | 	    "Unimplemented block at %s:%d\n",				\ | 
 |             __FILE__, __LINE__); | 
 |  | 
 | #define STRANGE 							\ | 
 |     xmlGenericError(xmlGenericErrorContext,				\ | 
 | 	    "Internal error at %s:%d\n",				\ | 
 |             __FILE__, __LINE__); | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		A few helper functions for child sequences		* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur); | 
 | /** | 
 |  * xmlXPtrGetArity: | 
 |  * @cur:  the node | 
 |  * | 
 |  * Returns the number of child for an element, -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlXPtrGetArity(xmlNodePtr cur) { | 
 |     int i; | 
 |     if (cur == NULL)  | 
 | 	return(-1); | 
 |     cur = cur->children; | 
 |     for (i = 0;cur != NULL;cur = cur->next) { | 
 | 	if ((cur->type == XML_ELEMENT_NODE) || | 
 | 	    (cur->type == XML_DOCUMENT_NODE) || | 
 | 	    (cur->type == XML_HTML_DOCUMENT_NODE)) { | 
 | 	    i++; | 
 | 	} | 
 |     } | 
 |     return(i); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrGetIndex: | 
 |  * @cur:  the node | 
 |  * | 
 |  * Returns the index of the node in its parent children list, -1 | 
 |  *         in case of error | 
 |  */ | 
 | static int | 
 | xmlXPtrGetIndex(xmlNodePtr cur) { | 
 |     int i; | 
 |     if (cur == NULL)  | 
 | 	return(-1); | 
 |     for (i = 1;cur != NULL;cur = cur->prev) { | 
 | 	if ((cur->type == XML_ELEMENT_NODE) || | 
 | 	    (cur->type == XML_DOCUMENT_NODE) || | 
 | 	    (cur->type == XML_HTML_DOCUMENT_NODE)) { | 
 | 	    i++; | 
 | 	} | 
 |     } | 
 |     return(i); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrGetNthChild: | 
 |  * @cur:  the node | 
 |  * @no:  the child number | 
 |  * | 
 |  * Returns the @no'th element child of @cur or NULL | 
 |  */ | 
 | static xmlNodePtr | 
 | xmlXPtrGetNthChild(xmlNodePtr cur, int no) { | 
 |     int i; | 
 |     if (cur == NULL)  | 
 | 	return(cur); | 
 |     cur = cur->children; | 
 |     for (i = 0;i <= no;cur = cur->next) { | 
 | 	if (cur == NULL)  | 
 | 	    return(cur); | 
 | 	if ((cur->type == XML_ELEMENT_NODE) || | 
 | 	    (cur->type == XML_DOCUMENT_NODE) || | 
 | 	    (cur->type == XML_HTML_DOCUMENT_NODE)) { | 
 | 	    i++; | 
 | 	    if (i == no) | 
 | 		break; | 
 | 	} | 
 |     } | 
 |     return(cur); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		Handling of XPointer specific types			* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlXPtrCmpPoints: | 
 |  * @node1:  the first node | 
 |  * @index1:  the first index | 
 |  * @node2:  the second node | 
 |  * @index2:  the second index | 
 |  * | 
 |  * Compare two points w.r.t document order | 
 |  * | 
 |  * Returns -2 in case of error 1 if first point < second point, 0 if | 
 |  *         that's the same point, -1 otherwise | 
 |  */ | 
 | static int | 
 | xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) { | 
 |     if ((node1 == NULL) || (node2 == NULL)) | 
 | 	return(-2); | 
 |     /* | 
 |      * a couple of optimizations which will avoid computations in most cases | 
 |      */ | 
 |     if (node1 == node2) { | 
 | 	if (index1 < index2) | 
 | 	    return(1); | 
 | 	if (index1 > index2) | 
 | 	    return(-1); | 
 | 	return(0); | 
 |     } | 
 |     return(xmlXPathCmpNodes(node1, node2)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewPoint: | 
 |  * @node:  the xmlNodePtr | 
 |  * @indx:  the indx within the node | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type point | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | static xmlXPathObjectPtr | 
 | xmlXPtrNewPoint(xmlNodePtr node, int indx) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (node == NULL) | 
 | 	return(NULL); | 
 |     if (indx < 0) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewPoint: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_POINT; | 
 |     ret->user = (void *) node; | 
 |     ret->index = indx; | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrRangeCheckOrder: | 
 |  * @range:  an object range | 
 |  * | 
 |  * Make sure the points in the range are in the right order | 
 |  */ | 
 | static void | 
 | xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) { | 
 |     int tmp; | 
 |     xmlNodePtr tmp2; | 
 |     if (range == NULL) | 
 | 	return; | 
 |     if (range->type != XPATH_RANGE) | 
 | 	return; | 
 |     if (range->user2 == NULL) | 
 | 	return; | 
 |     tmp = xmlXPtrCmpPoints(range->user, range->index, | 
 | 	                     range->user2, range->index2); | 
 |     if (tmp == -1) { | 
 | 	tmp2 = range->user; | 
 | 	range->user = range->user2; | 
 | 	range->user2 = tmp2; | 
 | 	tmp = range->index; | 
 | 	range->index = range->index2; | 
 | 	range->index2 = tmp; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrRangesEqual: | 
 |  * @range1:  the first range | 
 |  * @range2:  the second range | 
 |  * | 
 |  * Compare two ranges | 
 |  * | 
 |  * Returns 1 if equal, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) { | 
 |     if (range1 == range2) | 
 | 	return(1); | 
 |     if ((range1 == NULL) || (range2 == NULL)) | 
 | 	return(0); | 
 |     if (range1->type != range2->type) | 
 | 	return(0); | 
 |     if (range1->type != XPATH_RANGE) | 
 | 	return(0); | 
 |     if (range1->user != range2->user) | 
 | 	return(0); | 
 |     if (range1->index != range2->index) | 
 | 	return(0); | 
 |     if (range1->user2 != range2->user2) | 
 | 	return(0); | 
 |     if (range1->index2 != range2->index2) | 
 | 	return(0); | 
 |     return(1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewRange: | 
 |  * @start:  the starting node | 
 |  * @startindex:  the start index | 
 |  * @end:  the ending point | 
 |  * @endindex:  the ending index | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewRange(xmlNodePtr start, int startindex, | 
 | 	        xmlNodePtr end, int endindex) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     if (end == NULL) | 
 | 	return(NULL); | 
 |     if (startindex < 0) | 
 | 	return(NULL); | 
 |     if (endindex < 0) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewRange: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start; | 
 |     ret->index = startindex; | 
 |     ret->user2 = end; | 
 |     ret->index2 = endindex; | 
 |     xmlXPtrRangeCheckOrder(ret); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewRangePoints: | 
 |  * @start:  the starting point | 
 |  * @end:  the ending point | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range using 2 Points | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     if (end == NULL) | 
 | 	return(NULL); | 
 |     if (start->type != XPATH_POINT) | 
 | 	return(NULL); | 
 |     if (end->type != XPATH_POINT) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewRangePoints: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start->user; | 
 |     ret->index = start->index; | 
 |     ret->user2 = end->user; | 
 |     ret->index2 = end->index; | 
 |     xmlXPtrRangeCheckOrder(ret); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewRangePointNode: | 
 |  * @start:  the starting point | 
 |  * @end:  the ending node | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range from a point to a node | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     if (end == NULL) | 
 | 	return(NULL); | 
 |     if (start->type != XPATH_POINT) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewRangePointNode: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start->user; | 
 |     ret->index = start->index; | 
 |     ret->user2 = end; | 
 |     ret->index2 = -1; | 
 |     xmlXPtrRangeCheckOrder(ret); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewRangeNodePoint: | 
 |  * @start:  the starting node | 
 |  * @end:  the ending point | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range from a node to a point | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     if (end == NULL) | 
 | 	return(NULL); | 
 |     if (start->type != XPATH_POINT) | 
 | 	return(NULL); | 
 |     if (end->type != XPATH_POINT) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewRangeNodePoint: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start; | 
 |     ret->index = -1; | 
 |     ret->user2 = end->user; | 
 |     ret->index2 = end->index; | 
 |     xmlXPtrRangeCheckOrder(ret); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewRangeNodes: | 
 |  * @start:  the starting node | 
 |  * @end:  the ending node | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range using 2 nodes | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     if (end == NULL) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewRangeNodes: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start; | 
 |     ret->index = -1; | 
 |     ret->user2 = end; | 
 |     ret->index2 = -1; | 
 |     xmlXPtrRangeCheckOrder(ret); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewCollapsedRange: | 
 |  * @start:  the starting and ending node | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range using a single nodes | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewCollapsedRange(xmlNodePtr start) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewCollapsedRange: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start; | 
 |     ret->index = -1; | 
 |     ret->user2 = NULL; | 
 |     ret->index2 = -1; | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewRangeNodeObject: | 
 |  * @start:  the starting node | 
 |  * @end:  the ending object | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type range from a not to an object | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     if (end == NULL) | 
 | 	return(NULL); | 
 |     switch (end->type) { | 
 | 	case XPATH_POINT: | 
 | 	    break; | 
 | 	case XPATH_NODESET: | 
 | 	    /* | 
 | 	     * Empty set ...  | 
 | 	     */ | 
 | 	    if (end->nodesetval->nodeNr <= 0) | 
 | 		return(NULL); | 
 | 	    break; | 
 | 	default: | 
 | 	    TODO | 
 | 	    return(NULL); | 
 |     } | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewRangeNodeObject: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_RANGE; | 
 |     ret->user = start; | 
 |     ret->index = -1; | 
 |     switch (end->type) { | 
 | 	case XPATH_POINT: | 
 | 	    ret->user2 = end->user; | 
 | 	    ret->index2 = end->index; | 
 | 	case XPATH_NODESET: { | 
 | 	    ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1]; | 
 | 	    ret->index2 = -1; | 
 | 	    break; | 
 | 	} | 
 | 	default: | 
 | 	    STRANGE | 
 | 	    return(NULL); | 
 |     } | 
 |     xmlXPtrRangeCheckOrder(ret); | 
 |     return(ret); | 
 | } | 
 |  | 
 | #define XML_RANGESET_DEFAULT	10 | 
 |  | 
 | /** | 
 |  * xmlXPtrLocationSetCreate: | 
 |  * @val:  an initial xmlXPathObjectPtr, or NULL | 
 |  * | 
 |  * Create a new xmlLocationSetPtr of type double and of value @val | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlLocationSetPtr | 
 | xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { | 
 |     xmlLocationSetPtr ret; | 
 |  | 
 |     ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrLocationSetCreate: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlLocationSet)); | 
 |     if (val != NULL) { | 
 |         ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * | 
 | 					     sizeof(xmlXPathObjectPtr)); | 
 | 	if (ret->locTab == NULL) { | 
 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 		    "xmlXPtrLocationSetCreate: out of memory\n"); | 
 | 	    return(NULL); | 
 | 	} | 
 | 	memset(ret->locTab, 0 , | 
 | 	       XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); | 
 |         ret->locMax = XML_RANGESET_DEFAULT; | 
 | 	ret->locTab[ret->locNr++] = val; | 
 |     } | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrLocationSetAdd: | 
 |  * @cur:  the initial range set | 
 |  * @val:  a new xmlXPathObjectPtr | 
 |  * | 
 |  * add a new xmlXPathObjectPtr to an existing LocationSet | 
 |  * If the location already exist in the set @val is freed. | 
 |  */ | 
 | void | 
 | xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { | 
 |     int i; | 
 |  | 
 |     if (val == NULL) return; | 
 |  | 
 |     /* | 
 |      * check against doublons | 
 |      */ | 
 |     for (i = 0;i < cur->locNr;i++) { | 
 | 	if (xmlXPtrRangesEqual(cur->locTab[i], val)) { | 
 | 	    xmlXPathFreeObject(val); | 
 | 	    return; | 
 | 	} | 
 |     } | 
 |  | 
 |     /* | 
 |      * grow the locTab if needed | 
 |      */ | 
 |     if (cur->locMax == 0) { | 
 |         cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * | 
 | 					     sizeof(xmlXPathObjectPtr)); | 
 | 	if (cur->locTab == NULL) { | 
 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 		    "xmlXPtrLocationSetAdd: out of memory\n"); | 
 | 	    return; | 
 | 	} | 
 | 	memset(cur->locTab, 0 , | 
 | 	       XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); | 
 |         cur->locMax = XML_RANGESET_DEFAULT; | 
 |     } else if (cur->locNr == cur->locMax) { | 
 |         xmlXPathObjectPtr *temp; | 
 |  | 
 |         cur->locMax *= 2; | 
 | 	temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax * | 
 | 				      sizeof(xmlXPathObjectPtr)); | 
 | 	if (temp == NULL) { | 
 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 		    "xmlXPtrLocationSetAdd: out of memory\n"); | 
 | 	    return; | 
 | 	} | 
 | 	cur->locTab = temp; | 
 |     } | 
 |     cur->locTab[cur->locNr++] = val; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrLocationSetMerge: | 
 |  * @val1:  the first LocationSet | 
 |  * @val2:  the second LocationSet | 
 |  * | 
 |  * Merges two rangesets, all ranges from @val2 are added to @val1 | 
 |  * | 
 |  * Returns val1 once extended or NULL in case of error. | 
 |  */ | 
 | xmlLocationSetPtr | 
 | xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) { | 
 |     int i; | 
 |  | 
 |     if (val1 == NULL) return(NULL); | 
 |     if (val2 == NULL) return(val1); | 
 |  | 
 |     /* | 
 |      * !!!!! this can be optimized a lot, knowing that both | 
 |      *       val1 and val2 already have unicity of their values. | 
 |      */ | 
 |  | 
 |     for (i = 0;i < val2->locNr;i++) | 
 |         xmlXPtrLocationSetAdd(val1, val2->locTab[i]); | 
 |  | 
 |     return(val1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrLocationSetDel: | 
 |  * @cur:  the initial range set | 
 |  * @val:  an xmlXPathObjectPtr | 
 |  * | 
 |  * Removes an xmlXPathObjectPtr from an existing LocationSet | 
 |  */ | 
 | void | 
 | xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { | 
 |     int i; | 
 |  | 
 |     if (cur == NULL) return; | 
 |     if (val == NULL) return; | 
 |  | 
 |     /* | 
 |      * check against doublons | 
 |      */ | 
 |     for (i = 0;i < cur->locNr;i++) | 
 |         if (cur->locTab[i] == val) break; | 
 |  | 
 |     if (i >= cur->locNr) { | 
 | #ifdef DEBUG | 
 |         xmlGenericError(xmlGenericErrorContext,  | 
 | 	        "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n"); | 
 | #endif | 
 |         return; | 
 |     } | 
 |     cur->locNr--; | 
 |     for (;i < cur->locNr;i++) | 
 |         cur->locTab[i] = cur->locTab[i + 1]; | 
 |     cur->locTab[cur->locNr] = NULL; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrLocationSetRemove: | 
 |  * @cur:  the initial range set | 
 |  * @val:  the index to remove | 
 |  * | 
 |  * Removes an entry from an existing LocationSet list. | 
 |  */ | 
 | void | 
 | xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) { | 
 |     if (cur == NULL) return; | 
 |     if (val >= cur->locNr) return; | 
 |     cur->locNr--; | 
 |     for (;val < cur->locNr;val++) | 
 |         cur->locTab[val] = cur->locTab[val + 1]; | 
 |     cur->locTab[cur->locNr] = NULL; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrFreeLocationSet: | 
 |  * @obj:  the xmlLocationSetPtr to free | 
 |  * | 
 |  * Free the LocationSet compound (not the actual ranges !). | 
 |  */ | 
 | void | 
 | xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) { | 
 |     int i; | 
 |  | 
 |     if (obj == NULL) return; | 
 |     if (obj->locTab != NULL) { | 
 | 	for (i = 0;i < obj->locNr; i++) { | 
 |             xmlXPathFreeObject(obj->locTab[i]); | 
 | 	} | 
 | 	xmlFree(obj->locTab); | 
 |     } | 
 |     xmlFree(obj); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewLocationSetNodes: | 
 |  * @start:  the start NodePtr value | 
 |  * @end:  the end NodePtr value or NULL | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type LocationSet and initialize | 
 |  * it with the single range made of the two nodes @start and @end | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewLocationSetNodes: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_LOCATIONSET; | 
 |     if (end == NULL) | 
 | 	ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start)); | 
 |     else | 
 | 	ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end)); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrNewLocationSetNodeSet: | 
 |  * @set:  a node set | 
 |  * | 
 |  * Create a new xmlXPathObjectPtr of type LocationSet and initialize | 
 |  * it with all the nodes from @set | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrNewLocationSetNodeSet: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_LOCATIONSET; | 
 |     if (set != NULL) { | 
 | 	int i; | 
 | 	xmlLocationSetPtr newset; | 
 |  | 
 | 	newset = xmlXPtrLocationSetCreate(NULL); | 
 | 	if (newset == NULL) | 
 | 	    return(ret); | 
 |  | 
 | 	for (i = 0;i < set->nodeNr;i++) | 
 | 	    xmlXPtrLocationSetAdd(newset, | 
 | 		        xmlXPtrNewCollapsedRange(set->nodeTab[i])); | 
 |  | 
 | 	ret->user = (void *) newset; | 
 |     } | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrWrapLocationSet: | 
 |  * @val:  the LocationSet value | 
 |  * | 
 |  * Wrap the LocationSet @val in a new xmlXPathObjectPtr | 
 |  * | 
 |  * Returns the newly created object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrWrapLocationSet(xmlLocationSetPtr val) { | 
 |     xmlXPathObjectPtr ret; | 
 |  | 
 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 |     if (ret == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrWrapLocationSet: out of memory\n"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 |     ret->type = XPATH_LOCATIONSET; | 
 |     ret->user = (void *) val; | 
 |     return(ret); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *			The parser					* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | /* | 
 |  * Macros for accessing the content. Those should be used only by the parser, | 
 |  * and not exported. | 
 |  * | 
 |  * Dirty macros, i.e. one need to make assumption on the context to use them | 
 |  * | 
 |  *   CUR_PTR return the current pointer to the xmlChar to be parsed. | 
 |  *   CUR     returns the current xmlChar value, i.e. a 8 bit value | 
 |  *           in ISO-Latin or UTF-8. | 
 |  *           This should be used internally by the parser | 
 |  *           only to compare to ASCII values otherwise it would break when | 
 |  *           running with UTF-8 encoding. | 
 |  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only | 
 |  *           to compare on ASCII based substring. | 
 |  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined | 
 |  *           strings within the parser. | 
 |  *   CURRENT Returns the current char value, with the full decoding of | 
 |  *           UTF-8 if we are using this mode. It returns an int. | 
 |  *   NEXT    Skip to the next character, this does the proper decoding | 
 |  *           in UTF-8 mode. It also pop-up unfinished entities on the fly. | 
 |  *           It returns the pointer to the current xmlChar. | 
 |  */ | 
 |  | 
 | #define CUR (*ctxt->cur) | 
 | #define SKIP(val) ctxt->cur += (val) | 
 | #define NXT(val) ctxt->cur[(val)] | 
 | #define CUR_PTR ctxt->cur | 
 |  | 
 | #define SKIP_BLANKS 							\ | 
 |     while (IS_BLANK(*(ctxt->cur))) NEXT | 
 |  | 
 | #define CURRENT (*ctxt->cur) | 
 | #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur) | 
 |  | 
 | /* | 
 |  * xmlXPtrGetChildNo: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @index:  the child number | 
 |  * | 
 |  * Move the current node of the nodeset on the stack to the | 
 |  * given child if found | 
 |  */ | 
 | static void | 
 | xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) { | 
 |     xmlNodePtr cur = NULL; | 
 |     xmlXPathObjectPtr obj; | 
 |     xmlNodeSetPtr oldset; | 
 |  | 
 |     CHECK_TYPE(XPATH_NODESET); | 
 |     obj = valuePop(ctxt); | 
 |     oldset = obj->nodesetval; | 
 |     if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) { | 
 | 	xmlXPathFreeObject(obj); | 
 | 	valuePush(ctxt, xmlXPathNewNodeSet(NULL)); | 
 | 	return; | 
 |     } | 
 |     cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx); | 
 |     if (cur == NULL) { | 
 | 	xmlXPathFreeObject(obj); | 
 | 	valuePush(ctxt, xmlXPathNewNodeSet(NULL)); | 
 | 	return; | 
 |     } | 
 |     oldset->nodeTab[0] = cur; | 
 |     valuePush(ctxt, obj); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrEvalXPtrPart: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @name:  the preparsed Scheme for the XPtrPart | 
 |  *  | 
 |  * XPtrPart ::= 'xpointer' '(' XPtrExpr ')' | 
 |  *            | Scheme '(' SchemeSpecificExpr ')' | 
 |  * | 
 |  * Scheme   ::=  NCName - 'xpointer' [VC: Non-XPointer schemes] | 
 |  * | 
 |  * SchemeSpecificExpr ::= StringWithBalancedParens | 
 |  * | 
 |  * StringWithBalancedParens ::=   | 
 |  *              [^()]* ('(' StringWithBalancedParens ')' [^()]*)* | 
 |  *              [VC: Parenthesis escaping] | 
 |  * | 
 |  * XPtrExpr ::= Expr [VC: Parenthesis escaping] | 
 |  * | 
 |  * VC: Parenthesis escaping: | 
 |  *   The end of an XPointer part is signaled by the right parenthesis ")" | 
 |  *   character that is balanced with the left parenthesis "(" character | 
 |  *   that began the part. Any unbalanced parenthesis character inside the | 
 |  *   expression, even within literals, must be escaped with a circumflex (^) | 
 |  *   character preceding it. If the expression contains any literal | 
 |  *   occurrences of the circumflex, each must be escaped with an additional | 
 |  *   circumflex (that is, ^^). If the unescaped parentheses in the expression | 
 |  *   are not balanced, a syntax error results. | 
 |  * | 
 |  * Parse and evaluate an XPtrPart. Basically it generates the unescaped | 
 |  * string and if the scheme is 'xpointer' it will call the XPath interpreter. | 
 |  *  | 
 |  * TODO: there is no new scheme registration mechanism | 
 |  */ | 
 |  | 
 | static void | 
 | xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { | 
 |     xmlChar *buffer, *cur; | 
 |     int len; | 
 |     int level; | 
 |  | 
 |     if (name == NULL) | 
 |     name = xmlXPathParseName(ctxt); | 
 |     if (name == NULL) | 
 | 	XP_ERROR(XPATH_EXPR_ERROR); | 
 |  | 
 |     if (CUR != '(') | 
 | 	XP_ERROR(XPATH_EXPR_ERROR); | 
 |     NEXT; | 
 |     level = 1; | 
 |  | 
 |     len = xmlStrlen(ctxt->cur); | 
 |     len++; | 
 |     buffer = (xmlChar *) xmlMalloc(len * sizeof (xmlChar)); | 
 |     if (buffer == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrEvalXPtrPart: out of memory\n"); | 
 | 	return; | 
 |     } | 
 |  | 
 |     cur = buffer; | 
 |     while (CUR != 0) { | 
 | 	if (CUR == ')') { | 
 | 	    level--; | 
 | 	    if (level == 0) { | 
 | 		NEXT; | 
 | 		break; | 
 | 	    } | 
 | 	    *cur++ = CUR; | 
 | 	} else if (CUR == '(') { | 
 | 	    level++; | 
 | 	    *cur++ = CUR; | 
 | 	} else if (CUR == '^') { | 
 | 	    NEXT; | 
 | 	    if ((CUR == ')') || (CUR == '(') || (CUR == '^')) { | 
 | 		*cur++ = CUR; | 
 | 	    } else { | 
 | 		*cur++ = '^'; | 
 | 		*cur++ = CUR; | 
 | 	    } | 
 | 	} else { | 
 | 	    *cur++ = CUR; | 
 | 	} | 
 | 	NEXT; | 
 |     } | 
 |     *cur = 0; | 
 |  | 
 |     if ((level != 0) && (CUR == 0)) { | 
 | 	xmlFree(buffer); | 
 | 	XP_ERROR(XPTR_SYNTAX_ERROR); | 
 |     } | 
 |  | 
 |     if (xmlStrEqual(name, (xmlChar *) "xpointer")) { | 
 | 	const xmlChar *left = CUR_PTR; | 
 |  | 
 | 	CUR_PTR = buffer; | 
 | 	xmlXPathEvalExpr(ctxt); | 
 | 	CUR_PTR=left; | 
 | #ifdef XPTR_XMLNS_SCHEME | 
 |     } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) { | 
 | 	const xmlChar *left = CUR_PTR; | 
 | 	xmlChar *prefix; | 
 | 	xmlChar *URI; | 
 | 	xmlURIPtr value; | 
 |  | 
 | 	CUR_PTR = buffer; | 
 |         prefix = xmlXPathParseNCName(ctxt); | 
 | 	if (prefix == NULL) { | 
 | 	    xmlFree(buffer); | 
 | 	    xmlFree(name); | 
 | 	    XP_ERROR(XPTR_SYNTAX_ERROR); | 
 | 	} | 
 | 	SKIP_BLANKS; | 
 | 	if (CUR != '=') { | 
 | 	    xmlFree(prefix); | 
 | 	    xmlFree(buffer); | 
 | 	    xmlFree(name); | 
 | 	    XP_ERROR(XPTR_SYNTAX_ERROR); | 
 | 	} | 
 | 	NEXT; | 
 | 	SKIP_BLANKS; | 
 | 	/* @@ check escaping in the XPointer WD */ | 
 |  | 
 | 	value = xmlParseURI((const char *)ctxt->cur); | 
 | 	if (value == NULL) { | 
 | 	    xmlFree(prefix); | 
 | 	    xmlFree(buffer); | 
 | 	    xmlFree(name); | 
 | 	    XP_ERROR(XPTR_SYNTAX_ERROR); | 
 | 	} | 
 | 	URI = xmlSaveUri(value); | 
 | 	xmlFreeURI(value); | 
 | 	if (URI == NULL) { | 
 | 	    xmlFree(prefix); | 
 | 	    xmlFree(buffer); | 
 | 	    xmlFree(name); | 
 | 	    XP_ERROR(XPATH_MEMORY_ERROR); | 
 | 	} | 
 | 	 | 
 | 	xmlXPathRegisterNs(ctxt->context, prefix, URI); | 
 | 	CUR_PTR = left; | 
 | #endif /* XPTR_XMLNS_SCHEME */ | 
 |     } else { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 | 		"unsupported scheme '%s'\n", name); | 
 |     } | 
 |     xmlFree(buffer); | 
 |     xmlFree(name); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrEvalFullXPtr: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @name:  the preparsed Scheme for the first XPtrPart | 
 |  * | 
 |  * FullXPtr ::= XPtrPart (S? XPtrPart)* | 
 |  * | 
 |  * As the specs says: | 
 |  * ----------- | 
 |  * When multiple XPtrParts are provided, they must be evaluated in | 
 |  * left-to-right order. If evaluation of one part fails, the nexti | 
 |  * is evaluated. The following conditions cause XPointer part failure: | 
 |  * | 
 |  * - An unknown scheme | 
 |  * - A scheme that does not locate any sub-resource present in the resource | 
 |  * - A scheme that is not applicable to the media type of the resource | 
 |  * | 
 |  * The XPointer application must consume a failed XPointer part and | 
 |  * attempt to evaluate the next one, if any. The result of the first | 
 |  * XPointer part whose evaluation succeeds is taken to be the fragment | 
 |  * located by the XPointer as a whole. If all the parts fail, the result | 
 |  * for the XPointer as a whole is a sub-resource error. | 
 |  * ----------- | 
 |  * | 
 |  * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based | 
 |  * expressions or other schemes. | 
 |  */ | 
 | static void | 
 | xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) { | 
 |     if (name == NULL) | 
 |     name = xmlXPathParseName(ctxt); | 
 |     if (name == NULL) | 
 | 	XP_ERROR(XPATH_EXPR_ERROR); | 
 |     while (name != NULL) { | 
 | 	xmlXPtrEvalXPtrPart(ctxt, name); | 
 |  | 
 | 	/* in case of syntax error, break here */ | 
 | 	if (ctxt->error != XPATH_EXPRESSION_OK) | 
 | 	    return; | 
 |  | 
 | 	/* | 
 | 	 * If the returned value is a non-empty nodeset | 
 | 	 * or location set, return here. | 
 | 	 */ | 
 | 	if (ctxt->value != NULL) { | 
 | 	    xmlXPathObjectPtr obj = ctxt->value; | 
 |  | 
 | 	    switch (obj->type) { | 
 | 		case XPATH_LOCATIONSET: { | 
 | 		    xmlLocationSetPtr loc = ctxt->value->user; | 
 | 		    if ((loc != NULL) && (loc->locNr > 0)) | 
 | 			return; | 
 | 		    break; | 
 | 		} | 
 | 		case XPATH_NODESET: { | 
 | 		    xmlNodeSetPtr loc = ctxt->value->nodesetval; | 
 | 		    if ((loc != NULL) && (loc->nodeNr > 0)) | 
 | 			return; | 
 | 		    break; | 
 | 		} | 
 | 		default: | 
 | 		    break; | 
 | 	    } | 
 |  | 
 | 	    /* | 
 | 	     * Evaluating to improper values is equivalent to | 
 | 	     * a sub-resource error, clean-up the stack | 
 | 	     */ | 
 | 	    do { | 
 | 		obj = valuePop(ctxt); | 
 | 		if (obj != NULL) { | 
 | 		    xmlXPathFreeObject(obj); | 
 | 		} | 
 | 	    } while (obj != NULL); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Is there another XPointer part. | 
 | 	 */ | 
 | 	SKIP_BLANKS; | 
 | 	name = xmlXPathParseName(ctxt); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrEvalChildSeq: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @name:  a possible ID name of the child sequence | 
 |  * | 
 |  *  ChildSeq ::= '/1' ('/' [0-9]*)* | 
 |  *             | Name ('/' [0-9]*)+ | 
 |  * | 
 |  * Parse and evaluate a Child Sequence. This routine also handle the | 
 |  * case of a Bare Name used to get a document ID. | 
 |  */ | 
 | static void | 
 | xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) { | 
 |     /* | 
 |      * XPointer don't allow by syntax to address in mutirooted trees | 
 |      * this might prove useful in some cases, warn about it. | 
 |      */ | 
 |     if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) { | 
 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 		"warning: ChildSeq not starting by /1\n"); | 
 |     } | 
 |  | 
 |     if (name != NULL) { | 
 | 	valuePush(ctxt, xmlXPathNewString(name)); | 
 | 	xmlFree(name); | 
 | 	xmlXPathIdFunction(ctxt, 1); | 
 | 	CHECK_ERROR; | 
 |     } | 
 |  | 
 |     while (CUR == '/') { | 
 | 	int child = 0; | 
 | 	NEXT; | 
 |          | 
 | 	while ((CUR >= '0') && (CUR <= '9')) { | 
 | 	    child = child * 10 + (CUR - '0'); | 
 | 	    NEXT; | 
 | 	} | 
 | 	xmlXPtrGetChildNo(ctxt, child); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * xmlXPtrEvalXPointer: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * | 
 |  *  XPointer ::= Name | 
 |  *             | ChildSeq | 
 |  *             | FullXPtr | 
 |  * | 
 |  * Parse and evaluate an XPointer | 
 |  */ | 
 | static void | 
 | xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { | 
 |     if (ctxt->valueTab == NULL) { | 
 | 	/* Allocate the value stack */ | 
 | 	ctxt->valueTab = (xmlXPathObjectPtr *)  | 
 | 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); | 
 | 	if (ctxt->valueTab == NULL) { | 
 | 	    xmlFree(ctxt); | 
 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 		    "xmlXPathEvalXPointer: out of memory\n"); | 
 | 	    return; | 
 | 	} | 
 | 	ctxt->valueNr = 0; | 
 | 	ctxt->valueMax = 10; | 
 | 	ctxt->value = NULL; | 
 |     } | 
 |     SKIP_BLANKS; | 
 |     if (CUR == '/') { | 
 | 	xmlXPathRoot(ctxt); | 
 |         xmlXPtrEvalChildSeq(ctxt, NULL); | 
 |     } else { | 
 | 	xmlChar *name; | 
 |  | 
 | 	name = xmlXPathParseName(ctxt); | 
 | 	if (name == NULL) | 
 | 	    XP_ERROR(XPATH_EXPR_ERROR); | 
 | 	if (CUR == '(') { | 
 | 	    xmlXPtrEvalFullXPtr(ctxt, name); | 
 | 	    /* Short evaluation */ | 
 | 	    return; | 
 | 	} else { | 
 | 	    /* this handle both Bare Names and Child Sequences */ | 
 | 	    xmlXPtrEvalChildSeq(ctxt, name); | 
 | 	} | 
 |     } | 
 |     SKIP_BLANKS; | 
 |     if (CUR != 0) | 
 | 	XP_ERROR(XPATH_EXPR_ERROR); | 
 | } | 
 |  | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *			General routines				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 | void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 | void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 | void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 | void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 | void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 | void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); | 
 |  | 
 | /** | 
 |  * xmlXPtrNewContext: | 
 |  * @doc:  the XML document | 
 |  * @here:  the node that directly contains the XPointer being evaluated or NULL | 
 |  * @origin:  the element from which a user or program initiated traversal of | 
 |  *           the link, or NULL. | 
 |  * | 
 |  * Create a new XPointer context | 
 |  * | 
 |  * Returns the xmlXPathContext just allocated. | 
 |  */ | 
 | xmlXPathContextPtr | 
 | xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) { | 
 |     xmlXPathContextPtr ret; | 
 |  | 
 |     ret = xmlXPathNewContext(doc); | 
 |     if (ret == NULL) | 
 | 	return(ret); | 
 |     ret->xptr = 1; | 
 |     ret->here = here; | 
 |     ret->origin = origin; | 
 |  | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"range-to", | 
 | 	                 xmlXPtrRangeToFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"range", | 
 | 	                 xmlXPtrRangeFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside", | 
 | 	                 xmlXPtrRangeInsideFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"string-range", | 
 | 	                 xmlXPtrStringRangeFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"start-point", | 
 | 	                 xmlXPtrStartPointFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"end-point", | 
 | 	                 xmlXPtrEndPointFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)"here", | 
 | 	                 xmlXPtrHereFunction); | 
 |     xmlXPathRegisterFunc(ret, (xmlChar *)" origin", | 
 | 	                 xmlXPtrOriginFunction); | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrEval: | 
 |  * @str:  the XPointer expression | 
 |  * @ctx:  the XPointer context | 
 |  * | 
 |  * Evaluate the XPath Location Path in the given context. | 
 |  * | 
 |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. | 
 |  *         the caller has to free the object. | 
 |  */ | 
 | xmlXPathObjectPtr | 
 | xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { | 
 |     xmlXPathParserContextPtr ctxt; | 
 |     xmlXPathObjectPtr res = NULL, tmp; | 
 |     xmlXPathObjectPtr init = NULL; | 
 |     int stack = 0; | 
 |  | 
 |     xmlXPathInit(); | 
 |  | 
 |     if ((ctx == NULL) || (str == NULL)) | 
 | 	return(NULL); | 
 |  | 
 |     ctxt = xmlXPathNewParserContext(str, ctx); | 
 |     ctxt->xptr = 1; | 
 |     xmlXPtrEvalXPointer(ctxt); | 
 |  | 
 |     if ((ctxt->value != NULL) && | 
 | 	(ctxt->value->type != XPATH_NODESET) && | 
 | 	(ctxt->value->type != XPATH_LOCATIONSET)) { | 
 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrEval: evaluation failed to return a node set\n"); | 
 |     } else { | 
 | 	res = valuePop(ctxt); | 
 |     } | 
 |  | 
 |     do { | 
 |         tmp = valuePop(ctxt); | 
 | 	if (tmp != NULL) { | 
 | 	    if (tmp != init) { | 
 | 		if (tmp->type == XPATH_NODESET) { | 
 | 		    /* | 
 | 		     * Evaluation may push a root nodeset which is unused | 
 | 		     */ | 
 | 		    xmlNodeSetPtr set;  | 
 | 		    set = tmp->nodesetval; | 
 | 		    if ((set->nodeNr != 1) || | 
 | 			(set->nodeTab[0] != (xmlNodePtr) ctx->doc)) | 
 | 			stack++; | 
 | 		} else | 
 | 		    stack++;     | 
 | 	    } | 
 | 	    xmlXPathFreeObject(tmp); | 
 |         } | 
 |     } while (tmp != NULL); | 
 |     if (stack != 0) { | 
 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 		"xmlXPtrEval: %d object left on the stack\n", | 
 | 	        stack); | 
 |     } | 
 |     if (ctxt->error != XPATH_EXPRESSION_OK) { | 
 | 	xmlXPathFreeObject(res); | 
 | 	res = NULL; | 
 |     } | 
 |          | 
 |     xmlXPathFreeParserContext(ctxt); | 
 |     return(res); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrBuildRangeNodeList: | 
 |  * @range:  a range object | 
 |  * | 
 |  * Build a node list tree copy of the range | 
 |  * | 
 |  * Returns an xmlNodePtr list or NULL. | 
 |  *         the caller has to free the node tree. | 
 |  */ | 
 | static xmlNodePtr | 
 | xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { | 
 |     /* pointers to generated nodes */ | 
 |     xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp; | 
 |     /* pointers to traversal nodes */ | 
 |     xmlNodePtr start, cur, end; | 
 |     int index1, index2; | 
 |  | 
 |     if (range == NULL) | 
 | 	return(NULL); | 
 |     if (range->type != XPATH_RANGE) | 
 | 	return(NULL); | 
 |     start = (xmlNodePtr) range->user; | 
 |  | 
 |     if (start == NULL) | 
 | 	return(NULL); | 
 |     end = range->user2; | 
 |     if (end == NULL) | 
 | 	return(xmlCopyNode(start, 1)); | 
 |  | 
 |     cur = start; | 
 |     index1 = range->index; | 
 |     index2 = range->index2; | 
 |     while (cur != NULL) { | 
 | 	if (cur == end) { | 
 | 	    if (cur->type == XML_TEXT_NODE) { | 
 | 		const xmlChar *content = cur->content; | 
 | 		int len; | 
 |  | 
 | 		if (content == NULL) { | 
 | 		    tmp = xmlNewTextLen(NULL, 0); | 
 | 		} else { | 
 | 		    len = index2; | 
 | 		    if ((cur == start) && (index1 > 1)) { | 
 | 			content += (index1 - 1); | 
 | 			len -= (index1 - 1); | 
 | 			index1 = 0; | 
 | 		    } else { | 
 | 			len = index2; | 
 | 		    } | 
 | 		    tmp = xmlNewTextLen(content, len); | 
 | 		} | 
 | 		/* single sub text node selection */ | 
 | 		if (list == NULL) | 
 | 		    return(tmp); | 
 | 		/* prune and return full set */ | 
 | 		if (last != NULL) | 
 | 		    xmlAddNextSibling(last, tmp); | 
 | 		else  | 
 | 		    xmlAddChild(parent, tmp); | 
 | 		return(list); | 
 | 	    } else { | 
 | 		tmp = xmlCopyNode(cur, 0); | 
 | 		if (list == NULL) | 
 | 		    list = tmp; | 
 | 		else { | 
 | 		    if (last != NULL) | 
 | 			xmlAddNextSibling(last, tmp); | 
 | 		    else | 
 | 			xmlAddChild(parent, tmp); | 
 | 		} | 
 | 		last = NULL; | 
 | 		parent = tmp; | 
 |  | 
 | 		if (index2 > 1) { | 
 | 		    end = xmlXPtrGetNthChild(cur, index2 - 1); | 
 | 		    index2 = 0; | 
 | 		} | 
 | 		if ((cur == start) && (index1 > 1)) { | 
 | 		    cur = xmlXPtrGetNthChild(cur, index1 - 1); | 
 | 		    index1 = 0; | 
 | 		} else { | 
 | 		    cur = cur->children; | 
 | 		} | 
 | 		/* | 
 | 		 * Now gather the remaining nodes from cur to end | 
 | 		 */ | 
 | 		continue; /* while */ | 
 | 	    } | 
 | 	} else if ((cur == start) && | 
 | 		   (list == NULL) /* looks superfluous but ... */ ) { | 
 | 	    if ((cur->type == XML_TEXT_NODE) || | 
 | 		(cur->type == XML_CDATA_SECTION_NODE)) { | 
 | 		const xmlChar *content = cur->content; | 
 |  | 
 | 		if (content == NULL) { | 
 | 		    tmp = xmlNewTextLen(NULL, 0); | 
 | 		} else { | 
 | 		    if (index1 > 1) { | 
 | 			content += (index1 - 1); | 
 | 		    } | 
 | 		    tmp = xmlNewText(content); | 
 | 		} | 
 | 		last = list = tmp; | 
 | 	    } else { | 
 | 		if ((cur == start) && (index1 > 1)) { | 
 | 		    tmp = xmlCopyNode(cur, 0); | 
 | 		    list = tmp; | 
 | 		    parent = tmp; | 
 | 		    last = NULL; | 
 | 		    cur = xmlXPtrGetNthChild(cur, index1 - 1); | 
 | 		    index1 = 0; | 
 | 		    /* | 
 | 		     * Now gather the remaining nodes from cur to end | 
 | 		     */ | 
 | 		    continue; /* while */ | 
 | 		} | 
 | 		tmp = xmlCopyNode(cur, 1); | 
 | 		list = tmp; | 
 | 		parent = NULL; | 
 | 		last = tmp; | 
 | 	    } | 
 | 	} else { | 
 | 	    tmp = NULL; | 
 | 	    switch (cur->type) { | 
 | 		case XML_DTD_NODE: | 
 | 		case XML_ELEMENT_DECL: | 
 | 		case XML_ATTRIBUTE_DECL: | 
 | 		case XML_ENTITY_NODE: | 
 | 		    /* Do not copy DTD informations */ | 
 | 		    break; | 
 | 		case XML_ENTITY_DECL: | 
 | 		    TODO /* handle crossing entities -> stack needed */ | 
 | 		    break; | 
 | 		case XML_XINCLUDE_START: | 
 | 		case XML_XINCLUDE_END: | 
 | 		    /* don't consider it part of the tree content */ | 
 | 		    break; | 
 | 		case XML_ATTRIBUTE_NODE: | 
 | 		    /* Humm, should not happen ! */ | 
 | 		    STRANGE | 
 | 		    break; | 
 | 		default: | 
 | 		    tmp = xmlCopyNode(cur, 1); | 
 | 		    break; | 
 | 	    } | 
 | 	    if (tmp != NULL) { | 
 | 		if ((list == NULL) || ((last == NULL) && (parent == NULL)))  { | 
 | 		    STRANGE | 
 | 		    return(NULL); | 
 | 		} | 
 | 		if (last != NULL) | 
 | 		    xmlAddNextSibling(last, tmp); | 
 | 		else { | 
 | 		    xmlAddChild(parent, tmp); | 
 | 		    last = tmp; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 | 	/* | 
 | 	 * Skip to next node in document order | 
 | 	 */ | 
 | 	if ((list == NULL) || ((last == NULL) && (parent == NULL)))  { | 
 | 	    STRANGE | 
 | 	    return(NULL); | 
 | 	} | 
 | 	cur = xmlXPtrAdvanceNode(cur); | 
 |     } | 
 |     return(list); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrBuildNodeList: | 
 |  * @obj:  the XPointer result from the evaluation. | 
 |  * | 
 |  * Build a node list tree copy of the XPointer result. | 
 |  * This will drop Attributes and Namespace declarations. | 
 |  * | 
 |  * Returns an xmlNodePtr list or NULL. | 
 |  *         the caller has to free the node tree. | 
 |  */ | 
 | xmlNodePtr | 
 | xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) { | 
 |     xmlNodePtr list = NULL, last = NULL; | 
 |     int i; | 
 |  | 
 |     if (obj == NULL) | 
 | 	return(NULL); | 
 |     switch (obj->type) { | 
 |         case XPATH_NODESET: { | 
 | 	    xmlNodeSetPtr set = obj->nodesetval; | 
 | 	    if (set == NULL) | 
 | 		return(NULL); | 
 | 	    for (i = 0;i < set->nodeNr;i++) { | 
 | 		if (set->nodeTab[i] == NULL) | 
 | 		    continue; | 
 | 		switch (set->nodeTab[i]->type) { | 
 | 		    case XML_TEXT_NODE: | 
 | 		    case XML_CDATA_SECTION_NODE: | 
 | 		    case XML_ELEMENT_NODE: | 
 | 		    case XML_ENTITY_REF_NODE: | 
 | 		    case XML_ENTITY_NODE: | 
 | 		    case XML_PI_NODE: | 
 | 		    case XML_COMMENT_NODE: | 
 | 		    case XML_DOCUMENT_NODE: | 
 | 		    case XML_HTML_DOCUMENT_NODE: | 
 | #ifdef LIBXML_DOCB_ENABLED | 
 | 		    case XML_DOCB_DOCUMENT_NODE: | 
 | #endif | 
 | 		    case XML_XINCLUDE_START: | 
 | 		    case XML_XINCLUDE_END: | 
 | 			break; | 
 | 		    case XML_ATTRIBUTE_NODE: | 
 | 		    case XML_NAMESPACE_DECL: | 
 | 		    case XML_DOCUMENT_TYPE_NODE: | 
 | 		    case XML_DOCUMENT_FRAG_NODE: | 
 | 		    case XML_NOTATION_NODE: | 
 | 		    case XML_DTD_NODE: | 
 | 		    case XML_ELEMENT_DECL: | 
 | 		    case XML_ATTRIBUTE_DECL: | 
 | 		    case XML_ENTITY_DECL: | 
 | 			continue; /* for */ | 
 | 		} | 
 | 		if (last == NULL) | 
 | 		    list = last = xmlCopyNode(set->nodeTab[i], 1); | 
 | 		else { | 
 | 		    xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1)); | 
 | 		    if (last->next != NULL) | 
 | 			last = last->next; | 
 | 		} | 
 | 	    } | 
 | 	    break; | 
 | 	} | 
 | 	case XPATH_LOCATIONSET: { | 
 | 	    xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; | 
 | 	    if (set == NULL) | 
 | 		return(NULL); | 
 | 	    for (i = 0;i < set->locNr;i++) { | 
 | 		if (last == NULL) | 
 | 		    list = last = xmlXPtrBuildNodeList(set->locTab[i]); | 
 | 		else | 
 | 		    xmlAddNextSibling(last, | 
 | 			    xmlXPtrBuildNodeList(set->locTab[i])); | 
 | 		if (last != NULL) { | 
 | 		    while (last->next != NULL) | 
 | 			last = last->next; | 
 | 		} | 
 | 	    } | 
 | 	    break; | 
 | 	} | 
 | 	case XPATH_RANGE: | 
 | 	    return(xmlXPtrBuildRangeNodeList(obj)); | 
 | 	case XPATH_POINT: | 
 | 	    return(xmlCopyNode(obj->user, 0)); | 
 | 	default: | 
 | 	    break; | 
 |     } | 
 |     return(list); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *			XPointer functions				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlXPtrNbLocChildren: | 
 |  * @node:  an xmlNodePtr | 
 |  * | 
 |  * Count the number of location children of @node or the length of the | 
 |  * string value in case of text/PI/Comments nodes | 
 |  * | 
 |  * Returns the number of location children | 
 |  */ | 
 | static int | 
 | xmlXPtrNbLocChildren(xmlNodePtr node) { | 
 |     int ret = 0; | 
 |     if (node == NULL) | 
 | 	return(-1); | 
 |     switch (node->type) { | 
 |         case XML_HTML_DOCUMENT_NODE: | 
 |         case XML_DOCUMENT_NODE: | 
 |         case XML_ELEMENT_NODE: | 
 | 	    node = node->children; | 
 | 	    while (node != NULL) { | 
 | 		if (node->type == XML_ELEMENT_NODE) | 
 | 		    ret++; | 
 | 		node = node->next; | 
 | 	    } | 
 | 	    break; | 
 |         case XML_ATTRIBUTE_NODE: | 
 | 	    return(-1); | 
 |  | 
 |         case XML_PI_NODE: | 
 |         case XML_COMMENT_NODE: | 
 |         case XML_TEXT_NODE: | 
 |         case XML_CDATA_SECTION_NODE: | 
 |         case XML_ENTITY_REF_NODE: | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 	    ret = xmlStrlen(node->content); | 
 | #else | 
 | 	    ret = xmlBufferLength(node->content); | 
 | #endif | 
 | 	    break; | 
 | 	default: | 
 | 	    return(-1); | 
 |     } | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrHereFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing here() operation  | 
 |  * as described in 5.4.3 | 
 |  */ | 
 | void | 
 | xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     CHECK_ARITY(0); | 
 |  | 
 |     if (ctxt->context->here == NULL) | 
 | 	XP_ERROR(XPTR_SYNTAX_ERROR); | 
 |      | 
 |     valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrOriginFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing origin() operation  | 
 |  * as described in 5.4.3 | 
 |  */ | 
 | void | 
 | xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     CHECK_ARITY(0); | 
 |  | 
 |     if (ctxt->context->origin == NULL) | 
 | 	XP_ERROR(XPTR_SYNTAX_ERROR); | 
 |      | 
 |     valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrStartPointFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing start-point() operation  | 
 |  * as described in 5.4.3 | 
 |  * ---------------- | 
 |  * location-set start-point(location-set) | 
 |  * | 
 |  * For each location x in the argument location-set, start-point adds a | 
 |  * location of type point to the result location-set. That point represents | 
 |  * the start point of location x and is determined by the following rules: | 
 |  * | 
 |  * - If x is of type point, the start point is x. | 
 |  * - If x is of type range, the start point is the start point of x. | 
 |  * - If x is of type root, element, text, comment, or processing instruction, | 
 |  * - the container node of the start point is x and the index is 0. | 
 |  * - If x is of type attribute or namespace, the function must signal a | 
 |  *   syntax error. | 
 |  * ---------------- | 
 |  * | 
 |  */ | 
 | void | 
 | xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     xmlXPathObjectPtr tmp, obj, point; | 
 |     xmlLocationSetPtr newset = NULL; | 
 |     xmlLocationSetPtr oldset = NULL; | 
 |  | 
 |     CHECK_ARITY(1); | 
 |     if ((ctxt->value == NULL) || | 
 | 	((ctxt->value->type != XPATH_LOCATIONSET) && | 
 | 	 (ctxt->value->type != XPATH_NODESET))) | 
 |         XP_ERROR(XPATH_INVALID_TYPE) | 
 |  | 
 |     obj = valuePop(ctxt); | 
 |     if (obj->type == XPATH_NODESET) { | 
 | 	/* | 
 | 	 * First convert to a location set | 
 | 	 */ | 
 | 	tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); | 
 | 	xmlXPathFreeObject(obj); | 
 | 	obj = tmp; | 
 |     } | 
 |  | 
 |     newset = xmlXPtrLocationSetCreate(NULL); | 
 |     if (newset == NULL) { | 
 | 	xmlXPathFreeObject(obj); | 
 |         XP_ERROR(XPATH_MEMORY_ERROR); | 
 |     } | 
 |     oldset = (xmlLocationSetPtr) obj->user; | 
 |     if (oldset != NULL) { | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < oldset->locNr; i++) { | 
 | 	    tmp = oldset->locTab[i]; | 
 | 	    if (tmp == NULL) | 
 | 		continue; | 
 | 	    point = NULL; | 
 | 	    switch (tmp->type) { | 
 | 		case XPATH_POINT: | 
 | 		    point = xmlXPtrNewPoint(tmp->user, tmp->index); | 
 | 		    break; | 
 | 		case XPATH_RANGE: { | 
 | 		    xmlNodePtr node = tmp->user; | 
 | 		    if (node != NULL) { | 
 | 			if (node->type == XML_ATTRIBUTE_NODE) { | 
 | 			    /* TODO: Namespace Nodes ??? */ | 
 | 			    xmlXPathFreeObject(obj); | 
 | 			    xmlXPtrFreeLocationSet(newset); | 
 | 			    XP_ERROR(XPTR_SYNTAX_ERROR); | 
 | 			} | 
 | 			point = xmlXPtrNewPoint(node, tmp->index); | 
 | 		    } | 
 | 		    break; | 
 | 	        } | 
 | 		default: | 
 | 		    /*** Should we raise an error ? | 
 | 		    xmlXPathFreeObject(obj); | 
 | 		    xmlXPathFreeObject(newset); | 
 | 		    XP_ERROR(XPATH_INVALID_TYPE) | 
 | 		    ***/ | 
 | 		    break; | 
 | 	    } | 
 |             if (point != NULL) | 
 | 		xmlXPtrLocationSetAdd(newset, point); | 
 | 	} | 
 |     } | 
 |     xmlXPathFreeObject(obj); | 
 |     valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrEndPointFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing end-point() operation  | 
 |  * as described in 5.4.3 | 
 |  * ---------------------------- | 
 |  * location-set end-point(location-set) | 
 |  * | 
 |  * For each location x in the argument location-set, end-point adds a | 
 |  * location of type point to the result location-set. That point represents | 
 |  * the end point of location x and is determined by the following rules: | 
 |  * | 
 |  * - If x is of type point, the resulting point is x. | 
 |  * - If x is of type range, the resulting point is the end point of x. | 
 |  * - If x is of type root or element, the container node of the resulting | 
 |  *   point is x and the index is the number of location children of x. | 
 |  * - If x is of type text, comment, or processing instruction, the container | 
 |  *   node of the resulting point is x and the index is the length of the | 
 |  *   string-value of x. | 
 |  * - If x is of type attribute or namespace, the function must signal a | 
 |  *   syntax error. | 
 |  * ---------------------------- | 
 |  */ | 
 | void | 
 | xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     xmlXPathObjectPtr tmp, obj, point; | 
 |     xmlLocationSetPtr newset = NULL; | 
 |     xmlLocationSetPtr oldset = NULL; | 
 |  | 
 |     CHECK_ARITY(1); | 
 |     if ((ctxt->value == NULL) || | 
 | 	((ctxt->value->type != XPATH_LOCATIONSET) && | 
 | 	 (ctxt->value->type != XPATH_NODESET))) | 
 |         XP_ERROR(XPATH_INVALID_TYPE) | 
 |  | 
 |     obj = valuePop(ctxt); | 
 |     if (obj->type == XPATH_NODESET) { | 
 | 	/* | 
 | 	 * First convert to a location set | 
 | 	 */ | 
 | 	tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); | 
 | 	xmlXPathFreeObject(obj); | 
 | 	obj = tmp; | 
 |     } | 
 |  | 
 |     newset = xmlXPtrLocationSetCreate(NULL); | 
 |     oldset = (xmlLocationSetPtr) obj->user; | 
 |     if (oldset != NULL) { | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < oldset->locNr; i++) { | 
 | 	    tmp = oldset->locTab[i]; | 
 | 	    if (tmp == NULL) | 
 | 		continue; | 
 | 	    point = NULL; | 
 | 	    switch (tmp->type) { | 
 | 		case XPATH_POINT: | 
 | 		    point = xmlXPtrNewPoint(tmp->user, tmp->index); | 
 | 		    break; | 
 | 		case XPATH_RANGE: { | 
 | 		    xmlNodePtr node = tmp->user2; | 
 | 		    if (node != NULL) { | 
 | 			if (node->type == XML_ATTRIBUTE_NODE) { | 
 | 			    /* TODO: Namespace Nodes ??? */ | 
 | 			    xmlXPathFreeObject(obj); | 
 | 			    xmlXPtrFreeLocationSet(newset); | 
 | 			    XP_ERROR(XPTR_SYNTAX_ERROR); | 
 | 			} | 
 | 			point = xmlXPtrNewPoint(node, tmp->index2); | 
 | 		    } else if (tmp->user == NULL) { | 
 | 			point = xmlXPtrNewPoint(node, | 
 | 				       xmlXPtrNbLocChildren(node)); | 
 | 		    } | 
 | 		    break; | 
 | 	        } | 
 | 		default: | 
 | 		    /*** Should we raise an error ? | 
 | 		    xmlXPathFreeObject(obj); | 
 | 		    xmlXPathFreeObject(newset); | 
 | 		    XP_ERROR(XPATH_INVALID_TYPE) | 
 | 		    ***/ | 
 | 		    break; | 
 | 	    } | 
 |             if (point != NULL) | 
 | 		xmlXPtrLocationSetAdd(newset, point); | 
 | 	} | 
 |     } | 
 |     xmlXPathFreeObject(obj); | 
 |     valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * xmlXPtrCoveringRange: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @loc:  the location for which the covering range must be computed | 
 |  * | 
 |  * A covering range is a range that wholly encompasses a location | 
 |  * Section 5.3.3. Covering Ranges for All Location Types | 
 |  *        http://www.w3.org/TR/xptr#N2267 | 
 |  * | 
 |  * Returns a new location or NULL in case of error | 
 |  */ | 
 | static xmlXPathObjectPtr | 
 | xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { | 
 |     if (loc == NULL) | 
 | 	return(NULL); | 
 |     if ((ctxt == NULL) || (ctxt->context == NULL) || | 
 | 	(ctxt->context->doc == NULL)) | 
 | 	return(NULL); | 
 |     switch (loc->type) { | 
 |         case XPATH_POINT: | 
 | 	    return(xmlXPtrNewRange(loc->user, loc->index, | 
 | 			           loc->user, loc->index)); | 
 |         case XPATH_RANGE: | 
 | 	    if (loc->user2 != NULL) { | 
 | 		return(xmlXPtrNewRange(loc->user, loc->index, | 
 | 			              loc->user2, loc->index2)); | 
 | 	    } else { | 
 | 		xmlNodePtr node = (xmlNodePtr) loc->user; | 
 | 		if (node == (xmlNodePtr) ctxt->context->doc) { | 
 | 		    return(xmlXPtrNewRange(node, 0, node, | 
 | 					   xmlXPtrGetArity(node))); | 
 | 		} else { | 
 | 		    switch (node->type) { | 
 | 			case XML_ATTRIBUTE_NODE: | 
 | 			/* !!! our model is slightly different than XPath */ | 
 | 			    return(xmlXPtrNewRange(node, 0, node, | 
 | 					           xmlXPtrGetArity(node))); | 
 | 			case XML_ELEMENT_NODE: | 
 | 			case XML_TEXT_NODE: | 
 | 			case XML_CDATA_SECTION_NODE: | 
 | 			case XML_ENTITY_REF_NODE: | 
 | 			case XML_PI_NODE: | 
 | 			case XML_COMMENT_NODE: | 
 | 			case XML_DOCUMENT_NODE: | 
 | 			case XML_NOTATION_NODE: | 
 | 			case XML_HTML_DOCUMENT_NODE: { | 
 | 			    int indx = xmlXPtrGetIndex(node); | 
 | 			      | 
 | 			    node = node->parent; | 
 | 			    return(xmlXPtrNewRange(node, indx - 1, | 
 | 					           node, indx + 1)); | 
 | 			} | 
 | 			default: | 
 | 			    return(NULL); | 
 | 		    } | 
 | 		} | 
 | 	    } | 
 | 	default: | 
 | 	    TODO /* missed one case ??? */ | 
 |     } | 
 |     return(NULL); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrRangeFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing the range() function 5.4.3 | 
 |  *  location-set range(location-set ) | 
 |  * | 
 |  *  The range function returns ranges covering the locations in | 
 |  *  the argument location-set. For each location x in the argument | 
 |  *  location-set, a range location representing the covering range of | 
 |  *  x is added to the result location-set. | 
 |  */ | 
 | void | 
 | xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     int i; | 
 |     xmlXPathObjectPtr set; | 
 |     xmlLocationSetPtr oldset; | 
 |     xmlLocationSetPtr newset; | 
 |  | 
 |     CHECK_ARITY(1); | 
 |     if ((ctxt->value == NULL) || | 
 | 	((ctxt->value->type != XPATH_LOCATIONSET) && | 
 | 	 (ctxt->value->type != XPATH_NODESET))) | 
 |         XP_ERROR(XPATH_INVALID_TYPE) | 
 |  | 
 |     set = valuePop(ctxt); | 
 |     if (set->type == XPATH_NODESET) { | 
 | 	xmlXPathObjectPtr tmp; | 
 |  | 
 | 	/* | 
 | 	 * First convert to a location set | 
 | 	 */ | 
 | 	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); | 
 | 	xmlXPathFreeObject(set); | 
 | 	set = tmp; | 
 |     } | 
 |     oldset = (xmlLocationSetPtr) set->user; | 
 |  | 
 |     /* | 
 |      * The loop is to compute the covering range for each item and add it | 
 |      */ | 
 |     newset = xmlXPtrLocationSetCreate(NULL); | 
 |     for (i = 0;i < oldset->locNr;i++) { | 
 | 	xmlXPtrLocationSetAdd(newset, | 
 | 		xmlXPtrCoveringRange(ctxt, oldset->locTab[i])); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Save the new value and cleanup | 
 |      */ | 
 |     valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 |     xmlXPathFreeObject(set); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrInsideRange: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @loc:  the location for which the inside range must be computed | 
 |  * | 
 |  * A inside range is a range described in the range-inside() description | 
 |  * | 
 |  * Returns a new location or NULL in case of error | 
 |  */ | 
 | static xmlXPathObjectPtr | 
 | xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { | 
 |     if (loc == NULL) | 
 | 	return(NULL); | 
 |     if ((ctxt == NULL) || (ctxt->context == NULL) || | 
 | 	(ctxt->context->doc == NULL)) | 
 | 	return(NULL); | 
 |     switch (loc->type) { | 
 |         case XPATH_POINT: { | 
 | 	    xmlNodePtr node = (xmlNodePtr) loc->user; | 
 | 	    switch (node->type) { | 
 | 		case XML_PI_NODE: | 
 | 		case XML_COMMENT_NODE: | 
 | 		case XML_TEXT_NODE: | 
 | 		case XML_CDATA_SECTION_NODE: { | 
 | 		    if (node->content == NULL) { | 
 | 			return(xmlXPtrNewRange(node, 0, node, 0)); | 
 | 		    } else { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 			return(xmlXPtrNewRange(node, 0, node, | 
 | 					       xmlStrlen(node->content))); | 
 | #else | 
 | 			return(xmlXPtrNewRange(node, 0, node, | 
 | 					       xmlBufferLength(node->content))); | 
 | #endif | 
 | 		    } | 
 | 		} | 
 | 		case XML_ATTRIBUTE_NODE: | 
 | 		case XML_ELEMENT_NODE: | 
 | 		case XML_ENTITY_REF_NODE: | 
 | 		case XML_DOCUMENT_NODE: | 
 | 		case XML_NOTATION_NODE: | 
 | 		case XML_HTML_DOCUMENT_NODE: { | 
 | 		    return(xmlXPtrNewRange(node, 0, node, | 
 | 					   xmlXPtrGetArity(node))); | 
 | 		} | 
 | 		default: | 
 | 		    break; | 
 | 	    } | 
 | 	    return(NULL); | 
 | 	} | 
 |         case XPATH_RANGE: { | 
 | 	    xmlNodePtr node = (xmlNodePtr) loc->user; | 
 | 	    if (loc->user2 != NULL) { | 
 | 		return(xmlXPtrNewRange(node, loc->index, | 
 | 			               loc->user2, loc->index2)); | 
 | 	    } else { | 
 | 		switch (node->type) { | 
 | 		    case XML_PI_NODE: | 
 | 		    case XML_COMMENT_NODE: | 
 | 		    case XML_TEXT_NODE: | 
 | 		    case XML_CDATA_SECTION_NODE: { | 
 | 			if (node->content == NULL) { | 
 | 			    return(xmlXPtrNewRange(node, 0, node, 0)); | 
 | 			} else { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 			    return(xmlXPtrNewRange(node, 0, node, | 
 | 						   xmlStrlen(node->content))); | 
 | #else | 
 | 			    return(xmlXPtrNewRange(node, 0, node, | 
 | 					       xmlBufferLength(node->content))); | 
 | #endif | 
 | 			} | 
 | 		    } | 
 | 		    case XML_ATTRIBUTE_NODE: | 
 | 		    case XML_ELEMENT_NODE: | 
 | 		    case XML_ENTITY_REF_NODE: | 
 | 		    case XML_DOCUMENT_NODE: | 
 | 		    case XML_NOTATION_NODE: | 
 | 		    case XML_HTML_DOCUMENT_NODE: { | 
 | 			return(xmlXPtrNewRange(node, 0, node, | 
 | 					       xmlXPtrGetArity(node))); | 
 | 		    } | 
 | 		    default: | 
 | 			break; | 
 | 		} | 
 | 		return(NULL); | 
 | 	    } | 
 |         } | 
 | 	default: | 
 | 	    TODO /* missed one case ??? */ | 
 |     } | 
 |     return(NULL); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrRangeInsideFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing the range-inside() function 5.4.3 | 
 |  *  location-set range-inside(location-set ) | 
 |  * | 
 |  *  The range-inside function returns ranges covering the contents of | 
 |  *  the locations in the argument location-set. For each location x in | 
 |  *  the argument location-set, a range location is added to the result | 
 |  *  location-set. If x is a range location, then x is added to the | 
 |  *  result location-set. If x is not a range location, then x is used | 
 |  *  as the container location of the start and end points of the range | 
 |  *  location to be added; the index of the start point of the range is | 
 |  *  zero; if the end point is a character point then its index is the | 
 |  *  length of the string-value of x, and otherwise is the number of | 
 |  *  location children of x. | 
 |  * | 
 |  */ | 
 | void | 
 | xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     int i; | 
 |     xmlXPathObjectPtr set; | 
 |     xmlLocationSetPtr oldset; | 
 |     xmlLocationSetPtr newset; | 
 |  | 
 |     CHECK_ARITY(1); | 
 |     if ((ctxt->value == NULL) || | 
 | 	((ctxt->value->type != XPATH_LOCATIONSET) && | 
 | 	 (ctxt->value->type != XPATH_NODESET))) | 
 |         XP_ERROR(XPATH_INVALID_TYPE) | 
 |  | 
 |     set = valuePop(ctxt); | 
 |     if (set->type == XPATH_NODESET) { | 
 | 	xmlXPathObjectPtr tmp; | 
 |  | 
 | 	/* | 
 | 	 * First convert to a location set | 
 | 	 */ | 
 | 	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); | 
 | 	xmlXPathFreeObject(set); | 
 | 	set = tmp; | 
 |     } | 
 |     oldset = (xmlLocationSetPtr) set->user; | 
 |  | 
 |     /* | 
 |      * The loop is to compute the covering range for each item and add it | 
 |      */ | 
 |     newset = xmlXPtrLocationSetCreate(NULL); | 
 |     for (i = 0;i < oldset->locNr;i++) { | 
 | 	xmlXPtrLocationSetAdd(newset, | 
 | 		xmlXPtrInsideRange(ctxt, oldset->locTab[i])); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Save the new value and cleanup | 
 |      */ | 
 |     valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 |     xmlXPathFreeObject(set); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrRangeToFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Implement the range-to() XPointer function | 
 |  */ | 
 | void | 
 | xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     xmlXPathObjectPtr range; | 
 |     const xmlChar *cur; | 
 |     xmlXPathObjectPtr res, obj; | 
 |     xmlXPathObjectPtr tmp; | 
 |     xmlLocationSetPtr newset = NULL; | 
 |     xmlNodeSetPtr oldset; | 
 |     int i; | 
 |  | 
 |     CHECK_ARITY(1); | 
 |     /* | 
 |      * Save the expression pointer since we will have to evaluate | 
 |      * it multiple times. Initialize the new set. | 
 |      */ | 
 |     CHECK_TYPE(XPATH_NODESET); | 
 |     obj = valuePop(ctxt); | 
 |     oldset = obj->nodesetval; | 
 |     ctxt->context->node = NULL; | 
 |  | 
 |     cur = ctxt->cur; | 
 |     newset = xmlXPtrLocationSetCreate(NULL); | 
 |      | 
 |     for (i = 0; i < oldset->nodeNr; i++) { | 
 | 	ctxt->cur = cur; | 
 |  | 
 | 	/* | 
 | 	 * Run the evaluation with a node list made of a single item | 
 | 	 * in the nodeset. | 
 | 	 */ | 
 | 	ctxt->context->node = oldset->nodeTab[i]; | 
 | 	tmp = xmlXPathNewNodeSet(ctxt->context->node); | 
 | 	valuePush(ctxt, tmp); | 
 |  | 
 | 	xmlXPathEvalExpr(ctxt); | 
 | 	CHECK_ERROR; | 
 |  | 
 | 	/* | 
 | 	 * The result of the evaluation need to be tested to | 
 | 	 * decided whether the filter succeeded or not | 
 | 	 */ | 
 | 	res = valuePop(ctxt); | 
 | 	range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res); | 
 | 	if (range != NULL) { | 
 | 	    xmlXPtrLocationSetAdd(newset, range); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Cleanup | 
 | 	 */ | 
 | 	if (res != NULL) | 
 | 	    xmlXPathFreeObject(res); | 
 | 	if (ctxt->value == tmp) { | 
 | 	    res = valuePop(ctxt); | 
 | 	    xmlXPathFreeObject(res); | 
 | 	} | 
 | 	 | 
 | 	ctxt->context->node = NULL; | 
 |     } | 
 |  | 
 |     /* | 
 |      * The result is used as the new evaluation set. | 
 |      */ | 
 |     xmlXPathFreeObject(obj); | 
 |     ctxt->context->node = NULL; | 
 |     ctxt->context->contextSize = -1; | 
 |     ctxt->context->proximityPosition = -1; | 
 |     valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrAdvanceNode: | 
 |  * @cur:  the node | 
 |  * | 
 |  * Advance to the next element or text node in document order | 
 |  * TODO: add a stack for entering/exiting entities  | 
 |  * | 
 |  * Returns -1 in case of failure, 0 otherwise | 
 |  */ | 
 | xmlNodePtr | 
 | xmlXPtrAdvanceNode(xmlNodePtr cur) { | 
 | next: | 
 |     if (cur == NULL) | 
 | 	return(NULL); | 
 |     if (cur->children != NULL) { | 
 |         cur = cur->children ; | 
 | 	goto found; | 
 |     } | 
 |     if (cur->next != NULL) { | 
 | 	cur = cur->next; | 
 | 	goto found; | 
 |     } | 
 |     do { | 
 |         cur = cur->parent; | 
 |         if (cur == NULL) return(NULL); | 
 |         if (cur->next != NULL) { | 
 | 	    cur = cur->next; | 
 | 	    goto found; | 
 | 	} | 
 |     } while (cur != NULL); | 
 |  | 
 | found: | 
 |     if ((cur->type != XML_ELEMENT_NODE) && | 
 | 	(cur->type != XML_TEXT_NODE) && | 
 | 	(cur->type != XML_DOCUMENT_NODE) && | 
 | 	(cur->type != XML_HTML_DOCUMENT_NODE) && | 
 | 	(cur->type != XML_CDATA_SECTION_NODE)) | 
 | 	goto next; | 
 |     if (cur->type == XML_ENTITY_REF_NODE) { | 
 | 	TODO | 
 |     } | 
 |     return(cur); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrAdvanceChar: | 
 |  * @node:  the node | 
 |  * @indx:  the indx | 
 |  * @bytes:  the number of bytes | 
 |  * | 
 |  * Advance a point of the associated number of bytes (not UTF8 chars) | 
 |  * | 
 |  * Returns -1 in case of failure, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) { | 
 |     xmlNodePtr cur; | 
 |     int pos; | 
 |     int len; | 
 |  | 
 |     if ((node == NULL) || (indx == NULL)) | 
 | 	return(-1); | 
 |     cur = *node; | 
 |     if (cur == NULL) | 
 | 	return(-1); | 
 |     pos = *indx; | 
 |  | 
 |     while (bytes >= 0) { | 
 | 	/* | 
 | 	 * First position to the beginning of the first text node | 
 | 	 * corresponding to this point | 
 | 	 */ | 
 | 	while ((cur != NULL) && | 
 | 	       ((cur->type == XML_ELEMENT_NODE) || | 
 | 	        (cur->type == XML_DOCUMENT_NODE) || | 
 | 	        (cur->type == XML_HTML_DOCUMENT_NODE))) { | 
 | 	    if (pos > 0) { | 
 | 		cur = xmlXPtrGetNthChild(cur, pos); | 
 | 		pos = 0; | 
 | 	    } else { | 
 | 		cur = xmlXPtrAdvanceNode(cur); | 
 | 		pos = 0; | 
 | 	    } | 
 | 	} | 
 |  | 
 | 	if (cur == NULL) { | 
 | 	    *node = NULL; | 
 | 	    *indx = 0; | 
 | 	    return(-1); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * if there is no move needed return the current value. | 
 | 	 */ | 
 | 	if (pos == 0) pos = 1; | 
 | 	if (bytes == 0) { | 
 | 	    *node = cur; | 
 | 	    *indx = pos; | 
 | 	    return(0); | 
 | 	} | 
 | 	/* | 
 | 	 * We should have a text (or cdata) node ...  | 
 | 	 */ | 
 | 	len = 0; | 
 | 	if ((cur->type != XML_ELEMENT_NODE) && | 
 |             (cur->content != NULL)) { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 	    len = xmlStrlen(cur->content); | 
 | #else | 
 | 	    len = xmlBufferLength(cur->content); | 
 | #endif | 
 | 	} | 
 | 	if (pos > len) { | 
 | 	    /* Strange, the indx in the text node is greater than it's len */ | 
 | 	    STRANGE | 
 | 	    pos = len; | 
 | 	} | 
 | 	if (pos + bytes >= len) { | 
 | 	    bytes -= (len - pos); | 
 | 	    cur = xmlXPtrAdvanceNode(cur); | 
 | 	    cur = 0; | 
 | 	} else if (pos + bytes < len) { | 
 | 	    pos += bytes; | 
 | 	    *node = cur; | 
 | 	    *indx = pos; | 
 | 	    return(0); | 
 | 	} | 
 |     } | 
 |     return(-1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrMatchString: | 
 |  * @string:  the string to search | 
 |  * @start:  the start textnode | 
 |  * @startindex:  the start index | 
 |  * @end:  the end textnode IN/OUT | 
 |  * @endindex:  the end index IN/OUT | 
 |  * | 
 |  * Check whether the document contains @string at the position | 
 |  * (@start, @startindex) and limited by the (@end, @endindex) point | 
 |  * | 
 |  * Returns -1 in case of failure, 0 if not found, 1 if found in which case | 
 |  *            (@start, @startindex) will indicate the position of the beginning | 
 |  *            of the range and (@end, @endindex) will indicate the end | 
 |  *            of the range | 
 |  */ | 
 | static int | 
 | xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, | 
 | 	            xmlNodePtr *end, int *endindex) { | 
 |     xmlNodePtr cur; | 
 |     int pos; /* 0 based */ | 
 |     int len; /* in bytes */ | 
 |     int stringlen; /* in bytes */ | 
 |     int match; | 
 |  | 
 |     if (string == NULL) | 
 | 	return(-1); | 
 |     if (start == NULL) | 
 | 	return(-1); | 
 |     if ((end == NULL) || (endindex == NULL)) | 
 | 	return(-1); | 
 |     cur = start; | 
 |     if (cur == NULL) | 
 | 	return(-1); | 
 |     pos = startindex - 1; | 
 |     stringlen = xmlStrlen(string); | 
 |  | 
 |     while (stringlen > 0) { | 
 | 	if ((cur == *end) && (pos + stringlen > *endindex)) | 
 | 	    return(0); | 
 |  | 
 | 	if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 	    len = xmlStrlen(cur->content); | 
 | #else | 
 | 	    len = xmlBufferLength(cur->content); | 
 | #endif | 
 | 	    if (len >= pos + stringlen) { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 		match = (!xmlStrncmp(&cur->content[pos], string, stringlen)); | 
 | #else | 
 | 		len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos], | 
 | 			           string, stringlen)); | 
 | #endif | 
 | 		if (match) { | 
 | #ifdef DEBUG_RANGES | 
 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 			    "found range %d bytes at index %d of ->", | 
 | 			    stringlen, pos + 1); | 
 | 		    xmlDebugDumpString(stdout, cur->content); | 
 | 		    xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | #endif | 
 | 		    *end = cur; | 
 | 		    *endindex = pos + stringlen; | 
 | 		    return(1); | 
 | 		} else { | 
 | 		    return(0); | 
 | 		} | 
 | 	    } else { | 
 |                 int sub = len - pos; | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 		match = (!xmlStrncmp(&cur->content[pos], string, sub)); | 
 | #else | 
 | 		len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos], | 
 | 			           string, sub)); | 
 | #endif | 
 | 		if (match) { | 
 | #ifdef DEBUG_RANGES | 
 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 			    "found subrange %d bytes at index %d of ->", | 
 | 			    sub, pos + 1); | 
 | 		    xmlDebugDumpString(stdout, cur->content); | 
 | 		    xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | #endif | 
 |                     string = &string[sub]; | 
 | 		    stringlen -= sub; | 
 | 		} else { | 
 | 		    return(0); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 | 	cur = xmlXPtrAdvanceNode(cur); | 
 | 	if (cur == NULL) | 
 | 	    return(0); | 
 | 	pos = 0; | 
 |     } | 
 |     return(1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrSearchString: | 
 |  * @string:  the string to search | 
 |  * @start:  the start textnode IN/OUT | 
 |  * @startindex:  the start index IN/OUT | 
 |  * @end:  the end textnode | 
 |  * @endindex:  the end index | 
 |  * | 
 |  * Search the next occurrence of @string within the document content | 
 |  * until the (@end, @endindex) point is reached | 
 |  * | 
 |  * Returns -1 in case of failure, 0 if not found, 1 if found in which case | 
 |  *            (@start, @startindex) will indicate the position of the beginning | 
 |  *            of the range and (@end, @endindex) will indicate the end | 
 |  *            of the range | 
 |  */ | 
 | static int | 
 | xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, | 
 | 	            xmlNodePtr *end, int *endindex) { | 
 |     xmlNodePtr cur; | 
 |     const xmlChar *str; | 
 |     int pos; /* 0 based */ | 
 |     int len; /* in bytes */ | 
 |     xmlChar first; | 
 |  | 
 |     if (string == NULL) | 
 | 	return(-1); | 
 |     if ((start == NULL) || (startindex == NULL)) | 
 | 	return(-1); | 
 |     if ((end == NULL) || (endindex == NULL)) | 
 | 	return(-1); | 
 |     cur = *start; | 
 |     if (cur == NULL) | 
 | 	return(-1); | 
 |     pos = *startindex - 1; | 
 |     first = string[0]; | 
 |  | 
 |     while (cur != NULL) { | 
 | 	if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 	    len = xmlStrlen(cur->content); | 
 | #else | 
 | 	    len = xmlBufferLength(cur->content); | 
 | #endif | 
 | 	    while (pos <= len) { | 
 | 		if (first != 0) { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 		    str = xmlStrchr(&cur->content[pos], first); | 
 | #else | 
 | 		    str = xmlStrchr(&xmlBufferContent(cur->content)[pos], | 
 | 			            first); | 
 | #endif | 
 | 		    if (str != NULL) { | 
 | 			pos = (str - (xmlChar *)(cur->content)); | 
 | #ifdef DEBUG_RANGES | 
 | 			xmlGenericError(xmlGenericErrorContext, | 
 | 				"found '%c' at index %d of ->", | 
 | 				first, pos + 1); | 
 | 			xmlDebugDumpString(stdout, cur->content); | 
 | 			xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | #endif | 
 | 			if (xmlXPtrMatchString(string, cur, pos + 1, | 
 | 					       end, endindex)) { | 
 | 			    *start = cur; | 
 | 			    *startindex = pos + 1; | 
 | 			    return(1); | 
 | 			} | 
 | 			pos++; | 
 | 		    } else { | 
 | 			pos = len + 1; | 
 | 		    } | 
 | 		} else { | 
 | 		    /* | 
 | 		     * An empty string is considered to match before each | 
 | 		     * character of the string-value and after the final | 
 | 		     * character.  | 
 | 		     */ | 
 | #ifdef DEBUG_RANGES | 
 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 			    "found '' at index %d of ->", | 
 | 			    pos + 1); | 
 | 		    xmlDebugDumpString(stdout, cur->content); | 
 | 		    xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | #endif | 
 | 		    *start = cur; | 
 | 		    *startindex = pos + 1; | 
 | 		    *end = cur; | 
 | 		    *endindex = pos + 1; | 
 | 		    return(1); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 | 	if ((cur == *end) && (pos >= *endindex)) | 
 | 	    return(0); | 
 | 	cur = xmlXPtrAdvanceNode(cur); | 
 | 	if (cur == NULL) | 
 | 	    return(0); | 
 | 	pos = 1; | 
 |     } | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrGetLastChar: | 
 |  * @node:  the node | 
 |  * @index:  the index | 
 |  * | 
 |  * Computes the point coordinates of the last char of this point | 
 |  * | 
 |  * Returns -1 in case of failure, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) { | 
 |     xmlNodePtr cur; | 
 |     int pos, len = 0; | 
 |  | 
 |     if ((node == NULL) || (indx == NULL)) | 
 | 	return(-1); | 
 |     cur = *node; | 
 |     pos = *indx; | 
 |  | 
 |     if (cur == NULL) | 
 | 	return(-1); | 
 |      | 
 |     if ((cur->type == XML_ELEMENT_NODE) || | 
 | 	(cur->type == XML_DOCUMENT_NODE) || | 
 | 	(cur->type == XML_HTML_DOCUMENT_NODE)) { | 
 | 	if (pos > 0) { | 
 | 	    cur = xmlXPtrGetNthChild(cur, pos); | 
 | 	    pos = 0; | 
 | 	} | 
 |     } | 
 |     while (cur != NULL) { | 
 | 	if (cur->last != NULL) | 
 | 	    cur = cur->last; | 
 | 	else if ((cur->type != XML_ELEMENT_NODE) && | 
 | 	         (cur->content != NULL)) { | 
 | #ifndef XML_USE_BUFFER_CONTENT | 
 | 	    len = xmlStrlen(cur->content); | 
 | #else | 
 | 	    len = xmlBufferLength(cur->content); | 
 | #endif | 
 | 	    break; | 
 | 	} else { | 
 | 	    return(-1); | 
 | 	} | 
 |     } | 
 |     if (cur == NULL) | 
 | 	return(-1); | 
 |     *node = cur; | 
 |     *indx = len; | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrGetStartPoint: | 
 |  * @obj:  an range | 
 |  * @node:  the resulting node | 
 |  * @indx:  the resulting index | 
 |  * | 
 |  * read the object and return the start point coordinates. | 
 |  * | 
 |  * Returns -1 in case of failure, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { | 
 |     if ((obj == NULL) || (node == NULL) || (indx == NULL)) | 
 | 	return(-1); | 
 |  | 
 |     switch (obj->type) { | 
 |         case XPATH_POINT: | 
 | 	    *node = obj->user; | 
 | 	    if (obj->index <= 0) | 
 | 		*indx = 0; | 
 | 	    else | 
 | 		*indx = obj->index; | 
 | 	    return(0); | 
 |         case XPATH_RANGE: | 
 | 	    *node = obj->user; | 
 | 	    if (obj->index <= 0) | 
 | 		*indx = 0; | 
 | 	    else | 
 | 		*indx = obj->index; | 
 | 	    return(0); | 
 | 	default: | 
 | 	    break; | 
 |     } | 
 |     return(-1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrGetEndPoint: | 
 |  * @obj:  an range | 
 |  * @node:  the resulting node | 
 |  * @indx:  the resulting indx | 
 |  * | 
 |  * read the object and return the end point coordinates. | 
 |  * | 
 |  * Returns -1 in case of failure, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { | 
 |     if ((obj == NULL) || (node == NULL) || (indx == NULL)) | 
 | 	return(-1); | 
 |  | 
 |     switch (obj->type) { | 
 |         case XPATH_POINT: | 
 | 	    *node = obj->user; | 
 | 	    if (obj->index <= 0) | 
 | 		*indx = 0; | 
 | 	    else | 
 | 		*indx = obj->index; | 
 | 	    return(0); | 
 |         case XPATH_RANGE: | 
 | 	    *node = obj->user; | 
 | 	    if (obj->index <= 0) | 
 | 		*indx = 0; | 
 | 	    else | 
 | 		*indx = obj->index; | 
 | 	    return(0); | 
 | 	default: | 
 | 	    break; | 
 |     } | 
 |     return(-1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrStringRangeFunction: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * @nargs:  the number of args | 
 |  * | 
 |  * Function implementing the string-range() function | 
 |  * range as described in 5.4.2  | 
 |  * | 
 |  * ------------------------------ | 
 |  * [Definition: For each location in the location-set argument, | 
 |  * string-range returns a set of string ranges, a set of substrings in a | 
 |  * string. Specifically, the string-value of the location is searched for | 
 |  * substrings that match the string argument, and the resulting location-set | 
 |  * will contain a range location for each non-overlapping match.] | 
 |  * An empty string is considered to match before each character of the | 
 |  * string-value and after the final character. Whitespace in a string | 
 |  * is matched literally, with no normalization except that provided by | 
 |  * XML for line ends. The third argument gives the position of the first | 
 |  * character to be in the resulting range, relative to the start of the | 
 |  * match. The default value is 1, which makes the range start immediately | 
 |  * before the first character of the matched string. The fourth argument | 
 |  * gives the number of characters in the range; the default is that the | 
 |  * range extends to the end of the matched string. | 
 |  * | 
 |  * Element boundaries, as well as entire embedded nodes such as processing | 
 |  * instructions and comments, are ignored as defined in [XPath]. | 
 |  * | 
 |  * If the string in the second argument is not found in the string-value | 
 |  * of the location, or if a value in the third or fourth argument indicates | 
 |  * a string that is beyond the beginning or end of the document, the | 
 |  * expression fails. | 
 |  * | 
 |  * The points of the range-locations in the returned location-set will | 
 |  * all be character points. | 
 |  * ------------------------------ | 
 |  */ | 
 | void | 
 | xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 |     int i, startindex, endindex, fendindex; | 
 |     xmlNodePtr start, end, fend; | 
 |     xmlXPathObjectPtr set; | 
 |     xmlLocationSetPtr oldset; | 
 |     xmlLocationSetPtr newset; | 
 |     xmlXPathObjectPtr string; | 
 |     xmlXPathObjectPtr position = NULL; | 
 |     xmlXPathObjectPtr number = NULL; | 
 |     int found, pos = 0, num = 0; | 
 |  | 
 |     /* | 
 |      * Grab the arguments | 
 |      */ | 
 |     if ((nargs < 2) || (nargs > 4)) | 
 | 	XP_ERROR(XPATH_INVALID_ARITY); | 
 |  | 
 |     if (nargs >= 4) { | 
 | 	CHECK_TYPE(XPATH_NUMBER); | 
 | 	number = valuePop(ctxt); | 
 | 	if (number != NULL) | 
 | 	    num = (int) number->floatval; | 
 |     } | 
 |     if (nargs >= 3) { | 
 | 	CHECK_TYPE(XPATH_NUMBER); | 
 | 	position = valuePop(ctxt); | 
 | 	if (position != NULL) | 
 | 	    pos = (int) position->floatval; | 
 |     } | 
 |     CHECK_TYPE(XPATH_STRING); | 
 |     string = valuePop(ctxt); | 
 |     if ((ctxt->value == NULL) || | 
 | 	((ctxt->value->type != XPATH_LOCATIONSET) && | 
 | 	 (ctxt->value->type != XPATH_NODESET))) | 
 |         XP_ERROR(XPATH_INVALID_TYPE) | 
 |  | 
 |     set = valuePop(ctxt); | 
 |     if (set->type == XPATH_NODESET) { | 
 | 	xmlXPathObjectPtr tmp; | 
 |  | 
 | 	/* | 
 | 	 * First convert to a location set | 
 | 	 */ | 
 | 	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); | 
 | 	xmlXPathFreeObject(set); | 
 | 	set = tmp; | 
 |     } | 
 |     oldset = (xmlLocationSetPtr) set->user; | 
 |  | 
 |     /* | 
 |      * The loop is to search for each element in the location set | 
 |      * the list of location set corresponding to that search | 
 |      */ | 
 |     newset = xmlXPtrLocationSetCreate(NULL); | 
 |     for (i = 0;i < oldset->locNr;i++) { | 
 | #ifdef DEBUG_RANGES | 
 | 	xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0); | 
 | #endif | 
 |  | 
 | 	xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex); | 
 | 	xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex); | 
 | 	xmlXPtrAdvanceChar(&start, &startindex, 0); | 
 | 	xmlXPtrGetLastChar(&end, &endindex); | 
 |  | 
 | #ifdef DEBUG_RANGES | 
 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 		"from index %d of ->", startindex); | 
 | 	xmlDebugDumpString(stdout, start->content); | 
 | 	xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 		"to index %d of ->", endindex); | 
 | 	xmlDebugDumpString(stdout, end->content); | 
 | 	xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | #endif | 
 | 	do { | 
 |             fend = end; | 
 |             fendindex = endindex; | 
 | 	    found = xmlXPtrSearchString(string->stringval, &start, &startindex, | 
 | 		                        &fend, &fendindex); | 
 | 	    if (found == 1) { | 
 | 		if (position == NULL) { | 
 | 		    xmlXPtrLocationSetAdd(newset, | 
 | 			 xmlXPtrNewRange(start, startindex, fend, fendindex)); | 
 | 		} else if (xmlXPtrAdvanceChar(&start, &startindex, | 
 | 			                      pos - 1) == 0) { | 
 | 		    if ((number != NULL) && (num > 0)) { | 
 | 			int rindx; | 
 | 			xmlNodePtr rend; | 
 | 			rend = start; | 
 | 			rindx = startindex - 1; | 
 | 			if (xmlXPtrAdvanceChar(&rend, &rindx, | 
 | 				               num) == 0) { | 
 | 			    xmlXPtrLocationSetAdd(newset, | 
 | 					xmlXPtrNewRange(start, startindex, | 
 | 							rend, rindx)); | 
 | 			} | 
 | 		    } else if ((number != NULL) && (num <= 0)) { | 
 | 			xmlXPtrLocationSetAdd(newset, | 
 | 				    xmlXPtrNewRange(start, startindex, | 
 | 						    start, startindex)); | 
 | 		    } else { | 
 | 			xmlXPtrLocationSetAdd(newset, | 
 | 				    xmlXPtrNewRange(start, startindex, | 
 | 						    fend, fendindex)); | 
 | 		    } | 
 | 		} | 
 | 		start = fend; | 
 | 		startindex = fendindex; | 
 | 		if (string->stringval[0] == 0) | 
 | 		    startindex++; | 
 | 	    } | 
 | 	} while (found == 1); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Save the new value and cleanup | 
 |      */ | 
 |     valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 |     xmlXPathFreeObject(set); | 
 |     xmlXPathFreeObject(string); | 
 |     if (position) xmlXPathFreeObject(position); | 
 |     if (number) xmlXPathFreeObject(number); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlXPtrEvalRangePredicate: | 
 |  * @ctxt:  the XPointer Parser context | 
 |  * | 
 |  *  [8]   Predicate ::=   '[' PredicateExpr ']' | 
 |  *  [9]   PredicateExpr ::=   Expr  | 
 |  * | 
 |  * Evaluate a predicate as in xmlXPathEvalPredicate() but for | 
 |  * a Location Set instead of a node set | 
 |  */ | 
 | void | 
 | xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) { | 
 |     const xmlChar *cur; | 
 |     xmlXPathObjectPtr res; | 
 |     xmlXPathObjectPtr obj, tmp; | 
 |     xmlLocationSetPtr newset = NULL; | 
 |     xmlLocationSetPtr oldset; | 
 |     int i; | 
 |  | 
 |     SKIP_BLANKS; | 
 |     if (CUR != '[') { | 
 | 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); | 
 |     } | 
 |     NEXT; | 
 |     SKIP_BLANKS; | 
 |  | 
 |     /* | 
 |      * Extract the old set, and then evaluate the result of the | 
 |      * expression for all the element in the set. use it to grow | 
 |      * up a new set. | 
 |      */ | 
 |     CHECK_TYPE(XPATH_LOCATIONSET); | 
 |     obj = valuePop(ctxt); | 
 |     oldset = obj->user; | 
 |     ctxt->context->node = NULL; | 
 |  | 
 |     if ((oldset == NULL) || (oldset->locNr == 0)) { | 
 | 	ctxt->context->contextSize = 0; | 
 | 	ctxt->context->proximityPosition = 0; | 
 | 	xmlXPathEvalExpr(ctxt); | 
 | 	res = valuePop(ctxt); | 
 | 	if (res != NULL) | 
 | 	    xmlXPathFreeObject(res); | 
 | 	valuePush(ctxt, obj); | 
 | 	CHECK_ERROR; | 
 |     } else { | 
 | 	/* | 
 | 	 * Save the expression pointer since we will have to evaluate | 
 | 	 * it multiple times. Initialize the new set. | 
 | 	 */ | 
 |         cur = ctxt->cur; | 
 | 	newset = xmlXPtrLocationSetCreate(NULL); | 
 | 	 | 
 |         for (i = 0; i < oldset->locNr; i++) { | 
 | 	    ctxt->cur = cur; | 
 |  | 
 | 	    /* | 
 | 	     * Run the evaluation with a node list made of a single item | 
 | 	     * in the nodeset. | 
 | 	     */ | 
 | 	    ctxt->context->node = oldset->locTab[i]->user; | 
 | 	    tmp = xmlXPathNewNodeSet(ctxt->context->node); | 
 | 	    valuePush(ctxt, tmp); | 
 | 	    ctxt->context->contextSize = oldset->locNr; | 
 | 	    ctxt->context->proximityPosition = i + 1; | 
 |  | 
 | 	    xmlXPathEvalExpr(ctxt); | 
 | 	    CHECK_ERROR; | 
 |  | 
 | 	    /* | 
 | 	     * The result of the evaluation need to be tested to | 
 | 	     * decided whether the filter succeeded or not | 
 | 	     */ | 
 | 	    res = valuePop(ctxt); | 
 | 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) { | 
 | 	        xmlXPtrLocationSetAdd(newset, | 
 | 			xmlXPathObjectCopy(oldset->locTab[i])); | 
 | 	    } | 
 |  | 
 | 	    /* | 
 | 	     * Cleanup | 
 | 	     */ | 
 | 	    if (res != NULL) | 
 | 		xmlXPathFreeObject(res); | 
 | 	    if (ctxt->value == tmp) { | 
 | 		res = valuePop(ctxt); | 
 | 		xmlXPathFreeObject(res); | 
 | 	    } | 
 | 	     | 
 | 	    ctxt->context->node = NULL; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * The result is used as the new evaluation set. | 
 | 	 */ | 
 | 	xmlXPathFreeObject(obj); | 
 | 	ctxt->context->node = NULL; | 
 | 	ctxt->context->contextSize = -1; | 
 | 	ctxt->context->proximityPosition = -1; | 
 | 	valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); | 
 |     } | 
 |     if (CUR != ']') { | 
 | 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); | 
 |     } | 
 |  | 
 |     NEXT; | 
 |     SKIP_BLANKS; | 
 | } | 
 |  | 
 | #else | 
 | #endif | 
 |  |