XPath fixes and cleanup, 2 general bug fixes:
- xpath.[ch] : fixed some serious XPath Predicate evaluation
  problems
- Makefile.am : added XPath regression tests to normal tests
- uri.c: fixed a problem with local paths, cleanup
- parser.c: fixed a problem with large CData sections
Daniel
diff --git a/ChangeLog b/ChangeLog
index 23a079a..8ce8e95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sun Oct  1 16:28:22 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org>
+
+	* xpath.[ch] : fixed some serious XPath Predicate evaluation
+	  problems
+	* Makefile.am : added XPath regression tests to normal tests
+	* uri.c: fixed a problem with local paths, cleanup
+	* parser.c: fixed a problem with large CData sections
+
 Sat Sep 30 16:35:54 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org>
 
 	* configure.in xml-config.in: patch from "Ben Taylor"
diff --git a/Makefile.am b/Makefile.am
index 513e127..cecc284 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,9 +99,9 @@
 
 $(libxml_la_SOURCES): $(srcdir)/libxml
 
-testall : tests SVGtests SAXtests XPathtests
+testall : tests SVGtests SAXtests
 
-tests: XMLtests XMLenttests HTMLtests Validtests URItests
+tests: XMLtests XMLenttests HTMLtests Validtests URItests XPathtests
 
 HTMLtests : testHTML
 	@(rm -f .memdump ; touch .memdump)
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index fc567fd..0efe466 100644
--- a/include/libxml/xpath.h
+++ b/include/libxml/xpath.h
@@ -45,17 +45,19 @@
  * @@ XPointer will add more types !
  */
 
-#define XPATH_UNDEFINED	0
-#define XPATH_NODESET	1
-#define XPATH_BOOLEAN	2
-#define XPATH_NUMBER	3
-#define XPATH_STRING	4
-#define XPATH_USERS	5
+typedef enum {
+    XPATH_UNDEFINED = 0,
+    XPATH_NODESET = 1,
+    XPATH_BOOLEAN = 2,
+    XPATH_NUMBER = 3,
+    XPATH_STRING = 4,
+    XPATH_USERS = 5
+} xmlXPathObjectType;
 
 typedef struct _xmlXPathObject xmlXPathObject;
 typedef xmlXPathObject *xmlXPathObjectPtr;
 struct _xmlXPathObject {
-    int type;
+    xmlXPathObjectType type;
     xmlNodeSetPtr nodesetval;
     int boolval;
     double floatval;
@@ -163,6 +165,10 @@
     xmlNsPtr *namespaces;		/* The namespaces lookup */
     int nsNr;				/* the current Namespace index */
     void *user;				/* user defined extra info */
+
+    /* extra variables */
+    int contextSize;			/* the context size */
+    int proximityPosition;		/* the proximity position */
 };
 
 /*
diff --git a/parser.c b/parser.c
index 33a3dce..83e2350 100644
--- a/parser.c
+++ b/parser.c
@@ -6014,6 +6014,7 @@
     int r, rl;
     int	s, sl;
     int cur, l;
+    int count = 0;
 
     if ((NXT(0) == '<') && (NXT(1) == '!') &&
 	(NXT(2) == '[') && (NXT(3) == 'C') &&
@@ -6070,6 +6071,11 @@
 	rl = sl;
 	s = cur;
 	sl = l;
+	count++;
+	if (count > 50) {
+	    GROW;
+	    count = 0;
+	}
 	NEXTL(l);
 	cur = CUR_CHAR(l);
     }
diff --git a/uri.c b/uri.c
index 48b1506..7166c5d 100644
--- a/uri.c
+++ b/uri.c
@@ -1372,16 +1372,11 @@
 xmlChar *
 xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
     xmlChar *val = NULL;
-    int ret, len, index, cur, out;
+    int ret, ret2, len, index, cur, out;
     xmlURIPtr ref = NULL;
     xmlURIPtr bas = NULL;
     xmlURIPtr res = NULL;
 
-    if ((URI == NULL) && (base == NULL))
-	return(NULL);
-    if (URI == NULL)
-	return((xmlChar *) xmlMemStrdup((const char *) base));
-
     /*
      * 1) The URI reference is parsed into the potential four components and
      *    fragment identifier, as described in Section 4.3.
@@ -1390,20 +1385,43 @@
      *    as a reference to "." rather than as a synonym for the current
      *    URI.  Should we do that here?
      */
-    ref = xmlCreateURI();
-    if (ref == NULL)
-	goto done;
-    if (*URI) {
-	ret = xmlParseURIReference(ref, (const char *) URI);
-	if (ret != 0)
+    if (URI == NULL) 
+	ret = -1;
+    else {
+	ref = xmlCreateURI();
+	if (ref == NULL)
 	    goto done;
+	if (*URI)
+	    ret = xmlParseURIReference(ref, (const char *) URI);
+	else
+	    ret = -1;
     }
-    bas = xmlCreateURI();
-    if (bas == NULL)
+    if (base == NULL)
+	ret2 = -1;
+    else {
+	bas = xmlCreateURI();
+	if (bas == NULL)
+	    goto done;
+	ret2 = xmlParseURIReference(bas, (const char *) base);
+    }
+    if ((ret != 0) && (ret2 != 0))
 	goto done;
-    ret = xmlParseURIReference(bas, (const char *) base);
-    if (ret != 0)
+    if (ret != 0) {
+	/*
+	 * the base fragment must be ignored
+	 */
+	if (bas->fragment != NULL) {
+	    xmlFree(bas->fragment);
+	    bas->fragment = NULL;
+	}
+	val = xmlSaveUri(bas);
 	goto done;
+    }
+    if (ret2 != 0) {
+	val = xmlSaveUri(ref);
+	goto done;
+    }
+
 
     /*
      * 2) If the path component is empty and the scheme, authority, and
@@ -1552,7 +1570,7 @@
 	/*
 	 * Ensure the path includes a '/'
 	 */
-	if (out == 0)
+	if ((out == 0) && (bas->server != NULL))
 	    res->path[out++] = '/';
 	while (ref->path[index] != 0) {
 	    res->path[out++] = ref->path[index++];
diff --git a/xpath.c b/xpath.c
index 7826a72..753576d 100644
--- a/xpath.c
+++ b/xpath.c
@@ -262,6 +262,8 @@
 #define XPATH_INVALID_OPERAND		10
 #define XPATH_INVALID_TYPE		11
 #define XPATH_INVALID_ARITY		12
+#define XPATH_INVALID_CTXT_SIZE		13
+#define XPATH_INVALID_CTXT_POSITION	14
 
 const char *xmlXPathErrorMessages[] = {
     "Ok",
@@ -277,6 +279,8 @@
     "Invalid operand",
     "Invalid type",
     "Invalid number of arguments",
+    "Invalid context size",
+    "Invalid context position",
 };
 
 /**
@@ -835,6 +839,9 @@
     ret->namespaces = NULL;
     ret->user = NULL;
     ret->nsNr = 0;
+
+    ret->contextSize = -1;
+    ret->proximityPosition = -1;
     return(ret);
 }
 
@@ -2191,13 +2198,13 @@
 void
 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     CHECK_ARITY(0);
-    if ((ctxt->context->nodelist == NULL) ||
-        (ctxt->context->node == NULL) ||
-        (ctxt->context->nodelist->nodeNr == 0)) {
-	valuePush(ctxt, xmlXPathNewFloat((double) 0));
+    if (ctxt->context->contextSize > 0) {
+	valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
+#ifdef DEBUG_EXPR
+	fprintf(xmlXPathDebug, "last() : %d\n", ctxt->context->contextSize);
+#endif
     } else {
-	valuePush(ctxt, 
-	          xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
+	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
     }
 }
 
@@ -2212,21 +2219,17 @@
  */
 void
 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-    int i;
-
     CHECK_ARITY(0);
-    if ((ctxt->context->nodelist == NULL) ||
-        (ctxt->context->node == NULL) ||
-        (ctxt->context->nodelist->nodeNr == 0)) {
-	valuePush(ctxt, xmlXPathNewFloat((double) 0));
+    if (ctxt->context->proximityPosition > 0) {
+	valuePush(ctxt,
+		  xmlXPathNewFloat((double) ctxt->context->proximityPosition));
+#ifdef DEBUG_EXPR
+	fprintf(xmlXPathDebug, "position() : %d\n",
+		ctxt->context->proximityPosition);
+#endif
+    } else {
+	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
     }
-    for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
-        if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
-	    valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
-	    return;
-	}
-    }
-    valuePush(ctxt, xmlXPathNewFloat((double) 0));
 }
 
 /**
@@ -4137,13 +4140,13 @@
  */
 int
 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
-                                xmlXPathObjectPtr res, int index) {
+                                xmlXPathObjectPtr res) {
     if (res == NULL) return(0);
     switch (res->type) {
         case XPATH_BOOLEAN:
 	    return(res->boolval);
         case XPATH_NUMBER:
-	    return(res->floatval == index);
+	    return(res->floatval == ctxt->context->proximityPosition);
         case XPATH_NODESET:
 	    return(res->nodesetval->nodeNr != 0);
         case XPATH_STRING:
@@ -4162,6 +4165,15 @@
  *  [8]   Predicate ::=   '[' PredicateExpr ']'
  *  [9]   PredicateExpr ::=   Expr 
  *
+ * ---------------------
+ * For each node in the node-set to be filtered, the PredicateExpr is
+ * evaluated with that node as the context node, with the number of nodes
+ * in the node-set as the context size, and with the proximity position
+ * of the node in the node-set with respect to the axis as the context
+ * position; if PredicateExpr evaluates to true for that node, the node
+ * is included in the new node-set; otherwise, it is not included.
+ * ---------------------
+ *
  * Parse and evaluate a predicate for all the elements of the
  * current node list. Then refine the list by removing all
  * nodes where the predicate is false.
@@ -4169,8 +4181,9 @@
 void
 xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
     const xmlChar *cur;
-    xmlXPathObjectPtr res, listHolder = NULL;
+    xmlXPathObjectPtr res;
     xmlNodeSetPtr newset = NULL;
+    xmlNodeSetPtr oldset;
     int i;
 
     SKIP_BLANKS;
@@ -4179,59 +4192,75 @@
     }
     NEXT;
     SKIP_BLANKS;
-    if ((ctxt->context->nodelist == NULL) ||
-        (ctxt->context->nodelist->nodeNr == 0)) {
-        ctxt->context->node = NULL;
+
+    /*
+     * Extract the old set, and then evaluate the result of the
+     * expression for all the element in the set. use it to grow
+     * up a new set.
+     */
+    oldset = ctxt->context->nodelist;
+    ctxt->context->nodelist = NULL;
+    ctxt->context->node = NULL;
+
+    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
 	xmlXPathEvalExpr(ctxt);
 	CHECK_ERROR;
+	ctxt->context->contextSize = 0;
+	ctxt->context->proximityPosition = 0;
 	res = valuePop(ctxt);
 	if (res != NULL)
 	    xmlXPathFreeObject(res);
     } else {
+	/*
+	 * Save the expression pointer since we will have to evaluate
+	 * it multiple times. Initialize the new set.
+	 */
         cur = ctxt->cur;
 	newset = xmlXPathNodeSetCreate(NULL);
 	
-	/*	Create a copy of the current node set because it is important:	*/	
-	listHolder = xmlXPathNewNodeSetList(ctxt->context->nodelist);
-		
-        for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
+        for (i = 0; i < oldset->nodeNr; i++) {
 	    ctxt->cur = cur;
-	    ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
 
-		/*	This nodeset is useful for the loop but no, longer necessary this iteration:	*/
-		if (ctxt->context->nodelist != NULL)
-		    xmlXPathFreeNodeSet(ctxt->context->nodelist);
-
-		/*	This line was missed out:	*/
-		ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
+	    /*
+	     * Run the evaluation with a node list made of a single item
+	     * in the nodeset.
+	     */
+	    ctxt->context->node = oldset->nodeTab[i];
+	    ctxt->context->nodelist = NULL;
+	    ctxt->context->contextSize = oldset->nodeNr;
+	    ctxt->context->proximityPosition = i + 1;
 
 	    xmlXPathEvalExpr(ctxt);
 	    CHECK_ERROR;
+
+	    /*
+	     * The result of the evaluation need to be tested to
+	     * decided whether the filter succeeded or not
+	     */
 	    res = valuePop(ctxt);
-	    if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
-	    	{
-		    /*	Add the current node as the result has proven correct:	*/
-	        xmlXPathNodeSetAdd(newset, listHolder->nodesetval->nodeTab[i]);
-		    }
+	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
+	        xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
+	    }
 	    if (res != NULL)
-	    xmlXPathFreeObject(res);
+		xmlXPathFreeObject(res);
 	    
-	    /*	Copy the contents of the temporary list back to the node list for the next round:	*/
-        ctxt->context->nodelist = xmlXPathNewNodeSetList(listHolder->nodesetval)->nodesetval;
+	    ctxt->context->node = NULL;
 	}
-	if (ctxt->context->nodelist != NULL)
-	    xmlXPathFreeNodeSet(ctxt->context->nodelist);
-	    
-	/*	Clean up after temporary variable holder:	*/    
-	if (listHolder != NULL)
-		xmlXPathFreeObject(listHolder);
-		
+
+	/*
+	 * The result is used as the new evaluation set.
+	 */
 	ctxt->context->nodelist = newset;
 	ctxt->context->node = NULL;
+	ctxt->context->contextSize = -1;
+	ctxt->context->proximityPosition = -1;
     }
     if (CUR != ']') {
 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
     }
+    if (oldset != NULL)
+	xmlXPathFreeNodeSet(oldset);
+
     NEXT;
     SKIP_BLANKS;
 #ifdef DEBUG_STEP
diff --git a/xpath.h b/xpath.h
index fc567fd..0efe466 100644
--- a/xpath.h
+++ b/xpath.h
@@ -45,17 +45,19 @@
  * @@ XPointer will add more types !
  */
 
-#define XPATH_UNDEFINED	0
-#define XPATH_NODESET	1
-#define XPATH_BOOLEAN	2
-#define XPATH_NUMBER	3
-#define XPATH_STRING	4
-#define XPATH_USERS	5
+typedef enum {
+    XPATH_UNDEFINED = 0,
+    XPATH_NODESET = 1,
+    XPATH_BOOLEAN = 2,
+    XPATH_NUMBER = 3,
+    XPATH_STRING = 4,
+    XPATH_USERS = 5
+} xmlXPathObjectType;
 
 typedef struct _xmlXPathObject xmlXPathObject;
 typedef xmlXPathObject *xmlXPathObjectPtr;
 struct _xmlXPathObject {
-    int type;
+    xmlXPathObjectType type;
     xmlNodeSetPtr nodesetval;
     int boolval;
     double floatval;
@@ -163,6 +165,10 @@
     xmlNsPtr *namespaces;		/* The namespaces lookup */
     int nsNr;				/* the current Namespace index */
     void *user;				/* user defined extra info */
+
+    /* extra variables */
+    int contextSize;			/* the context size */
+    int proximityPosition;		/* the proximity position */
 };
 
 /*