- xpath.[ch] xpointer.[ch]: worked on XPath functions and variable
  handlings (registration, lookup, cleanup)
Daniel
diff --git a/ChangeLog b/ChangeLog
index a729636..035aeef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Wed Oct 11 12:41:30 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org>
+
+	* xpath.[ch] xpointer.[ch]: worked on XPath functions and variable
+	  handlings (registration, lookup, cleanup)
+
 Wed Oct 11 01:46:44 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org>
 
 	* configure.in Makefile.am include/makefile.am: adding XPointer
diff --git a/configure.in b/configure.in
index 28b4685..ede84f5 100644
--- a/configure.in
+++ b/configure.in
@@ -311,7 +311,7 @@
 dnl
 if test ! -d $srcdir/include/libxml
 then
-    if [ ! -d $srcdir/include ]
+    if test ! -d $srcdir/include
     then
         rm -f $srcdir/include
         mkdir $srcdir/include
@@ -325,7 +325,7 @@
 fi
 if test ! -e include/libxml
 then
-    if [ ! -d include ]
+    if test ! -d include
     then
         rm -f include
         mkdir include
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index 9845578..533ca3f 100644
--- a/include/libxml/xpath.h
+++ b/include/libxml/xpath.h
@@ -288,6 +288,7 @@
 					 	int nargs);
 void		  xmlXPathRoot			(xmlXPathParserContextPtr ctxt);
 void		  xmlXPathEvalExpr		(xmlXPathParserContextPtr ctxt);
+xmlChar *	  xmlXPathParseName		(xmlXPathParserContextPtr ctxt);
 
 /************************************************************************
  *									*
@@ -296,20 +297,14 @@
  ************************************************************************/
 
 /**
- * Registering extensions to the expression language
+ * Extending a context
  */
-/* TODO */ int	   xmlXPathRegisterType		(xmlXPathContextPtr ctxt,
-						 const xmlChar *name,
-                                                 xmlXPathConvertFunc f);
-/* TODO */ int	   xmlXPathRegisterAxis		(xmlXPathContextPtr ctxt,
-						 const xmlChar *name,
-						 xmlXPathAxisFunc f);
-/* TODO */ int	   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
+int		   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
 						 const xmlChar *name,
 						 xmlXPathFunction f);
-/* TODO */ int	   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
+int		   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
 						 const xmlChar *name,
-						 xmlXPathObject value);
+						 xmlXPathObjectPtr value);
 
 /**
  * Evaluation functions.
@@ -327,6 +322,7 @@
 xmlNodeSetPtr	   xmlXPathNodeSetCreate	(xmlNodePtr val);
 void		   xmlXPathFreeNodeSetList	(xmlXPathObjectPtr obj);
 void		   xmlXPathFreeNodeSet		(xmlNodeSetPtr obj);
+xmlXPathObjectPtr  xmlXPathObjectCopy		(xmlXPathObjectPtr val);
 
 
 #ifdef __cplusplus
diff --git a/include/libxml/xpointer.h b/include/libxml/xpointer.h
index 927cdfb..3921687 100644
--- a/include/libxml/xpointer.h
+++ b/include/libxml/xpointer.h
@@ -31,6 +31,14 @@
 };
 
 /*
+ * Handling of location sets
+ */
+
+void			xmlXPtrFreeLocationSet	(xmlLocationSetPtr obj);
+xmlLocationSetPtr	xmlXPtrLocationSetMerge	(xmlLocationSetPtr val1,
+						 xmlLocationSetPtr val2);
+
+/*
  * Functions
  */
 xmlXPathContextPtr	xmlXPtrNewContext	(xmlDocPtr doc,
@@ -40,7 +48,6 @@
 						 xmlXPathContextPtr ctx);
 void			xmlXPtrRangeToFunction	(xmlXPathParserContextPtr ctxt,
        						 int nargs);
-void			xmlXPtrFreeLocationSet	(xmlLocationSetPtr obj);
 
 #ifdef __cplusplus
 }
diff --git a/xpath.c b/xpath.c
index 1d30755..83b7087 100644
--- a/xpath.c
+++ b/xpath.c
@@ -413,10 +413,11 @@
 
 /**
  * xmlXPathNodeSetMerge:
- * @val1:  the first NodeSet
+ * @val1:  the first NodeSet or NULL
  * @val2:  the second NodeSet
  *
  * Merges two nodesets, all nodes 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.
  */
@@ -424,8 +425,10 @@
 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
     int i;
 
-    if (val1 == NULL) return(NULL);
     if (val2 == NULL) return(val1);
+    if (val1 == NULL) {
+	val1 = xmlXPathNodeSetCreate(NULL);
+    }
 
     /*
      * !!!!! this can be optimized a lot, knowing that both
@@ -644,31 +647,218 @@
 
 /************************************************************************
  *									*
- *			Routines to handle Variable			*
- *									*
- *			UNIMPLEMENTED CURRENTLY				*
+ *		Routines to handle extra functions			*
  *									*
  ************************************************************************/
 
 /**
- * xmlXPathVariablelookup:
- * @ctxt:  the XPath Parser context
- * @prefix:  the variable name namespace if any
+ * xmlXPathRegisterFunc:
+ * @ctxt:  the XPath context
+ * @name:  the function name
+ * @f:  the function implementation or NULL
+ *
+ * Register a new function. If @f is NULL it unregisters the function
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int		  
+xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
+		     xmlXPathFunction f) {
+    int i;
+
+    if (ctxt == NULL)
+	return(-1);
+    if (name == NULL)
+	return(-1);
+
+    for (i = 0;i < ctxt->nb_funcs;i++) {
+	if (xmlStrEqual(ctxt->funcs[i]->name, name)) {
+	    /*
+	     * It's just an update or a removal
+	     */
+	    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));
+    } else if (ctxt->max_funcs <= ctxt->nb_funcs) {
+	ctxt->max_funcs *= 2;
+	ctxt->funcs = (xmlXPathFuncPtr *) xmlRealloc(ctxt->funcs,
+		                  ctxt->max_funcs * sizeof(xmlXPathFuncPtr));
+    }
+    if (ctxt->funcs == NULL) {
+        fprintf(xmlXPathDebug, "xmlXPathRegisterFunc: out of memory\n");
+	return(-1);
+    }
+    ctxt->funcs[i]->name = xmlStrdup(name);
+    ctxt->funcs[i]->func = f;
+    return(0);
+}
+
+/**
+ * xmlXPathFunctionLookup:
+ * @ctxt:  the XPath context
+ * @name:  the function name
+ *
+ * Search in the Function array of the context for the given
+ * function.
+ *
+ * Returns the xmlXPathFunction or NULL if not found
+ */
+xmlXPathFunction
+xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
+    int i;
+
+    if (ctxt == NULL)
+	return(NULL);
+    if (name == NULL)
+	return(NULL);
+
+    for (i = 0;i < ctxt->nb_funcs;i++) {
+	if (xmlStrEqual(ctxt->funcs[i]->name, name)) {
+	    return(ctxt->funcs[i]->func);
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xmlXPathRegisteredFuncsCleanup:
+ * @ctxt:  the XPath context
+ *
+ * Cleanup the XPath context data associated to registered functions
+ */
+void
+xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
+    int i;
+
+    if (ctxt == NULL)
+	return;
+
+    for (i = 0;i < ctxt->nb_funcs;i++) {
+	xmlFree((xmlChar *) ctxt->funcs[i]->name);
+    }
+    ctxt->nb_funcs = -1;
+    ctxt->max_funcs = -1;
+    if (ctxt->funcs != NULL)
+	xmlFree(ctxt->funcs);
+    ctxt->funcs = NULL;
+}
+
+/************************************************************************
+ *									*
+ *			Routines to handle Variable			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathRegisterVariable:
+ * @ctxt:  the XPath context
+ * @name:  the variable name
+ * @value:  the variable value or NULL
+ *
+ * Register a new variable value. If @value is NULL it unregisters
+ * the variable
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int		  
+xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
+			 xmlXPathObjectPtr value) {
+    int i;
+
+    if (ctxt == NULL)
+	return(-1);
+    if (name == NULL)
+	return(-1);
+
+    for (i = 0;i < ctxt->nb_variables;i++) {
+	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);
+	    }
+	    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));
+    } else if (ctxt->max_variables <= ctxt->nb_variables) {
+	ctxt->max_variables *= 2;
+	ctxt->variables = (xmlXPathVariablePtr *)
+	    xmlRealloc(ctxt->variables,
+		       ctxt->max_variables * sizeof(xmlXPathVariablePtr));
+    }
+    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);
+    return(0);
+}
+
+/**
+ * xmlXPathVariableLookup:
+ * @ctxt:  the XPath context
  * @name:  the variable name
  *
  * Search in the Variable array of the context for the given
  * variable value.
  *
- * UNIMPLEMENTED: always return NULL.
- *
  * Returns the value or NULL if not found
  */
 xmlXPathObjectPtr
-xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
-                       const xmlChar *prefix, const xmlChar *name) {
+xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
+    int i;
+
+    if (ctxt == NULL)
+	return(NULL);
+    if (name == NULL)
+	return(NULL);
+
+    for (i = 0;i < ctxt->nb_variables;i++) {
+	if (xmlStrEqual(ctxt->variables[i]->name, name)) {
+	    return(xmlXPathObjectCopy(ctxt->variables[i]->value));
+	}
+    }
     return(NULL);
 }
 
+/**
+ * xmlXPathRegisteredVariablesCleanup:
+ * @ctxt:  the XPath context
+ *
+ * Cleanup the XPath context data associated to registered variables
+ */
+void
+xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
+    int i;
+
+    if (ctxt == NULL)
+	return;
+
+    for (i = 0;i < ctxt->nb_variables;i++) {
+	xmlFree((xmlChar *) ctxt->variables[i]->name);
+	xmlXPathFreeObject(ctxt->variables[i]->value);
+    }
+    ctxt->nb_variables = -1;
+    ctxt->max_variables = -1;
+    if (ctxt->variables != NULL)
+	xmlFree(ctxt->variables);
+    ctxt->variables = NULL;
+}
+
 /************************************************************************
  *									*
  *			Routines to handle Values			*
@@ -770,6 +960,53 @@
 }
 
 /**
+ * xmlXPathObjectCopy:
+ * @val:  the original object
+ *
+ * allocate a new copy of a given object
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathObjectCopy(xmlXPathObjectPtr val) {
+    xmlXPathObjectPtr ret;
+
+    if (val == NULL)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        fprintf(xmlXPathDebug, "xmlXPathObjectCopy: out of memory\n");
+	return(NULL);
+    }
+    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
+    switch (val->type) {
+	case XPATH_BOOLEAN:
+	case XPATH_NUMBER:
+	case XPATH_STRING:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	    break;
+	case XPATH_NODESET:
+	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
+	    break;
+	case XPATH_LOCATIONSET:
+#ifdef LIBXML_XPTR_ENABLED
+	{
+	    xmlLocationSetPtr loc = val->user;
+	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
+	    break;
+	}
+#endif
+	case XPATH_UNDEFINED:
+	case XPATH_USERS:
+	    fprintf(xmlXPathDebug, "xmlXPathObjectCopy: unsupported type %d\n",
+		    val->type);
+    }
+    return(ret);
+}
+
+/**
  * xmlXPathFreeObject:
  * @obj:  the object to free
  *
@@ -860,6 +1097,8 @@
     if (ctxt->namespaces != NULL)
         xmlFree(ctxt->namespaces);
 
+    xmlXPathRegisteredFuncsCleanup(ctxt);
+    xmlXPathRegisteredVariablesCleanup(ctxt);
 #ifdef DEBUG
     memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
 #endif
@@ -3349,6 +3588,41 @@
 }
 
 /**
+ * xmlXPathParseName:
+ * @ctxt:  the XPointer Parser context
+ *
+ * parse an XML name
+ *
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ *                  CombiningChar | Extender
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * Returns the namespace name or NULL
+ */
+
+xmlChar *
+xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+
+    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
+    q = NEXT;
+
+    /* TODO Make this UTF8 compliant !!! */
+    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+           (CUR == '.') || (CUR == '-') ||
+	   (CUR == '_') || (CUR == ':') ||
+	   (IS_COMBINING(CUR)) ||
+	   (IS_EXTENDER(CUR)))
+	NEXT;
+    
+    ret = xmlStrndup(q, CUR_PTR - q);
+
+    return(ret);
+}
+
+/**
  * xmlXPathStringEvalNumber:
  * @str:  A string to scan
  *
@@ -3503,23 +3777,21 @@
 void
 xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
     xmlChar *name;
-    xmlChar *prefix;
     xmlXPathObjectPtr value;
 
     SKIP_BLANKS;
     if (CUR != '$') {
 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
     }
-    name = xmlXPathParseQName(ctxt, &prefix);
+    name = xmlXPathParseName(ctxt);
     if (name == NULL) {
 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
     }
-    value = xmlXPathVariablelookup(ctxt, prefix, name);
+    value = xmlXPathVariableLookup(ctxt->context, name);
     if (value == NULL) {
 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
     }
     valuePush(ctxt, value);
-    if (prefix != NULL) xmlFree(prefix);
     xmlFree(name);
     SKIP_BLANKS;
 }
@@ -3570,6 +3842,9 @@
  */
 xmlXPathFunction
 xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
+    if (name == NULL)
+	return(NULL);
+
     switch (name[0]) {
         case 'b':
 	    if (xmlStrEqual(name, BAD_CAST "boolean"))
@@ -3648,7 +3923,7 @@
 	        return(xmlXPathTranslateFunction);
 	    break;
     }
-    return(NULL);
+    return(xmlXPathFunctionLookup(ctxt->context, name));
 }
  
 /**
diff --git a/xpath.h b/xpath.h
index 9845578..533ca3f 100644
--- a/xpath.h
+++ b/xpath.h
@@ -288,6 +288,7 @@
 					 	int nargs);
 void		  xmlXPathRoot			(xmlXPathParserContextPtr ctxt);
 void		  xmlXPathEvalExpr		(xmlXPathParserContextPtr ctxt);
+xmlChar *	  xmlXPathParseName		(xmlXPathParserContextPtr ctxt);
 
 /************************************************************************
  *									*
@@ -296,20 +297,14 @@
  ************************************************************************/
 
 /**
- * Registering extensions to the expression language
+ * Extending a context
  */
-/* TODO */ int	   xmlXPathRegisterType		(xmlXPathContextPtr ctxt,
-						 const xmlChar *name,
-                                                 xmlXPathConvertFunc f);
-/* TODO */ int	   xmlXPathRegisterAxis		(xmlXPathContextPtr ctxt,
-						 const xmlChar *name,
-						 xmlXPathAxisFunc f);
-/* TODO */ int	   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
+int		   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
 						 const xmlChar *name,
 						 xmlXPathFunction f);
-/* TODO */ int	   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
+int		   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
 						 const xmlChar *name,
-						 xmlXPathObject value);
+						 xmlXPathObjectPtr value);
 
 /**
  * Evaluation functions.
@@ -327,6 +322,7 @@
 xmlNodeSetPtr	   xmlXPathNodeSetCreate	(xmlNodePtr val);
 void		   xmlXPathFreeNodeSetList	(xmlXPathObjectPtr obj);
 void		   xmlXPathFreeNodeSet		(xmlNodeSetPtr obj);
+xmlXPathObjectPtr  xmlXPathObjectCopy		(xmlXPathObjectPtr val);
 
 
 #ifdef __cplusplus
diff --git a/xpointer.c b/xpointer.c
index 82379ab..d9baf19 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -656,41 +656,6 @@
 #define CURRENT (*ctxt->cur)
 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
 
-/**
- * xmlXPtrParseName:
- * @ctxt:  the XPointer Parser context
- *
- * parse an XML name
- *
- * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
- *                  CombiningChar | Extender
- *
- * [5] Name ::= (Letter | '_' | ':') (NameChar)*
- *
- * Returns the namespace name or NULL
- */
-
-xmlChar *
-xmlXPtrParseName(xmlXPathParserContextPtr ctxt) {
-    const xmlChar *q;
-    xmlChar *ret = NULL;
-
-    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
-    q = NEXT;
-
-    /* TODO Make this UTF8 compliant !!! */
-    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
-           (CUR == '.') || (CUR == '-') ||
-	   (CUR == '_') || (CUR == ':') ||
-	   (IS_COMBINING(CUR)) ||
-	   (IS_EXTENDER(CUR)))
-	NEXT;
-    
-    ret = xmlStrndup(q, CUR_PTR - q);
-
-    return(ret);
-}
-
 /*
  * xmlXPtrGetChildNo:
  * @ctxt:  the XPointer Parser context
@@ -781,7 +746,7 @@
     int level;
 
     if (name == NULL)
-    name = xmlXPtrParseName(ctxt);
+    name = xmlXPathParseName(ctxt);
     if (name == NULL)
 	XP_ERROR(XPATH_EXPR_ERROR);
 
@@ -878,7 +843,7 @@
 void
 xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
     if (name == NULL)
-    name = xmlXPtrParseName(ctxt);
+    name = xmlXPathParseName(ctxt);
     if (name == NULL)
 	XP_ERROR(XPATH_EXPR_ERROR);
     while (name != NULL) {
@@ -928,7 +893,7 @@
 	 * Is there another XPoointer part.
 	 */
 	SKIP_BLANKS;
-	name = xmlXPtrParseName(ctxt);
+	name = xmlXPathParseName(ctxt);
     }
 }
 
@@ -992,7 +957,7 @@
     } else {
 	xmlChar *name;
 
-	name = xmlXPtrParseName(ctxt);
+	name = xmlXPathParseName(ctxt);
 	if (name == NULL)
 	    XP_ERROR(XPATH_EXPR_ERROR);
 	if (CUR == '(') {
diff --git a/xpointer.h b/xpointer.h
index 927cdfb..3921687 100644
--- a/xpointer.h
+++ b/xpointer.h
@@ -31,6 +31,14 @@
 };
 
 /*
+ * Handling of location sets
+ */
+
+void			xmlXPtrFreeLocationSet	(xmlLocationSetPtr obj);
+xmlLocationSetPtr	xmlXPtrLocationSetMerge	(xmlLocationSetPtr val1,
+						 xmlLocationSetPtr val2);
+
+/*
  * Functions
  */
 xmlXPathContextPtr	xmlXPtrNewContext	(xmlDocPtr doc,
@@ -40,7 +48,6 @@
 						 xmlXPathContextPtr ctx);
 void			xmlXPtrRangeToFunction	(xmlXPathParserContextPtr ctxt,
        						 int nargs);
-void			xmlXPtrFreeLocationSet	(xmlLocationSetPtr obj);
 
 #ifdef __cplusplus
 }