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