Bug fixes, improvement on ID/IDREF support, 1.6.2, no memleaks, Daniel
diff --git a/ChangeLog b/ChangeLog
index a60e0a7..e939c0c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Wed Sep  8 22:46:14 CEST 1999 Daniel Veillard <Daniel.Veillard@w3.org>
+
+	* HTMLparser.c : cleanup
+	* SAX.c valid.c valid.h: added ID/IDREF checking
+	* tree.c tree.h: extended doc structure for refs
+	* configure.in: 1.6.2
+	* parser.c: patched bug in SAX user arg call
+	* parserInternals.h: patched missing close in C++ wrapping
+	* testXPath.c xpath.c xpath.h: prepared for extensibility,
+	  especially upcoming XPointer implementation.
+	* doc/xml.html: augmented, typo
+
 Sat Sep  4 22:48:05 CEST 1999 Timur Bakeyev <mc@bat.ru>
 
 	* doc/Makefile.am: replaced "install -d " with "mkinstalldirs" -
diff --git a/HACKING b/HACKING
index 6b702fa..8f791bc 100644
--- a/HACKING
+++ b/HACKING
@@ -15,7 +15,7 @@
 The reasons I'm asking for an ask before commit policy is that I'm
 using a separate CVS base for unstable developments and if you commit
 a patch I didn't get, I may loose your change by mistake (it happened
-already once) and seriously complicatye my job of merging both bases.
+already once) and seriously complicates my job of merging both bases.
 (The second base is at http://dev.w3.org/ under the XML module).
 
   thanks in advance for following the rule,
diff --git a/HTMLparser.c b/HTMLparser.c
index adfa2d9..a559d9b 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -1133,6 +1133,8 @@
     cur->encoding = NULL;
     cur->standalone = 1;
     cur->compression = 0;
+    cur->ids = NULL;
+    cur->refs = NULL;
 #ifndef XML_WITHOUT_CORBA
     cur->_private = NULL;
     cur->vepv = NULL;
diff --git a/SAX.c b/SAX.c
index 57443ed..d0c08fe 100644
--- a/SAX.c
+++ b/SAX.c
@@ -492,10 +492,13 @@
 void
 endDocument(void *ctx)
 {
-    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
 #ifdef DEBUG_SAX
     fprintf(stderr, "SAX.endDocument()\n");
 #endif
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+	ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
 }
 
 /**
@@ -572,6 +575,8 @@
 	 */
 	if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
 	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
+	else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
+	    xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
     }
 
     if (name != NULL) 
diff --git a/configure.in b/configure.in
index 7d33d2b..49d5708 100644
--- a/configure.in
+++ b/configure.in
@@ -5,7 +5,7 @@
 
 LIBXML_MAJOR_VERSION=1
 LIBXML_MINOR_VERSION=6
-LIBXML_MICRO_VERSION=1
+LIBXML_MICRO_VERSION=2
 LIBXML_VERSION=$LIBXML_MAJOR_VERSION.$LIBXML_MINOR_VERSION.$LIBXML_MICRO_VERSION
 LIBXML_VERSION_INFO=`expr $LIBXML_MAJOR_VERSION + $LIBXML_MINOR_VERSION`:$LIBXML_MICRO_VERSION:$LIBXML_MINOR_VERSION
 
diff --git a/doc/xml.html b/doc/xml.html
index 49e0899..a5afae1 100644
--- a/doc/xml.html
+++ b/doc/xml.html
@@ -529,7 +529,7 @@
 Model</em> this is an API for accessing XML or HTML structured documents.
 Native support for DOM in Gnome is on the way (module gnome-dom), and it will
 be based on gnome-xml. This will be a far cleaner interface to manipulate XML
-files within Gnome since it won't expose the internal structure. DOM defiles a
+files within Gnome since it won't expose the internal structure. DOM defines a
 set of IDL (or Java) interfaces allowing to traverse and manipulate a
 document. The DOM library will allow accessing and modifying "live" documents
 presents on other programs like this:</p>
@@ -747,6 +747,6 @@
 
 <p><a href="mailto:Daniel.Veillard@w3.org">Daniel Veillard</a></p>
 
-<p>$Id$</p>
+<p>$Id: xml.html,v 1.7 1999/09/04 18:27:23 veillard Exp $</p>
 </body>
 </html>
diff --git a/include/libxml/parserInternals.h b/include/libxml/parserInternals.h
index 13ea136..cb28943 100644
--- a/include/libxml/parserInternals.h
+++ b/include/libxml/parserInternals.h
@@ -637,4 +637,7 @@
 						 xmlParserInputPtr value);
 xmlParserInputPtr	inputPop		(xmlParserCtxtPtr ctxt);
 
+#ifdef __cplusplus
+}
+#endif
 #endif /* __XML_PARSER_INTERNALS_H__ */
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 6d22ac1..bf8a77e 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -211,6 +211,17 @@
 typedef xmlID *xmlIDPtr;
 
 /*
+ * An XML IDREF instance.
+ */
+
+typedef struct xmlRef {
+    struct xmlRef     *next;	/* next Ref */
+    const CHAR       *value;	/* The Ref name */
+    xmlAttrPtr        attr;	/* The attribut holding it */
+} xmlRef;
+typedef xmlRef *xmlRefPtr;
+
+/*
  * A node in an XML tree.
  */
 typedef struct xmlNode {
@@ -253,6 +264,7 @@
     struct xmlNs   *oldNs;	/* Global namespace, the old way */
     struct xmlNode *root;	/* the document tree */
     void           *ids;        /* Hash table for ID attributes if any */
+    void           *refs;       /* Hash table for IDREFs attributes if any */
 } _xmlDoc;
 typedef _xmlDoc xmlDoc;
 typedef xmlDoc *xmlDocPtr;
@@ -441,6 +453,12 @@
 					 const CHAR *lang);
 
 /*
+ * Removing content.
+ */
+int		xmlRemoveProp		(xmlAttrPtr attr); /* TODO */
+int		xmlRemoveNode		(xmlNodePtr node); /* TODO */
+
+/*
  * Internal, don't use
  */
 void		xmlBufferWriteCHAR	(xmlBufferPtr buf,
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
index 37b4f99..22a2c27 100644
--- a/include/libxml/valid.h
+++ b/include/libxml/valid.h
@@ -88,6 +88,20 @@
 } xmlIDTable;
 typedef xmlIDTable *xmlIDTablePtr;
 
+/*
+ * ALl Refs attributes are stored in a table
+ * there is one table per document
+ */
+
+#define XML_MIN_REF_TABLE	32
+
+typedef struct xmlRefTable {
+    int nb_refs;			/* number of refs stored */
+    int max_refs;		/* maximum number of refs */
+    xmlRefPtr *table;		/* the table of refs */
+} xmlRefTable;
+typedef xmlRefTable *xmlRefTablePtr;
+
 /* Notation */
 xmlNotationPtr	    xmlAddNotationDecl	(xmlValidCtxtPtr ctxt,
 					 xmlDtdPtr dtd,
@@ -148,6 +162,17 @@
 				 xmlNodePtr elem,
 				 xmlAttrPtr attr);
 
+/* IDREFs */
+xmlRefPtr	xmlAddRef	(xmlValidCtxtPtr ctxt,
+				 xmlDocPtr doc,
+				 const CHAR *value,
+				 xmlAttrPtr attr);
+xmlRefTablePtr	xmlCopyRefTable	(xmlRefTablePtr table);
+void		xmlFreeRefTable	(xmlRefTablePtr table);
+int		xmlIsRef	(xmlDocPtr doc,
+				 xmlNodePtr elem,
+				 xmlAttrPtr attr);
+
 /**
  * The public function calls related to validity checking
  */
@@ -181,6 +206,8 @@
 					 xmlNodePtr	elem,
 					 xmlAttrPtr attr,
 					 const CHAR *value);
+int		xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
 int		xmlValidateNotationUse	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 const CHAR *notationName);
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index 6408503..d46c063 100644
--- a/include/libxml/xpath.h
+++ b/include/libxml/xpath.h
@@ -14,6 +14,8 @@
 
 #include "tree.h"
 
+typedef struct xmlXPathParserContext *xmlXPathParserContextPtr;
+
 /*
  * A node-set (an unordered collection of nodes without duplicates) 
  */
@@ -37,6 +39,7 @@
 #define XPATH_BOOLEAN	2
 #define XPATH_NUMBER	3
 #define XPATH_STRING	4
+#define XPATH_USERS	5
 
 typedef struct xmlXPathObject {
     int type;
@@ -44,8 +47,66 @@
     int boolval;
     double floatval;
     CHAR *stringval;
+    void *user;
 } xmlXPathObject, *xmlXPathObjectPtr;
 
+/*
+ * A conversion function is associated to a type and used to cast
+ * the new type to primitive values.
+ */
+typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type);
+
+/*
+ * Extra type: a name and a conversion function.
+ */
+
+typedef struct xmlXPathType {
+    const CHAR         *name;		/* the type name */
+    xmlXPathConvertFunc func;		/* the conversion function */
+} xmlXPathType, *xmlXPathTypePtr;
+
+/*
+ * Extra variable: a name and a value.
+ */
+
+typedef struct xmlXPathVariable {
+    const CHAR       *name;		/* the variable name */
+    xmlXPathObjectPtr value;		/* the value */
+} xmlXPathVariable, *xmlXPathVariablePtr;
+
+/*
+ * an evaluation function, the parameters are on the context stack
+ */
+
+typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, int nargs);
+
+/*
+ * Extra function: a name and a evaluation function.
+ */
+
+typedef struct xmlXPathFunct {
+    const CHAR      *name;		/* the function name */
+    xmlXPathEvalFunc func;		/* the evaluation function */
+} xmlXPathFunc, *xmlXPathFuncPtr;
+
+/*
+ * An axis traversal function. To traverse an axis, the engine calls
+ * the first time with cur == NULL and repeat until the function returns
+ * NULL indicating the end of the axis traversal.
+ */
+
+typedef xmlXPathObjectPtr (*xmlXPathAxisFunc)	(xmlXPathParserContextPtr ctxt,
+						 xmlXPathObjectPtr cur);
+
+/*
+ * Extra axis: a name and an axis function.
+ */
+
+typedef struct xmlXPathAxis {
+    const CHAR      *name;		/* the axis name */
+    xmlXPathAxisFunc func;		/* the search function */
+} xmlXPathAxis, *xmlXPathAxisPtr;
+
 /* 
  * Expression evaluation occurs with respect to a context.
  * he context consists of:
@@ -60,10 +121,27 @@
     xmlDocPtr doc;			/* The current document */
     xmlNodePtr node;			/* The current node */
     xmlNodeSetPtr nodelist;		/* The current node list */
-    void *variables; /* TODO !!!! */
-    void *functions; /* TODO !!!! */
+
+    int nb_variables;			/* number of defined variables */
+    int max_variables;			/* max number of 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 */
+
+    int nb_funcs;			/* number of defined funcs */
+    int max_funcs;			/* max number of 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 */
+
+    /* Namespace traversal should be implemented with user */
     xmlNsPtr *namespaces;		/* The namespaces lookup */
     int nsNr;				/* the current Namespace index */
+    void *user;				/* user defined extra info */
 } xmlXPathContext, *xmlXPathContextPtr;
 
 /*
@@ -81,7 +159,7 @@
     int                 valueNr;	/* number of values stacked */
     int                valueMax;	/* max number of values stacked */
     xmlXPathObjectPtr *valueTab;	/* stack of values */
-} xmlXPathParserContext, *xmlXPathParserContextPtr;
+} xmlXPathParserContext;
 
 /*
  * An XPath function
@@ -97,9 +175,26 @@
  *									*
  ************************************************************************/
 
-xmlXPathContextPtr xmlXPathNewContext		(xmlDocPtr doc,
-						 void *variables,
-						 void *functions);
+/**
+ * Registering extensions to the expression language
+ */
+/* TODO */ int	   xmlXPathRegisterType		(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+                                                 xmlXPathConvertFunc f);
+/* TODO */ int	   xmlXPathRegisterAxis		(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+						 xmlXPathAxisFunc f);
+/* TODO */ int	   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+						 xmlXPathFunction f);
+/* TODO */ int	   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+						 xmlXPathObject value);
+
+/**
+ * Evaluation functions.
+ */
+xmlXPathContextPtr xmlXPathNewContext		(xmlDocPtr doc);
 void		   xmlXPathFreeContext		(xmlXPathContextPtr ctxt);
 xmlXPathObjectPtr  xmlXPathEval			(const CHAR *str,
 						 xmlXPathContextPtr ctxt);
diff --git a/parser.c b/parser.c
index 0f3e7cf..1b353fb 100644
--- a/parser.c
+++ b/parser.c
@@ -3122,11 +3122,11 @@
 	    if (isParameter) {
 	        if ((ctxt->sax != NULL) &&
 		    (ctxt->sax->getParameterEntity != NULL))
-		    cur = ctxt->sax->getParameterEntity(ctxt, name);
+		    cur = ctxt->sax->getParameterEntity(ctxt->userData, name);
 	    } else {
 	        if ((ctxt->sax != NULL) &&
 		    (ctxt->sax->getEntity != NULL))
-		    cur = ctxt->sax->getEntity(ctxt, name);
+		    cur = ctxt->sax->getEntity(ctxt->userData, name);
 	    }
             if (cur != NULL) {
 	        if (cur->orig != NULL)
diff --git a/parserInternals.h b/parserInternals.h
index 13ea136..cb28943 100644
--- a/parserInternals.h
+++ b/parserInternals.h
@@ -637,4 +637,7 @@
 						 xmlParserInputPtr value);
 xmlParserInputPtr	inputPop		(xmlParserCtxtPtr ctxt);
 
+#ifdef __cplusplus
+}
+#endif
 #endif /* __XML_PARSER_INTERNALS_H__ */
diff --git a/testXPath.c b/testXPath.c
index 178f23e..5045396 100644
--- a/testXPath.c
+++ b/testXPath.c
@@ -125,7 +125,7 @@
     xmlXPathObjectPtr res;
     xmlXPathContextPtr ctxt;
     
-    ctxt = xmlXPathNewContext(document, NULL, NULL);
+    ctxt = xmlXPathNewContext(document);
     if (expr)
 	res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
     else
diff --git a/tree.c b/tree.c
index 9e622ff..006defe 100644
--- a/tree.c
+++ b/tree.c
@@ -395,6 +395,7 @@
     cur->standalone = -1;
     cur->compression = xmlCompressMode;
     cur->ids = NULL;
+    cur->refs = NULL;
 #ifndef XML_WITHOUT_CORBA
     cur->_private = NULL;
     cur->vepv = NULL;
@@ -425,6 +426,7 @@
     if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
     if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
+    if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
     memset(cur, -1, sizeof(xmlDoc));
     xmlFree(cur);
 }
diff --git a/tree.h b/tree.h
index 6d22ac1..bf8a77e 100644
--- a/tree.h
+++ b/tree.h
@@ -211,6 +211,17 @@
 typedef xmlID *xmlIDPtr;
 
 /*
+ * An XML IDREF instance.
+ */
+
+typedef struct xmlRef {
+    struct xmlRef     *next;	/* next Ref */
+    const CHAR       *value;	/* The Ref name */
+    xmlAttrPtr        attr;	/* The attribut holding it */
+} xmlRef;
+typedef xmlRef *xmlRefPtr;
+
+/*
  * A node in an XML tree.
  */
 typedef struct xmlNode {
@@ -253,6 +264,7 @@
     struct xmlNs   *oldNs;	/* Global namespace, the old way */
     struct xmlNode *root;	/* the document tree */
     void           *ids;        /* Hash table for ID attributes if any */
+    void           *refs;       /* Hash table for IDREFs attributes if any */
 } _xmlDoc;
 typedef _xmlDoc xmlDoc;
 typedef xmlDoc *xmlDocPtr;
@@ -441,6 +453,12 @@
 					 const CHAR *lang);
 
 /*
+ * Removing content.
+ */
+int		xmlRemoveProp		(xmlAttrPtr attr); /* TODO */
+int		xmlRemoveNode		(xmlNodePtr node); /* TODO */
+
+/*
  * Internal, don't use
  */
 void		xmlBufferWriteCHAR	(xmlBufferPtr buf,
diff --git a/valid.c b/valid.c
index 3a107db..a6466ff 100644
--- a/valid.c
+++ b/valid.c
@@ -1316,7 +1316,7 @@
 
 /************************************************************************
  *									*
- *				NOTATIONs				*
+ *				IDs					*
  *									*
  ************************************************************************/
 /**
@@ -1551,6 +1551,228 @@
 
 /************************************************************************
  *									*
+ *				Refs					*
+ *									*
+ ************************************************************************/
+/**
+ * xmlCreateRefTable:
+ *
+ * create and initialize an empty ref hash table.
+ *
+ * Returns the xmlRefTablePtr just created or NULL in case
+ *                of error.
+ */
+xmlRefTablePtr
+xmlCreateRefTable(void) {
+    xmlRefTablePtr ret;
+
+    ret = (xmlRefTablePtr) 
+         xmlMalloc(sizeof(xmlRefTable));
+    if (ret == NULL) {
+        fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
+	        (long)sizeof(xmlRefTable));
+        return(NULL);
+    }
+    ret->max_refs = XML_MIN_NOTATION_TABLE;
+    ret->nb_refs = 0;
+    ret->table = (xmlRefPtr *) 
+         xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
+    if (ret == NULL) {
+        fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
+	        ret->max_refs * (long)sizeof(xmlRef));
+	xmlFree(ret);
+        return(NULL);
+    }
+    return(ret);
+}
+
+
+/**
+ * xmlAddRef:
+ * @ctxt:  the validation context
+ * @doc:  pointer to the document
+ * @value:  the value name
+ * @attr:  the attribute holding the Ref
+ *
+ * Register a new ref declaration
+ *
+ * Returns NULL if not, othervise the new xmlRefPtr
+ */
+xmlRefPtr 
+xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
+         xmlAttrPtr attr) {
+    xmlRefPtr ret;
+    xmlRefTablePtr table;
+
+    if (doc == NULL) {
+        fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
+	return(NULL);
+    }
+    if (value == NULL) {
+        fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
+	return(NULL);
+    }
+    if (attr == NULL) {
+        fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
+	return(NULL);
+    }
+
+    /*
+     * Create the Ref table if needed.
+     */
+    table = doc->refs;
+    if (table == NULL) 
+        table = doc->refs = xmlCreateRefTable();
+    if (table == NULL) {
+	fprintf(stderr, "xmlAddRef: Table creation failed!\n");
+        return(NULL);
+    }
+
+    /*
+     * Grow the table, if needed.
+     */
+    if (table->nb_refs >= table->max_refs) {
+        /*
+	 * need more refs.
+	 */
+	table->max_refs *= 2;
+	table->table = (xmlRefPtr *) 
+	    xmlRealloc(table->table, table->max_refs *
+	            sizeof(xmlRefPtr));
+	if (table->table == NULL) {
+	    fprintf(stderr, "xmlAddRef: out of memory\n");
+	    return(NULL);
+	}
+    }
+    ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
+    if (ret == NULL) {
+	fprintf(stderr, "xmlAddRef: out of memory\n");
+	return(NULL);
+    }
+    table->table[table->nb_refs] = ret;
+
+    /*
+     * fill the structure.
+     */
+    ret->value = xmlStrdup(value);
+    ret->attr = attr;
+    table->nb_refs++;
+
+    return(ret);
+}
+
+/**
+ * xmlFreeRef:
+ * @not:  A ref
+ *
+ * Deallocate the memory used by an ref definition
+ */
+void
+xmlFreeRef(xmlRefPtr ref) {
+    if (ref == NULL) return;
+    if (ref->value != NULL)
+	xmlFree((CHAR *) ref->value);
+    memset(ref, -1, sizeof(xmlRef));
+    xmlFree(ref);
+}
+
+/**
+ * xmlFreeRefTable:
+ * @table:  An ref table
+ *
+ * Deallocate the memory used by an Ref hash table.
+ */
+void
+xmlFreeRefTable(xmlRefTablePtr table) {
+    int i;
+
+    if (table == NULL) return;
+
+    for (i = 0;i < table->nb_refs;i++) {
+        xmlFreeRef(table->table[i]);
+    }
+    xmlFree(table->table);
+    xmlFree(table);
+}
+
+/**
+ * xmlIsRef
+ * @doc:  the document
+ * @elem:  the element carrying the attribute
+ * @attr:  the attribute
+ *
+ * Determine whether an attribute is of type Ref. In case we have Dtd(s)
+ * then this is simple, otherwise we use an heuristic: name Ref (upper
+ * or lowercase).
+ *
+ * Returns 0 or 1 depending on the lookup result
+ */
+int
+xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
+    if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
+        return(0);
+	/*******************
+        if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
+            ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
+	    (attr->name[2] == 0)) return(1);
+	 *******************/
+    } else {
+	xmlAttributePtr attrDecl;
+
+	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
+	if ((attrDecl == NULL) && (doc->extSubset != NULL))
+	    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
+	                                 attr->name);
+
+        if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
+	    return(1);
+    }
+    return(0);
+}
+
+/**
+ * xmlGetRef:
+ * @doc:  pointer to the document
+ * @Ref:  the Ref value
+ *
+ * Search the attribute declaring the given Ref
+ *
+ * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
+ */
+xmlAttrPtr 
+xmlGetRef(xmlDocPtr doc, const CHAR *Ref) {
+    xmlRefPtr cur;
+    xmlRefTablePtr table;
+    int i;
+
+    if (doc == NULL) {
+        fprintf(stderr, "xmlGetRef: doc == NULL\n");
+	return(NULL);
+    }
+
+    if (Ref == NULL) {
+        fprintf(stderr, "xmlGetRef: Ref == NULL\n");
+	return(NULL);
+    }
+
+    table = doc->refs;
+    if (table == NULL) 
+        return(NULL);
+
+    /*
+     * Search the Ref list.
+     */
+    for (i = 0;i < table->nb_refs;i++) {
+        cur = table->table[i];
+	if (!xmlStrcmp(cur->value, Ref)) {
+	    return(cur->attr);
+	}
+    }
+    return(NULL);
+}
+
+/************************************************************************
+ *									*
  *		Routines for validity checking				*
  *									*
  ************************************************************************/
@@ -2165,6 +2387,10 @@
         xmlAddID(ctxt, doc, value, attr);
     }
 
+    if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
+        xmlAddRef(ctxt, doc, value, attr);
+    }
+
     /* Validity Constraint: Notation Attributes */
     if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
         xmlEnumerationPtr tree = attrDecl->tree;
@@ -2610,9 +2836,75 @@
 
 int
 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
+    xmlNodePtr child;
+    xmlAttrPtr attr;
+    CHAR *value;
+    int ret = 1;
+
+    /* TODO xmlValidateElement */
+
+    if (elem == NULL) return(0);
     CHECK_DTD;
 
-    return(1);
+    ret &= xmlValidateOneElement(ctxt, doc, elem);
+    attr = elem->properties;
+    while(attr != NULL) {
+        value = xmlNodeListGetString(doc, attr->val, 0);
+	ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
+	if (value != NULL)
+	    free(value);
+	attr= attr->next;
+    }
+    child = elem->childs;
+    while (child != NULL) {
+        ret &= xmlValidateElement(ctxt, doc, child);
+        child = child->next;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlValidateDocumentFinal:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Does the final step for the document validation once all the
+ * incremental validation steps have been completed
+ *
+ * basically it does the following checks described by the XML Rec
+ * 
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    int ret = 1, i;
+    xmlRefTablePtr table;
+    xmlAttrPtr id;
+
+    if (doc == NULL) {
+        fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
+	return(0);
+    }
+
+    /*
+     * Get the refs table
+     */
+    table = doc->refs;
+    if (table != NULL) {
+        for (i = 0; i < table->nb_refs; i++) {
+	    id = xmlGetID(doc, table->table[i]->value);
+	    if (id == NULL) {
+		VERROR(ctxt->userData, 
+		       "IDREF attribute %s reference an unknown ID '%s'\n",
+		       table->table[i]->attr->name, table->table[i]->value);
+	        ret = 0;
+	    }
+	}
+    }
+    return(ret);
 }
 
 /**
@@ -2630,6 +2922,7 @@
 
 int
 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
+    /* TODO xmlValidateDtd */
     return(1);
 }
 
@@ -2640,7 +2933,7 @@
  *
  * Try to validate the document instance
  *
- * basically it does the all the checks described by the
+ * basically it does the all the checks described by the XML Rec
  * i.e. validates the internal and external subset (if present)
  * and validate the document tree.
  *
@@ -2649,8 +2942,12 @@
 
 int
 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    int ret;
+
     if (!xmlValidateRoot(ctxt, doc)) return(0);
 
-    return(1);
+    ret = xmlValidateElement(ctxt, doc, doc->root);
+    ret &= xmlValidateDocumentFinal(ctxt, doc);
+    return(ret);
 }
 
diff --git a/valid.h b/valid.h
index 37b4f99..22a2c27 100644
--- a/valid.h
+++ b/valid.h
@@ -88,6 +88,20 @@
 } xmlIDTable;
 typedef xmlIDTable *xmlIDTablePtr;
 
+/*
+ * ALl Refs attributes are stored in a table
+ * there is one table per document
+ */
+
+#define XML_MIN_REF_TABLE	32
+
+typedef struct xmlRefTable {
+    int nb_refs;			/* number of refs stored */
+    int max_refs;		/* maximum number of refs */
+    xmlRefPtr *table;		/* the table of refs */
+} xmlRefTable;
+typedef xmlRefTable *xmlRefTablePtr;
+
 /* Notation */
 xmlNotationPtr	    xmlAddNotationDecl	(xmlValidCtxtPtr ctxt,
 					 xmlDtdPtr dtd,
@@ -148,6 +162,17 @@
 				 xmlNodePtr elem,
 				 xmlAttrPtr attr);
 
+/* IDREFs */
+xmlRefPtr	xmlAddRef	(xmlValidCtxtPtr ctxt,
+				 xmlDocPtr doc,
+				 const CHAR *value,
+				 xmlAttrPtr attr);
+xmlRefTablePtr	xmlCopyRefTable	(xmlRefTablePtr table);
+void		xmlFreeRefTable	(xmlRefTablePtr table);
+int		xmlIsRef	(xmlDocPtr doc,
+				 xmlNodePtr elem,
+				 xmlAttrPtr attr);
+
 /**
  * The public function calls related to validity checking
  */
@@ -181,6 +206,8 @@
 					 xmlNodePtr	elem,
 					 xmlAttrPtr attr,
 					 const CHAR *value);
+int		xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
 int		xmlValidateNotationUse	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 const CHAR *notationName);
diff --git a/xpath.c b/xpath.c
index 4ff7da5..a0f6a2a 100644
--- a/xpath.c
+++ b/xpath.c
@@ -769,7 +769,7 @@
  * Returns the xmlXPathContext just allocated.
  */
 xmlXPathContextPtr
-xmlXPathNewContext(xmlDocPtr doc, void *variables, void *functions) {
+xmlXPathNewContext(xmlDocPtr doc) {
     xmlXPathContextPtr ret;
 
     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
@@ -779,9 +779,25 @@
     }
     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
     ret->doc = doc;
-    ret->variables = variables;
-    ret->functions = functions;
+
+    ret->nb_variables = 0;
+    ret->max_variables = 0;
+    ret->variables = NULL;
+
+    ret->nb_types = 0;
+    ret->max_types = 0;
+    ret->types = NULL;
+
+    ret->nb_funcs = 0;
+    ret->max_funcs = 0;
+    ret->funcs = NULL;
+
+    ret->nb_axis = 0;
+    ret->max_axis = 0;
+    ret->axis = NULL;
+
     ret->namespaces = NULL;
+    ret->user = NULL;
     ret->nsNr = 0;
     return(ret);
 }
diff --git a/xpath.h b/xpath.h
index 6408503..d46c063 100644
--- a/xpath.h
+++ b/xpath.h
@@ -14,6 +14,8 @@
 
 #include "tree.h"
 
+typedef struct xmlXPathParserContext *xmlXPathParserContextPtr;
+
 /*
  * A node-set (an unordered collection of nodes without duplicates) 
  */
@@ -37,6 +39,7 @@
 #define XPATH_BOOLEAN	2
 #define XPATH_NUMBER	3
 #define XPATH_STRING	4
+#define XPATH_USERS	5
 
 typedef struct xmlXPathObject {
     int type;
@@ -44,8 +47,66 @@
     int boolval;
     double floatval;
     CHAR *stringval;
+    void *user;
 } xmlXPathObject, *xmlXPathObjectPtr;
 
+/*
+ * A conversion function is associated to a type and used to cast
+ * the new type to primitive values.
+ */
+typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type);
+
+/*
+ * Extra type: a name and a conversion function.
+ */
+
+typedef struct xmlXPathType {
+    const CHAR         *name;		/* the type name */
+    xmlXPathConvertFunc func;		/* the conversion function */
+} xmlXPathType, *xmlXPathTypePtr;
+
+/*
+ * Extra variable: a name and a value.
+ */
+
+typedef struct xmlXPathVariable {
+    const CHAR       *name;		/* the variable name */
+    xmlXPathObjectPtr value;		/* the value */
+} xmlXPathVariable, *xmlXPathVariablePtr;
+
+/*
+ * an evaluation function, the parameters are on the context stack
+ */
+
+typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, int nargs);
+
+/*
+ * Extra function: a name and a evaluation function.
+ */
+
+typedef struct xmlXPathFunct {
+    const CHAR      *name;		/* the function name */
+    xmlXPathEvalFunc func;		/* the evaluation function */
+} xmlXPathFunc, *xmlXPathFuncPtr;
+
+/*
+ * An axis traversal function. To traverse an axis, the engine calls
+ * the first time with cur == NULL and repeat until the function returns
+ * NULL indicating the end of the axis traversal.
+ */
+
+typedef xmlXPathObjectPtr (*xmlXPathAxisFunc)	(xmlXPathParserContextPtr ctxt,
+						 xmlXPathObjectPtr cur);
+
+/*
+ * Extra axis: a name and an axis function.
+ */
+
+typedef struct xmlXPathAxis {
+    const CHAR      *name;		/* the axis name */
+    xmlXPathAxisFunc func;		/* the search function */
+} xmlXPathAxis, *xmlXPathAxisPtr;
+
 /* 
  * Expression evaluation occurs with respect to a context.
  * he context consists of:
@@ -60,10 +121,27 @@
     xmlDocPtr doc;			/* The current document */
     xmlNodePtr node;			/* The current node */
     xmlNodeSetPtr nodelist;		/* The current node list */
-    void *variables; /* TODO !!!! */
-    void *functions; /* TODO !!!! */
+
+    int nb_variables;			/* number of defined variables */
+    int max_variables;			/* max number of 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 */
+
+    int nb_funcs;			/* number of defined funcs */
+    int max_funcs;			/* max number of 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 */
+
+    /* Namespace traversal should be implemented with user */
     xmlNsPtr *namespaces;		/* The namespaces lookup */
     int nsNr;				/* the current Namespace index */
+    void *user;				/* user defined extra info */
 } xmlXPathContext, *xmlXPathContextPtr;
 
 /*
@@ -81,7 +159,7 @@
     int                 valueNr;	/* number of values stacked */
     int                valueMax;	/* max number of values stacked */
     xmlXPathObjectPtr *valueTab;	/* stack of values */
-} xmlXPathParserContext, *xmlXPathParserContextPtr;
+} xmlXPathParserContext;
 
 /*
  * An XPath function
@@ -97,9 +175,26 @@
  *									*
  ************************************************************************/
 
-xmlXPathContextPtr xmlXPathNewContext		(xmlDocPtr doc,
-						 void *variables,
-						 void *functions);
+/**
+ * Registering extensions to the expression language
+ */
+/* TODO */ int	   xmlXPathRegisterType		(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+                                                 xmlXPathConvertFunc f);
+/* TODO */ int	   xmlXPathRegisterAxis		(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+						 xmlXPathAxisFunc f);
+/* TODO */ int	   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+						 xmlXPathFunction f);
+/* TODO */ int	   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
+						 const CHAR *name,
+						 xmlXPathObject value);
+
+/**
+ * Evaluation functions.
+ */
+xmlXPathContextPtr xmlXPathNewContext		(xmlDocPtr doc);
 void		   xmlXPathFreeContext		(xmlXPathContextPtr ctxt);
 xmlXPathObjectPtr  xmlXPathEval			(const CHAR *str,
 						 xmlXPathContextPtr ctxt);