- 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
}