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