Going forward in XPointer implementation:
- testXPath.c xpath.[ch]: moved some debug functions to xpath core
- xpointer.c: implemented string-range() at least a good first version
- test/XPath/docs/str test/XPath/xptr/strrange
  result/XPath/xptr/strrange: the string-range() tests
Daniel
diff --git a/ChangeLog b/ChangeLog
index f2ea765..e8c3356 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Fri Oct 13 02:54:37 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org>
+
+	* testXPath.c xpath.[ch]: moved some debug functions to xpath core
+	* xpointer.c: implemented string-range() at least a good first version
+	* test/XPath/docs/str test/XPath/xptr/strrange
+	  result/XPath/xptr/strrange: the string-range() tests
+
 Thu Oct 12 10:02:59 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org>
 
 	* Makefile.am include/Makefile.am include/win32config.h
diff --git a/Makefile.am b/Makefile.am
index bff30d7..e837a14 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -345,6 +345,9 @@
 	-cp libxml.spec $(distdir)
 	(cd $(srcdir) ; tar -cf - --exclude CVS test result SAXresult ) | (cd $(distdir); tar xf -)
 
+rpm: $(distdir).tar.gz
+	rpm -ta $(distdir).tar.gz
+
 ## We create xmlConf.sh here and not from configure because we want
 ## to get the paths expanded correctly.  Macros like srcdir are given
 ## the value NONE in configure if the user doesn't specify them (this
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index 533ca3f..81a11f6 100644
--- a/include/libxml/xpath.h
+++ b/include/libxml/xpath.h
@@ -178,19 +178,19 @@
 
     int nb_variables;			/* number of defined variables */
     int max_variables;			/* max number of variables */
-    xmlXPathVariablePtr *variables;	/* Array of defined variables */
+    xmlXPathVariablePtr variables;	/* Array of defined variables */
 
     int nb_types;			/* number of defined types */
     int max_types;			/* max number of types */
-    xmlXPathTypePtr *types;		/* Array of defined types */
+    xmlXPathTypePtr types;		/* Array of defined types */
 
     int nb_funcs;			/* number of defined funcs */
     int max_funcs;			/* max number of funcs */
-    xmlXPathFuncPtr *funcs;		/* Array of defined funcs */
+    xmlXPathFuncPtr funcs;		/* Array of defined funcs */
 
     int nb_axis;			/* number of defined axis */
     int max_axis;			/* max number of axis */
-    xmlXPathAxisPtr *axis;		/* Array of defined axis */
+    xmlXPathAxisPtr axis;		/* Array of defined axis */
 
     /* Namespace traversal should be implemented with user */
     xmlNsPtr *namespaces;		/* The namespaces lookup */
@@ -266,6 +266,10 @@
 				 int line,
 				 int no);
 
+void		xmlXPathDebugDumpObject	(FILE *output,
+					 xmlXPathObjectPtr cur,
+					 int depth);
+
 /**
  * Utilities to extend XPath (XPointer)
  */
diff --git a/result/XPath/xptr/strrange b/result/XPath/xptr/strrange
new file mode 100644
index 0000000..c48ba43
--- /dev/null
+++ b/result/XPath/xptr/strrange
@@ -0,0 +1,76 @@
+
+========================
+Expression: xpointer(string-range(//p, 'simple'))
+Object is a Location Set:
+1 :   Object is a range :
+  From index 3 in node
+    TEXT
+      content=a simple test
+  To index 8 in node
+    TEXT
+      content=a simple test
+
+
+========================
+Expression: xpointer(string-range(//p, 'test'))
+Object is a Location Set:
+1 :   Object is a range :
+  From index 10 in node
+    TEXT
+      content=a simple test
+  To index 13 in node
+    TEXT
+      content=a simple test
+
+2 :   Object is a range :
+  From index 10 in node
+    TEXT
+      content=multiple tests
+  To index 13 in node
+    TEXT
+      content=multiple tests
+
+3 :   Object is a range :
+  From index 7 in node
+    TEXT
+      content=anced test
+  To index 10 in node
+    TEXT
+      content=anced test
+
+
+========================
+Expression: xpointer(string-range(//p, 'difficult'))
+Object is a Location Set:
+1 :   Object is a range :
+  From index 3 in node
+    TEXT
+      content=a diff
+  To index 4 in node
+    TEXT
+      content=cult one
+
+
+========================
+Expression: xpointer(string-range(//p, 'spanning'))
+Object is a Location Set:
+1 :   Object is a range :
+  From index 3 in node
+    TEXT
+      content=a span
+  To index 3 in node
+    TEXT
+      content=ing one
+
+
+========================
+Expression: xpointer(string-range(//p, 'unbalanced'))
+Object is a Location Set:
+1 :   Object is a range :
+  From index 8 in node
+    TEXT
+      content=and an unbal
+  To index 5 in node
+    TEXT
+      content=anced test
+
diff --git a/test/XPath/docs/str b/test/XPath/docs/str
new file mode 100644
index 0000000..7127ca2
--- /dev/null
+++ b/test/XPath/docs/str
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<chapter>
+  <p>a simple test</p>
+  <p>multiple tests</p>
+  <p>a diff<em>i</em>cult one</p>
+  <p><p>a span</p>n<p>ing one</p></p>
+  <p><p>and an unbal</p><empty/>anced test</p>
+</chapter>
diff --git a/test/XPath/xptr/strrange b/test/XPath/xptr/strrange
new file mode 100644
index 0000000..3c2aafc
--- /dev/null
+++ b/test/XPath/xptr/strrange
@@ -0,0 +1,5 @@
+xpointer(string-range(//p, 'simple'))
+xpointer(string-range(//p, 'test'))
+xpointer(string-range(//p, 'difficult'))
+xpointer(string-range(//p, 'spanning'))
+xpointer(string-range(//p, 'unbalanced'))
diff --git a/testXPath.c b/testXPath.c
index 1133d4c..c226cf0 100644
--- a/testXPath.c
+++ b/testXPath.c
@@ -84,146 +84,6 @@
 </EXAMPLE>\n\
 ";
 
-void xmlXPAthDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
-    int i;
-    char shift[100];
-
-    for (i = 0;((i < depth) && (i < 25));i++)
-        shift[2 * i] = shift[2 * i + 1] = ' ';
-    shift[2 * i] = shift[2 * i + 1] = 0;
-    if (cur == NULL) {
-	fprintf(output, shift);
-	fprintf(output, "Node is NULL !\n");
-	return;
-        
-    }
-
-    if ((cur->type == XML_DOCUMENT_NODE) ||
-	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
-	fprintf(output, shift);
-	fprintf(output, " /\n");
-    } else if (cur->type == XML_ATTRIBUTE_NODE)
-	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
-    else
-	xmlDebugDumpOneNode(output, cur, depth);
-}
-
-void xmlXPAthDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
-    int i;
-    char shift[100];
-
-    for (i = 0;((i < depth) && (i < 25));i++)
-        shift[2 * i] = shift[2 * i + 1] = ' ';
-    shift[2 * i] = shift[2 * i + 1] = 0;
-
-    if (cur == NULL) {
-	fprintf(output, shift);
-	fprintf(output, "NodeSet is NULL !\n");
-	return;
-        
-    }
-
-    fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
-    for (i = 0;i < cur->nodeNr;i++) {
-	fprintf(output, shift);
-        fprintf(output, "%d", i + 1);
-	xmlXPAthDebugDumpNode(output, cur->nodeTab[i], depth + 1);
-    }
-}
-
-#if defined(LIBXML_XPTR_ENABLED)
-void xmlXPAthDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
-void xmlXPAthDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
-    int i;
-    char shift[100];
-
-    for (i = 0;((i < depth) && (i < 25));i++)
-        shift[2 * i] = shift[2 * i + 1] = ' ';
-    shift[2 * i] = shift[2 * i + 1] = 0;
-
-    if (cur == NULL) {
-	fprintf(output, shift);
-	fprintf(output, "LocationSet is NULL !\n");
-	return;
-        
-    }
-
-    for (i = 0;i < cur->locNr;i++) {
-	fprintf(output, shift);
-        fprintf(output, "%d : ", i + 1);
-	xmlXPAthDebugDumpObject(output, cur->locTab[i], depth + 1);
-    }
-}
-#endif
-
-void xmlXPAthDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
-    int i;
-    char shift[100];
-
-    for (i = 0;((i < depth) && (i < 25));i++)
-        shift[2 * i] = shift[2 * i + 1] = ' ';
-    shift[2 * i] = shift[2 * i + 1] = 0;
-
-    fprintf(output, shift);
-
-    if (cur == NULL) {
-        fprintf(output, "Object is empty (NULL)\n");
-	return;
-    }
-    switch(cur->type) {
-        case XPATH_UNDEFINED:
-	    fprintf(output, "Object is uninitialized\n");
-	    break;
-        case XPATH_NODESET:
-	    fprintf(output, "Object is a Node Set :\n");
-	    xmlXPAthDebugDumpNodeSet(output, cur->nodesetval, depth);
-	    break;
-        case XPATH_BOOLEAN:
-	    fprintf(output, "Object is a Boolean : ");
-	    if (cur->boolval) fprintf(output, "true\n");
-	    else fprintf(output, "false\n");
-	    break;
-        case XPATH_NUMBER:
-	    fprintf(output, "Object is a number : %0g\n", cur->floatval);
-	    break;
-        case XPATH_STRING:
-	    fprintf(output, "Object is a string : ");
-	    xmlDebugDumpString(output, cur->stringval);
-	    fprintf(output, "\n");
-	    break;
-	case XPATH_POINT:
-	    fprintf(output, "Object is a point : index %d in node", cur->index);
-	    xmlXPAthDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
-	    fprintf(output, "\n");
-	    break;
-	case XPATH_RANGE:
-	    fprintf(output, "Object is a range :\n");
-	    fprintf(output, shift);
-	    fprintf(output, "From ");
-	    if (cur->index >= 0)
-		fprintf(output, "index %d in ", cur->index);
-	    fprintf(output, "node\n");
-	    xmlXPAthDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
-	    fprintf(output, shift);
-	    fprintf(output, "To ");
-	    if (cur->index2 >= 0)
-		fprintf(output, "index %d in ", cur->index2);
-	    fprintf(output, "node\n");
-	    xmlXPAthDebugDumpNode(output, (xmlNodePtr) cur->user2, depth + 1);
-	    fprintf(output, "\n");
-	    break;
-	case XPATH_LOCATIONSET:
-#if defined(LIBXML_XPTR_ENABLED)
-	    fprintf(output, "Object is a Location Set:\n");
-	    xmlXPAthDebugDumpLocationSet(output,
-		    (xmlLocationSetPtr) cur->user, depth);
-#endif
-	    break;
-	case XPATH_USERS:
-	    fprintf(output, "Object is user defined\n");
-	    break;
-    }
-}
 
 void testXPath(const char *str) {
     xmlXPathObjectPtr res;
@@ -243,7 +103,7 @@
 #if defined(LIBXML_XPTR_ENABLED)
     }
 #endif
-    xmlXPAthDebugDumpObject(stdout, res, 0);
+    xmlXPathDebugDumpObject(stdout, res, 0);
     xmlXPathFreeObject(res);
     xmlXPathFreeContext(ctxt);
 }
diff --git a/xpath.c b/xpath.c
index 83b7087..371ecbb 100644
--- a/xpath.c
+++ b/xpath.c
@@ -52,11 +52,17 @@
 #ifdef LIBXML_XPTR_ENABLED
 #include <libxml/xpointer.h>
 #endif
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
 
 /* #define DEBUG */
 /* #define DEBUG_STEP */
 /* #define DEBUG_EXPR */
 
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+double xmlXPathStringEvalNumber(const xmlChar *str);
+
 /*
  * Setup stuff for floating point
  * The lack of portability of this section of the libc is annoying !
@@ -159,17 +165,14 @@
     initialized = 1;
 }
 
-FILE *xmlXPathDebug = NULL;
-
-double xmlXPathStringEvalNumber(const xmlChar *str);
-void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
-
 /************************************************************************
  *									*
- * 		Parser stacks related functions and macros		*
+ * 		Debugging related functions				*
  *									*
  ************************************************************************/
 
+FILE *xmlXPathDebug = NULL;
+
 #define TODO 								\
     fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n",		\
             __FILE__, __LINE__);
@@ -178,6 +181,171 @@
     fprintf(xmlXPathDebug, "Internal error at %s:%d\n",			\
             __FILE__, __LINE__);
 
+#ifdef LIBXML_DEBUG_ENABLED
+double xmlXPathStringEvalNumber(const xmlChar *str);
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+
+void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+    if (cur == NULL) {
+	fprintf(output, shift);
+	fprintf(output, "Node is NULL !\n");
+	return;
+        
+    }
+
+    if ((cur->type == XML_DOCUMENT_NODE) ||
+	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	fprintf(output, shift);
+	fprintf(output, " /\n");
+    } else if (cur->type == XML_ATTRIBUTE_NODE)
+	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
+    else
+	xmlDebugDumpOneNode(output, cur, depth);
+}
+
+void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    if (cur == NULL) {
+	fprintf(output, shift);
+	fprintf(output, "NodeSet is NULL !\n");
+	return;
+        
+    }
+
+    fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
+    for (i = 0;i < cur->nodeNr;i++) {
+	fprintf(output, shift);
+        fprintf(output, "%d", i + 1);
+	xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
+    }
+}
+
+#if defined(LIBXML_XPTR_ENABLED)
+void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
+void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    if (cur == NULL) {
+	fprintf(output, shift);
+	fprintf(output, "LocationSet is NULL !\n");
+	return;
+        
+    }
+
+    for (i = 0;i < cur->locNr;i++) {
+	fprintf(output, shift);
+        fprintf(output, "%d : ", i + 1);
+	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
+    }
+}
+#endif
+
+void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    if (cur == NULL) {
+        fprintf(output, "Object is empty (NULL)\n");
+	return;
+    }
+    switch(cur->type) {
+        case XPATH_UNDEFINED:
+	    fprintf(output, "Object is uninitialized\n");
+	    break;
+        case XPATH_NODESET:
+	    fprintf(output, "Object is a Node Set :\n");
+	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
+	    break;
+        case XPATH_BOOLEAN:
+	    fprintf(output, "Object is a Boolean : ");
+	    if (cur->boolval) fprintf(output, "true\n");
+	    else fprintf(output, "false\n");
+	    break;
+        case XPATH_NUMBER:
+	    fprintf(output, "Object is a number : %0g\n", cur->floatval);
+	    break;
+        case XPATH_STRING:
+	    fprintf(output, "Object is a string : ");
+	    xmlDebugDumpString(output, cur->stringval);
+	    fprintf(output, "\n");
+	    break;
+	case XPATH_POINT:
+	    fprintf(output, "Object is a point : index %d in node", cur->index);
+	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
+	    fprintf(output, "\n");
+	    break;
+	case XPATH_RANGE:
+	    if ((cur->user2 == NULL) ||
+		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
+		fprintf(output, "Object is a collapsed range :\n");
+		fprintf(output, shift);
+		if (cur->index >= 0)
+		    fprintf(output, "index %d in ", cur->index);
+		fprintf(output, "node\n");
+		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
+			              depth + 1);
+	    } else  {
+		fprintf(output, "Object is a range :\n");
+		fprintf(output, shift);
+		fprintf(output, "From ");
+		if (cur->index >= 0)
+		    fprintf(output, "index %d in ", cur->index);
+		fprintf(output, "node\n");
+		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
+			              depth + 1);
+		fprintf(output, shift);
+		fprintf(output, "To ");
+		if (cur->index2 >= 0)
+		    fprintf(output, "index %d in ", cur->index2);
+		fprintf(output, "node\n");
+		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
+			              depth + 1);
+		fprintf(output, "\n");
+	    }
+	    break;
+	case XPATH_LOCATIONSET:
+#if defined(LIBXML_XPTR_ENABLED)
+	    fprintf(output, "Object is a Location Set:\n");
+	    xmlXPathDebugDumpLocationSet(output,
+		    (xmlLocationSetPtr) cur->user, depth);
+#endif
+	    break;
+	case XPATH_USERS:
+	    fprintf(output, "Object is user defined\n");
+	    break;
+    }
+}
+#endif
+
+/************************************************************************
+ *									*
+ * 		Parser stacks related functions and macros		*
+ *									*
+ ************************************************************************/
+
 /*
  * Generic function for accessing stacks in the Parser Context
  */
@@ -672,30 +840,31 @@
 	return(-1);
 
     for (i = 0;i < ctxt->nb_funcs;i++) {
-	if (xmlStrEqual(ctxt->funcs[i]->name, name)) {
+	if (xmlStrEqual(ctxt->funcs[i].name, name)) {
 	    /*
 	     * It's just an update or a removal
 	     */
-	    ctxt->funcs[i]->func = f;
+	    ctxt->funcs[i].func = f;
 	    return(0);
 	}
     }
     if (ctxt->max_funcs <= 0) {
 	ctxt->max_funcs = 10;
 	ctxt->nb_funcs = 0;
-	ctxt->funcs = (xmlXPathFuncPtr *) xmlMalloc(ctxt->max_funcs *
-		                                    sizeof(xmlXPathFuncPtr));
+	ctxt->funcs = (xmlXPathFuncPtr) xmlMalloc(ctxt->max_funcs *
+		                                    sizeof(xmlXPathFunct));
     } else if (ctxt->max_funcs <= ctxt->nb_funcs) {
 	ctxt->max_funcs *= 2;
-	ctxt->funcs = (xmlXPathFuncPtr *) xmlRealloc(ctxt->funcs,
-		                  ctxt->max_funcs * sizeof(xmlXPathFuncPtr));
+	ctxt->funcs = (xmlXPathFuncPtr) xmlRealloc(ctxt->funcs,
+		                  ctxt->max_funcs * sizeof(xmlXPathFunct));
     }
     if (ctxt->funcs == NULL) {
         fprintf(xmlXPathDebug, "xmlXPathRegisterFunc: out of memory\n");
 	return(-1);
     }
-    ctxt->funcs[i]->name = xmlStrdup(name);
-    ctxt->funcs[i]->func = f;
+    ctxt->funcs[ctxt->nb_funcs].name = xmlStrdup(name);
+    ctxt->funcs[ctxt->nb_funcs].func = f;
+    ctxt->nb_funcs++;
     return(0);
 }
 
@@ -719,8 +888,8 @@
 	return(NULL);
 
     for (i = 0;i < ctxt->nb_funcs;i++) {
-	if (xmlStrEqual(ctxt->funcs[i]->name, name)) {
-	    return(ctxt->funcs[i]->func);
+	if (xmlStrEqual(ctxt->funcs[i].name, name)) {
+	    return(ctxt->funcs[i].func);
 	}
     }
     return(NULL);
@@ -740,7 +909,7 @@
 	return;
 
     for (i = 0;i < ctxt->nb_funcs;i++) {
-	xmlFree((xmlChar *) ctxt->funcs[i]->name);
+	xmlFree((xmlChar *) ctxt->funcs[i].name);
     }
     ctxt->nb_funcs = -1;
     ctxt->max_funcs = -1;
@@ -777,34 +946,35 @@
 	return(-1);
 
     for (i = 0;i < ctxt->nb_variables;i++) {
-	if (xmlStrEqual(ctxt->variables[i]->name, name)) {
+	if (xmlStrEqual(ctxt->variables[i].name, name)) {
 	    /*
 	     * It's just an update or a removal
 	     */
-	    if (ctxt->variables[i]->value != NULL) {
-		xmlXPathFreeObject(ctxt->variables[i]->value);
+	    if (ctxt->variables[i].value != NULL) {
+		xmlXPathFreeObject(ctxt->variables[i].value);
 	    }
-	    ctxt->variables[i]->value = xmlXPathObjectCopy(value);
+	    ctxt->variables[i].value = xmlXPathObjectCopy(value);
 	    return(0);
 	}
     }
     if (ctxt->max_variables <= 0) {
 	ctxt->max_variables = 10;
 	ctxt->nb_variables = 0;
-	ctxt->variables = (xmlXPathVariablePtr *)
-	    xmlMalloc(ctxt->max_variables * sizeof(xmlXPathVariablePtr));
+	ctxt->variables = (xmlXPathVariablePtr)
+	    xmlMalloc(ctxt->max_variables * sizeof(xmlXPathVariable));
     } else if (ctxt->max_variables <= ctxt->nb_variables) {
 	ctxt->max_variables *= 2;
-	ctxt->variables = (xmlXPathVariablePtr *)
+	ctxt->variables = (xmlXPathVariablePtr)
 	    xmlRealloc(ctxt->variables,
-		       ctxt->max_variables * sizeof(xmlXPathVariablePtr));
+		       ctxt->max_variables * sizeof(xmlXPathVariable));
     }
     if (ctxt->variables == NULL) {
         fprintf(xmlXPathDebug, "xmlXPathRegisterVariable: out of memory\n");
 	return(-1);
     }
-    ctxt->variables[i]->name = xmlStrdup(name);
-    ctxt->variables[i]->value = xmlXPathObjectCopy(value);
+    ctxt->variables[ctxt->nb_variables].name = xmlStrdup(name);
+    ctxt->variables[ctxt->nb_variables].value = xmlXPathObjectCopy(value);
+    ctxt->nb_variables++;
     return(0);
 }
 
@@ -828,8 +998,8 @@
 	return(NULL);
 
     for (i = 0;i < ctxt->nb_variables;i++) {
-	if (xmlStrEqual(ctxt->variables[i]->name, name)) {
-	    return(xmlXPathObjectCopy(ctxt->variables[i]->value));
+	if (xmlStrEqual(ctxt->variables[i].name, name)) {
+	    return(xmlXPathObjectCopy(ctxt->variables[i].value));
 	}
     }
     return(NULL);
@@ -849,8 +1019,8 @@
 	return;
 
     for (i = 0;i < ctxt->nb_variables;i++) {
-	xmlFree((xmlChar *) ctxt->variables[i]->name);
-	xmlXPathFreeObject(ctxt->variables[i]->value);
+	xmlFree((xmlChar *) ctxt->variables[i].name);
+	xmlXPathFreeObject(ctxt->variables[i].value);
     }
     ctxt->nb_variables = -1;
     ctxt->max_variables = -1;
diff --git a/xpath.h b/xpath.h
index 533ca3f..81a11f6 100644
--- a/xpath.h
+++ b/xpath.h
@@ -178,19 +178,19 @@
 
     int nb_variables;			/* number of defined variables */
     int max_variables;			/* max number of variables */
-    xmlXPathVariablePtr *variables;	/* Array of defined variables */
+    xmlXPathVariablePtr variables;	/* Array of defined variables */
 
     int nb_types;			/* number of defined types */
     int max_types;			/* max number of types */
-    xmlXPathTypePtr *types;		/* Array of defined types */
+    xmlXPathTypePtr types;		/* Array of defined types */
 
     int nb_funcs;			/* number of defined funcs */
     int max_funcs;			/* max number of funcs */
-    xmlXPathFuncPtr *funcs;		/* Array of defined funcs */
+    xmlXPathFuncPtr funcs;		/* Array of defined funcs */
 
     int nb_axis;			/* number of defined axis */
     int max_axis;			/* max number of axis */
-    xmlXPathAxisPtr *axis;		/* Array of defined axis */
+    xmlXPathAxisPtr axis;		/* Array of defined axis */
 
     /* Namespace traversal should be implemented with user */
     xmlNsPtr *namespaces;		/* The namespaces lookup */
@@ -266,6 +266,10 @@
 				 int line,
 				 int no);
 
+void		xmlXPathDebugDumpObject	(FILE *output,
+					 xmlXPathObjectPtr cur,
+					 int depth);
+
 /**
  * Utilities to extend XPath (XPointer)
  */
diff --git a/xpointer.c b/xpointer.c
index 2756057..3403bc3 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -18,6 +18,10 @@
 /**
  * TODO: better handling of error cases, the full expression should
  *       be parsed beforehand instead of a progressive evaluation
+ * TODO: Access into entities references are not supported now ...
+ *       need a start to be able to pop out of entities refs since
+ *       parent is the endity declaration, not the ref.
+ * TODO: some functions are still missing !
  */
 
 #include <stdio.h>
@@ -25,8 +29,15 @@
 #include <libxml/xmlmemory.h>
 #include <libxml/parserInternals.h>
 #include <libxml/xpath.h>
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
 
 #ifdef LIBXML_XPTR_ENABLED
+
+/* #define DEBUG_RANGES */
+
+
 extern FILE *xmlXPathDebug;
 
 #define TODO 								\
@@ -74,6 +85,45 @@
 }
 
 /**
+ * xmlXPtrNewRange:
+ * @start:  the starting node
+ * @startindex:  the start index
+ * @end:  the ending point
+ * @endindex:  the ending index
+ *
+ * Create a new xmlXPathObjectPtr of type range
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRange(xmlNodePtr start, int startindex,
+	        xmlNodePtr end, int endindex) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+    if (startindex < 0)
+	return(NULL);
+    if (endindex < 0)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        fprintf(xmlXPathDebug, "xmlXPtrNewRangePoints: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start;
+    ret->index = startindex;
+    ret->user2 = end;
+    ret->index2 = endindex;
+    return(ret);
+}
+
+/**
  * xmlXPtrNewRangePoints:
  * @start:  the starting point
  * @end:  the ending point
@@ -381,11 +431,10 @@
 
 /**
  * xmlXPtrLocationSetMerge:
- * @val1:  the first LocationSet or NULL
+ * @val1:  the first LocationSet
  * @val2:  the second LocationSet
  *
  * Merges two rangesets, all ranges from @val2 are added to @val1
- * if @val1 is NULL, a new set is created and copied from @val2
  *
  * Returns val1 once extended or NULL in case of error.
  */
@@ -393,12 +442,8 @@
 xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
     int i;
 
+    if (val1 == NULL) return(NULL);
     if (val2 == NULL) return(val1);
-    if (val1 == NULL) {
-	val1 = xmlXPtrLocationSetCreate(NULL);
-	if (val1 == NULL)
-	    return(NULL);
-    }
 
     /*
      * !!!!! this can be optimized a lot, knowing that both
@@ -661,6 +706,33 @@
 #define CURRENT (*ctxt->cur)
 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
 
+/**
+ * xmlXPtrGetNthChild:
+ * @cur:  the node
+ * @no:  the child number
+ *
+ * Returns the @no'th element child of @cur or NULL
+ */
+xmlNodePtr
+xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
+    int i;
+    if (cur == NULL) 
+	return(cur);
+    cur = cur->children;
+    for (i = 0;i <= no;cur = cur->next) {
+	if (cur == NULL) 
+	    return(cur);
+	if ((cur->type == XML_ELEMENT_NODE) ||
+	    (cur->type == XML_DOCUMENT_NODE) ||
+	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	    i++;
+	    if (i == no)
+		break;
+	}
+    }
+    return(cur);
+}
+
 /*
  * xmlXPtrGetChildNo:
  * @ctxt:  the XPointer Parser context
@@ -674,7 +746,6 @@
     xmlNodePtr cur = NULL;
     xmlXPathObjectPtr obj;
     xmlNodeSetPtr oldset;
-    int i;
 
     CHECK_TYPE(XPATH_NODESET);
     obj = valuePop(ctxt);
@@ -684,23 +755,7 @@
 	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
 	return;
     }
-    cur = oldset->nodeTab[0];
-    if (cur == NULL) 
-	goto done;
-    cur = cur->children;
-    for (i = 0;i <= index;cur = cur->next) {
-	if (cur == NULL) 
-	    goto done;
-	if ((cur->type == XML_ELEMENT_NODE) ||
-	    (cur->type == XML_DOCUMENT_NODE) ||
-	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
-	    i++;
-	    if (i == index)
-		break;
-	}
-    }
-
-done:
+    cur = xmlXPtrGetNthChild(oldset->nodeTab[0], index);
     if (cur == NULL) {
 	xmlXPathFreeObject(obj);
 	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
@@ -802,13 +857,9 @@
 
     if (xmlStrEqual(name, (xmlChar *) "xpointer")) {
 	const xmlChar *left = CUR_PTR;
-	xmlXPathObjectPtr root = NULL;
 
 	CUR_PTR = buffer;
-	if (buffer[0] == '/') {
-	    xmlXPathRoot(ctxt);
-	    root = ctxt->value;
-	}
+	xmlXPathRoot(ctxt);
 	xmlXPathEvalExpr(ctxt);
 	CUR_PTR=left;
     } else {
@@ -986,6 +1037,13 @@
  *									*
  ************************************************************************/
 
+void xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
+
 /**
  * xmlXPtrNewContext:
  * @doc:  the XML document
@@ -1008,6 +1066,19 @@
     ret->here = here;
     ret->origin = origin;
 
+    xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
+	                 xmlXPtrRangeToFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
+	                 xmlXPtrStringRangeFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
+	                 xmlXPtrStartPointFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
+	                 xmlXPtrEndPointFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"here",
+	                 xmlXPtrHereFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
+	                 xmlXPtrOriginFunction);
+
     return(ret);
 }
 
@@ -1054,9 +1125,20 @@
     do {
         tmp = valuePop(ctxt);
 	if (tmp != NULL) {
+	    if (tmp != init) {
+		if (tmp->type == XPATH_NODESET) {
+		    /*
+		     * Evaluation may push a root nodeset which is unused
+		     */
+		    xmlNodeSetPtr set; 
+		    set = tmp->nodesetval;
+		    if ((set->nodeNr != 1) ||
+			(set->nodeTab[0] != (xmlNodePtr) ctx->doc))
+			stack++;
+		} else
+		    stack++;    
+	    }
 	    xmlXPathFreeObject(tmp);
-	    if (tmp != init)
-		stack++;    
         }
     } while (tmp != NULL);
     if (stack != 0) {
@@ -1125,14 +1207,14 @@
 }
 
 /**
- * xmlXPtrHere:
+ * xmlXPtrHereFunction:
  * @ctxt:  the XPointer Parser context
  *
  * Function implementing here() operation 
  * as described in 5.4.3
  */
 void
-xmlXPtrHere(xmlXPathParserContextPtr ctxt, int nargs) {
+xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     if (ctxt->context->here == NULL)
 	XP_ERROR(XPTR_SYNTAX_ERROR);
     
@@ -1140,14 +1222,14 @@
 }
 
 /**
- * xmlXPtrOrigin:
+ * xmlXPtrOriginFunction:
  * @ctxt:  the XPointer Parser context
  *
  * Function implementing origin() operation 
  * as described in 5.4.3
  */
 void
-xmlXPtrOrigin(xmlXPathParserContextPtr ctxt, int nargs) {
+xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     if (ctxt->context->origin == NULL)
 	XP_ERROR(XPTR_SYNTAX_ERROR);
     
@@ -1155,7 +1237,7 @@
 }
 
 /**
- * xmlXPtrStartPoint:
+ * xmlXPtrStartPointFunction:
  * @ctxt:  the XPointer Parser context
  *
  * Function implementing start-point() operation 
@@ -1177,7 +1259,7 @@
  *
  */
 void
-xmlXPtrStartPoint(xmlXPathParserContextPtr ctxt, int nargs) {
+xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathObjectPtr tmp, obj, point;
     xmlLocationSetPtr newset = NULL;
     xmlLocationSetPtr oldset = NULL;
@@ -1245,7 +1327,7 @@
 }
 
 /**
- * xmlXPtrEndPoint:
+ * xmlXPtrEndPointFunction:
  * @ctxt:  the XPointer Parser context
  *
  * Function implementing end-point() operation 
@@ -1269,7 +1351,7 @@
  * ----------------------------
  */
 void
-xmlXPtrEndPoint(xmlXPathParserContextPtr ctxt, int nargs) {
+xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathObjectPtr tmp, obj, point;
     xmlLocationSetPtr newset = NULL;
     xmlLocationSetPtr oldset = NULL;
@@ -1426,6 +1508,528 @@
     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
 }
 
+/**
+ * xmlXPtrAdvanceNode:
+ * @cur:  the node
+ *
+ * Advance to the next element or text node in document order
+ * TODO: add a stack for entering/exiting entities 
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+xmlNodePtr
+xmlXPtrAdvanceNode(xmlNodePtr cur) {
+next:
+    if (cur == NULL)
+	return(NULL);
+    if (cur->children != NULL) {
+        cur = cur->children ;
+	goto found;
+    }
+    if (cur->next != NULL) {
+	cur = cur->next;
+	goto found;
+    }
+    do {
+        cur = cur->parent;
+        if (cur == NULL) return(NULL);
+        if (cur->next != NULL) {
+	    cur = cur->next;
+	    goto found;
+	}
+    } while (cur != NULL);
+
+found:
+    if ((cur->type != XML_ELEMENT_NODE) &&
+	(cur->type != XML_TEXT_NODE) &&
+	(cur->type != XML_DOCUMENT_NODE) &&
+	(cur->type != XML_HTML_DOCUMENT_NODE) &&
+	(cur->type != XML_CDATA_SECTION_NODE))
+	goto next;
+    if (cur->type == XML_ENTITY_REF_NODE) {
+	TODO
+    }
+    return(cur);
+}
+
+/**
+ * xmlXPtrAdvanceChar:
+ * @node:  the node
+ * @index:  the index
+ * @bytes:  the number of bytes
+ *
+ * Advance a point of the associated number of bytes (not UTF8 chars)
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrAdvanceChar(xmlNodePtr *node, int *index, int bytes) {
+    xmlNodePtr cur;
+    int pos;
+    int len;
+
+    if ((node == NULL) || (index == NULL))
+	return(-1);
+    cur = *node;
+    if (cur == NULL)
+	return(-1);
+    pos = *index;
+
+    while (bytes >= 0) {
+	/*
+	 * First position to the beginning of the first text node
+	 * corresponding to this point
+	 */
+	while ((cur != NULL) &&
+	       ((cur->type == XML_ELEMENT_NODE) ||
+	        (cur->type == XML_DOCUMENT_NODE) ||
+	        (cur->type == XML_HTML_DOCUMENT_NODE))) {
+	    if (pos > 0) {
+		cur = xmlXPtrGetNthChild(cur, pos);
+		pos = 0;
+	    } else {
+		cur = xmlXPtrAdvanceNode(cur);
+		pos = 0;
+	    }
+	}
+	if (cur == NULL) {
+	    *node = NULL;
+	    *index = 0;
+	    return(-1);
+	}
+
+	/*
+	 * if there is no move needed return the current value.
+	 */
+	if (pos == 0) pos = 1;
+	if (bytes == 0) {
+	    *node = cur;
+	    *index = pos;
+	    return(0);
+	}
+	/*
+	 * We should have a text (or cdata) node ... 
+	 */
+	len = 0;
+	if (cur->content != NULL) {
+	    len = xmlStrlen(cur->content);
+	}
+	if (pos > len) {
+	    /* Strange, the index in the text node is greater than it's len */
+	    STRANGE
+	    pos = len;
+	}
+	if (pos + bytes >= len) {
+	    bytes -= (len - pos);
+	    cur = xmlXPtrAdvanceNode(cur);
+	    cur = 0;
+	}
+    }
+    return(-1);
+}
+
+/**
+ * xmlXPtrMatchString:
+ * @string:  the string to search
+ * @start:  the start textnode
+ * @startindex:  the start index
+ * @end:  the end textnode IN/OUT
+ * @endindex:  the end index IN/OUT
+ *
+ * Check whether the document contains @string at the position
+ * (@start, @startindex) and limited by the (@end, @endindex) point
+ *
+ * Returns -1 in case of failure, 0 if not found, 1 if found in which case
+ *            (@start, @startindex) will indicate the position of the beginning
+ *            of the range and (@end, @endindex) will endicate the end
+ *            of the range
+ */
+int
+xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
+	            xmlNodePtr *end, int *endindex) {
+    xmlNodePtr cur;
+    int pos; /* 0 based */
+    int len; /* in bytes */
+    int stringlen; /* in bytes */
+    int match;
+
+    if (string == NULL)
+	return(-1);
+    if (start == NULL)
+	return(-1);
+    if ((end == NULL) || (endindex == NULL))
+	return(-1);
+    cur = start;
+    if (cur == NULL)
+	return(-1);
+    pos = startindex - 1;
+    stringlen = xmlStrlen(string);
+
+    while (stringlen > 0) {
+	if ((cur == *end) && (pos + stringlen > *endindex))
+	    return(0);
+	if (cur->content != NULL) {
+	    len = xmlStrlen(cur->content);
+	    if (len >= pos + stringlen) {
+		match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
+		if (match) {
+#ifdef DEBUG_RANGES
+		    fprintf(stdout, "found range %d bytes at index %d of ->",
+			    stringlen, pos + 1);
+		    xmlDebugDumpString(stdout, cur->content);
+		    fprintf(stdout, "\n");
+#endif
+		    *end = cur;
+		    *endindex = pos + stringlen;
+		    return(1);
+		} else {
+		    return(0);
+		}
+	    } else {
+                int sub = len - pos;
+		match = (!xmlStrncmp(&cur->content[pos], string, sub));
+		if (match) {
+#ifdef DEBUG_RANGES
+		    fprintf(stdout, "found subrange %d bytes at index %d of ->",
+			    sub, pos + 1);
+		    xmlDebugDumpString(stdout, cur->content);
+		    fprintf(stdout, "\n");
+#endif
+                    string = &string[sub];
+		    stringlen -= sub;
+		} else {
+		    return(0);
+		}
+	    }
+	}
+	cur = xmlXPtrAdvanceNode(cur);
+	if (cur == NULL)
+	    return(0);
+	pos = 0;
+    }
+    return(1);
+}
+
+/**
+ * xmlXPtrSearchString:
+ * @string:  the string to search
+ * @start:  the start textnode IN/OUT
+ * @startindex:  the start index IN/OUT
+ * @end:  the end textnode
+ * @endindex:  the end index
+ *
+ * Search the next occurence of @string within the document content
+ * until the (@end, @endindex) point is reached
+ *
+ * Returns -1 in case of failure, 0 if not found, 1 if found in which case
+ *            (@start, @startindex) will indicate the position of the beginning
+ *            of the range and (@end, @endindex) will endicate the end
+ *            of the range
+ */
+int
+xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
+	            xmlNodePtr *end, int *endindex) {
+    xmlNodePtr cur;
+    const xmlChar *str;
+    int pos; /* 0 based */
+    int len; /* in bytes */
+    int stringlen; /* in bytes */
+    xmlChar first;
+
+    if (string == NULL)
+	return(-1);
+    if ((start == NULL) || (startindex == NULL))
+	return(-1);
+    if ((end == NULL) || (endindex == NULL))
+	return(-1);
+    cur = *start;
+    if (cur == NULL)
+	return(-1);
+    pos = *startindex - 1;
+    first = string[0];
+    stringlen = xmlStrlen(string);
+
+    /* TODO: first = 0 */
+    while (cur != NULL) {
+	if (cur->content != NULL) {
+	    len = xmlStrlen(cur->content);
+	    while (pos <= len) {
+		str = xmlStrchr(&cur->content[pos], first);
+		if (str != NULL) {
+		    pos = (str - cur->content);
+#ifdef DEBUG_RANGES
+		    fprintf(stdout, "found '%c' at index %d of ->",
+			    first, pos + 1);
+		    xmlDebugDumpString(stdout, cur->content);
+		    fprintf(stdout, "\n");
+#endif
+		    if (xmlXPtrMatchString(string, cur, pos + 1,
+				           end, endindex)) {
+			*start = cur;
+			*startindex = pos + 1;
+			return(1);
+		    }
+		    pos++;
+		} else {
+		    pos = len + 1;
+		}
+	    }
+	}
+	if ((cur == *end) && (pos >= *endindex))
+	    return(0);
+	cur = xmlXPtrAdvanceNode(cur);
+	if (cur == NULL)
+	    return(0);
+	pos = 1;
+    }
+    return(0);
+}
+
+/**
+ * xmlXPtrGetLastChar:
+ * @node:  the node
+ * @index:  the index
+ *
+ * Computes the point coordinates of the last char of this point
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrGetLastChar(xmlNodePtr *node, int *index) {
+    xmlNodePtr cur;
+    int pos, len = 0;
+
+    if ((node == NULL) || (index == NULL))
+	return(-1);
+    cur = *node;
+    pos = *index;
+
+    if (cur == NULL)
+	return(-1);
+    
+    if ((cur->type == XML_ELEMENT_NODE) ||
+	(cur->type == XML_DOCUMENT_NODE) ||
+	(cur->type == XML_HTML_DOCUMENT_NODE)) {
+	if (pos > 0) {
+	    cur = xmlXPtrGetNthChild(cur, pos);
+	    pos = 0;
+	}
+    }
+    while (cur != NULL) {
+	if (cur->last != NULL)
+	    cur = cur->last;
+	else if (cur->content != NULL) {
+	    len = xmlStrlen(cur->content);
+	    break;
+	}
+    }
+    if (cur == NULL)
+	return(-1);
+    *node = cur;
+    *index = len;
+    return(0);
+}
+
+/**
+ * xmlXPtrGetStartPoint:
+ * @obj:  an range
+ * @node:  the resulting node
+ * @index:  the resulting index
+ *
+ * read the object and return the start point coordinates.
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *index) {
+    if ((obj == NULL) || (node == NULL) || (index == NULL))
+	return(-1);
+
+    switch (obj->type) {
+        case XPATH_POINT:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+        case XPATH_RANGE:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+	default:
+	    return(-1);
+    }
+    return(-1);
+}
+
+/**
+ * xmlXPtrGetEndPoint:
+ * @obj:  an range
+ * @node:  the resulting node
+ * @index:  the resulting index
+ *
+ * read the object and return the end point coordinates.
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *index) {
+    if ((obj == NULL) || (node == NULL) || (index == NULL))
+	return(-1);
+
+    switch (obj->type) {
+        case XPATH_POINT:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+        case XPATH_RANGE:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+	default:
+	    return(-1);
+    }
+    return(-1);
+}
+
+/**
+ * xmlXPtrStringRangeFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing the string-range() function
+ * range as described in 5.4.2 
+ *
+ * ------------------------------
+ * [Definition: For each location in the location-set argument,
+ * string-range returns a set of string ranges, a set of substrings in a
+ * string. Specifically, the string-value of the location is searched for
+ * substrings that match the string argument, and the resulting location-set
+ * will contain a range location for each non-overlapping match.]
+ * An empty string is considered to match before each character of the
+ * string-value and after the final character. Whitespace in a string
+ * is matched literally, with no normalization except that provided by
+ * XML for line ends. The third argument gives the position of the first
+ * character to be in the resulting range, relative to the start of the
+ * match. The default value is 1, which makes the range start immediately
+ * before the first character of the matched string. The fourth argument
+ * gives the number of characters in the range; the default is that the
+ * range extends to the end of the matched string.
+ *
+ * Element boundaries, as well as entire embedded nodes such as processing
+ * instructions and comments, are ignored as defined in [XPath].
+ *
+ * If the string in the second argument is not found in the string-value
+ * of the location, or if a value in the third or fourth argument indicates
+ * a string that is beyond the beginning or end of the document, the
+ * expression fails.
+ *
+ * The points of the range-locations in the returned location-set will
+ * all be character points.
+ * ------------------------------
+ */
+void
+xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    int i, startindex, endindex, fendindex;
+    xmlNodePtr start, end, fend;
+    xmlXPathObjectPtr set;
+    xmlLocationSetPtr oldset;
+    xmlLocationSetPtr newset;
+    xmlXPathObjectPtr string;
+    xmlXPathObjectPtr position = NULL;
+    xmlXPathObjectPtr number = NULL;
+    int found;
+
+    /*
+     * Grab the arguments
+     */
+    if ((nargs < 2) || (nargs > 4))
+	XP_ERROR(XPATH_INVALID_ARITY);
+
+    if (nargs >= 4) {
+	CHECK_TYPE(XPATH_NUMBER);
+	number = valuePop(ctxt);
+    }
+    if (nargs >= 3) {
+	CHECK_TYPE(XPATH_NUMBER);
+	position = valuePop(ctxt);
+    }
+    CHECK_TYPE(XPATH_STRING);
+    string = valuePop(ctxt);
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_LOCATIONSET) &&
+	 (ctxt->value->type != XPATH_NODESET)))
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+    set = valuePop(ctxt);
+    if (set->type == XPATH_NODESET) {
+	xmlXPathObjectPtr tmp;
+
+	/*
+	 * First convert to a location set
+	 */
+	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
+	xmlXPathFreeObject(set);
+	set = tmp;
+    }
+    oldset = (xmlLocationSetPtr) set->user;
+
+    /*
+     * The loop is to search for each element in the location set
+     * the list of location set corresponding to that search
+     */
+    newset = xmlXPtrLocationSetCreate(NULL);
+    for (i = 0;i < oldset->locNr;i++) {
+#ifdef DEBUG_RANGES
+	xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0);
+#endif
+
+	xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
+	xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
+	xmlXPtrAdvanceChar(&start, &startindex, 0);
+	xmlXPtrGetLastChar(&end, &endindex);
+
+#ifdef DEBUG_RANGES
+	fprintf(stdout, "from index %d of ->", startindex);
+	xmlDebugDumpString(stdout, start->content);
+	fprintf(stdout, "\n");
+	fprintf(stdout, "to index %d of ->", endindex);
+	xmlDebugDumpString(stdout, end->content);
+	fprintf(stdout, "\n");
+#endif
+	do {
+            fend = end;
+            fendindex = endindex;
+	    found = xmlXPtrSearchString(string->stringval, &start, &startindex,
+		                        &fend, &fendindex);
+	    if (found == 1) {
+		xmlXPtrLocationSetAdd(newset,
+			 xmlXPtrNewRange(start, startindex, fend, fendindex));
+		start = fend;
+		startindex = fendindex;
+	    }
+	} while (found == 1);
+    }
+
+    /*
+     * Save the new value and cleanup
+     */
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+    xmlXPathFreeObject(set);
+    xmlXPathFreeObject(string);
+    if (position) xmlXPathFreeObject(position);
+    if (number) xmlXPathFreeObject(number);
+}
+
 #else
 #endif