added the close and getattribute methods of XmlTextReader. added the

* xmlreader.c doc/libxml2-api.xml: added the close and getattribute
  methods of XmlTextReader.
* python/generator.py python/libxml_wrap.h python/types.c
  python/libxml2class.txt: added the reader to the Python bindings
* python/tests/Makefile.am python/tests/reader.py: added a specific
  test for the Python bindings of the Reader APIs
* parser.c: small cleanup.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 23be7c1..4d1f1b2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Sat Dec 14 23:57:39 CET 2002 Daniel Veillard <daniel@veillard.com>
+
+	* xmlreader.c doc/libxml2-api.xml: added the close and getattribute
+	  methods of XmlTextReader.
+	* python/generator.py python/libxml_wrap.h python/types.c 
+	  python/libxml2class.txt: added the reader to the Python bindings
+	* python/tests/Makefile.am python/tests/reader.py: added a specific
+	  test for the Python bindings of the Reader APIs
+	* parser.c: small cleanup.
+
 Fri Dec 13 11:39:44 CET 2002 Daniel Veillard <daniel@veillard.com>
 
 	* xinclude.c: fallback was only copying the first child not the
diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml
index 0028b5c..7909b8e 100644
--- a/doc/libxml2-api.xml
+++ b/doc/libxml2-api.xml
@@ -1093,7 +1093,11 @@
      <exports symbol='xmlTextReader'/>
      <exports symbol='xmlTextReaderAttributeCount'/>
      <exports symbol='xmlTextReaderBaseUri'/>
+     <exports symbol='xmlTextReaderClose'/>
      <exports symbol='xmlTextReaderDepth'/>
+     <exports symbol='xmlTextReaderGetAttribute'/>
+     <exports symbol='xmlTextReaderGetAttributeNo'/>
+     <exports symbol='xmlTextReaderGetAttributeNs'/>
      <exports symbol='xmlTextReaderHasAttributes'/>
      <exports symbol='xmlTextReaderHasValue'/>
      <exports symbol='xmlTextReaderIsDefault'/>
@@ -7876,11 +7880,35 @@
       <return type='xmlChar *' info='the base URI or NULL if not available'/>
       <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
     </function>
+    <function name='xmlTextReaderClose' file='xmlreader'>
+      <info>This method releases any resources allocated by the current instance changes the state to Closed and close any underlying input.</info>
+      <return type='int' info='0 or -1 in case of error'/>
+      <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+    </function>
     <function name='xmlTextReaderDepth' file='xmlreader'>
       <info>The depth of the node in the tree.</info>
       <return type='int' info='the depth or -1 in case of error'/>
       <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
     </function>
+    <function name='xmlTextReaderGetAttribute' file='xmlreader'>
+      <info>Provides the value of the attribute with the specified qualified name.</info>
+      <return type='xmlChar *' info='a string containing the value of the specified attribute, or NULL in case of error. The string must be deallocated by the caller.'/>
+      <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+      <arg name='name' type='const xmlChar *' info='the qualified name of the attribute.'/>
+    </function>
+    <function name='xmlTextReaderGetAttributeNo' file='xmlreader'>
+      <info>Provides the value of the attribute with the specified index relative to the containing element.</info>
+      <return type='xmlChar *' info='a string containing the value of the specified attribute, or NULL in case of error. The string must be deallocated by the caller.'/>
+      <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+      <arg name='no' type='int' info='the zero-based index of the attribute relative to the containing element'/>
+    </function>
+    <function name='xmlTextReaderGetAttributeNs' file='xmlreader'>
+      <info>Provides the value of the specified attribute</info>
+      <return type='xmlChar *' info='a string containing the value of the specified attribute, or NULL in case of error. The string must be deallocated by the caller.'/>
+      <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+      <arg name='localName' type='const xmlChar *' info='the local name of the attribute.'/>
+      <arg name='namespaceURI' type='const xmlChar *' info='the namespace URI of the attribute.'/>
+    </function>
     <function name='xmlTextReaderHasAttributes' file='xmlreader'>
       <info>Whether the node has attributes.</info>
       <return type='int' info='1 if true, 0 if false, and -1 in case or error'/>
diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h
index 8e4b057..15937a1 100644
--- a/include/libxml/xmlreader.h
+++ b/include/libxml/xmlreader.h
@@ -49,6 +49,18 @@
 int		xmlTextReaderQuoteChar	(xmlTextReaderPtr reader);
 xmlChar *	xmlTextReaderValue	(xmlTextReaderPtr reader);
 xmlChar *	xmlTextReaderXmlLang	(xmlTextReaderPtr reader);
+
+/*
+ * Methods of the XmlTextReader
+ */
+int		xmlTextReaderClose		(xmlTextReaderPtr reader);
+xmlChar *	xmlTextReaderGetAttributeNo	(xmlTextReaderPtr reader,
+						 int no);
+xmlChar *	xmlTextReaderGetAttribute	(xmlTextReaderPtr reader,
+						 const xmlChar *name);
+xmlChar *	xmlTextReaderGetAttributeNs	(xmlTextReaderPtr reader,
+						 const xmlChar *localName,
+						 const xmlChar *namespaceURI);
 #ifdef __cplusplus
 }
 #endif
diff --git a/parser.c b/parser.c
index 6690826..f68c424 100644
--- a/parser.c
+++ b/parser.c
@@ -1769,7 +1769,8 @@
 	    int first = CUR_SCHAR(cur, l);
 
 	    if (!IS_LETTER(first) && (first != '_')) {
-		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		if ((ctxt != NULL) && (ctxt->sax != NULL) &&
+		    (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt->userData,
 			    "Name %s is not XML Namespace compliant\n",
 			             name);
@@ -1790,7 +1791,8 @@
 	    
 	    buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
 	    if (buffer == NULL) {
-		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		if ((ctxt != NULL) && (ctxt->sax != NULL) &&
+	            (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt->userData,
 				     "xmlSplitQName: out of memory\n");
 		return(NULL);
@@ -1802,7 +1804,8 @@
 		    buffer = (xmlChar *) xmlRealloc(buffer,
 						    max * sizeof(xmlChar));
 		    if (buffer == NULL) {
-			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			if ((ctxt != NULL) && (ctxt->sax != NULL) &&
+			    (ctxt->sax->error != NULL))
 			    ctxt->sax->error(ctxt->userData,
 					     "xmlSplitQName: out of memory\n");
 			return(NULL);
diff --git a/python/generator.py b/python/generator.py
index 9c75713..b42630b 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -271,6 +271,7 @@
     'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
     'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
     'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"),
+    'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"),
 }
 
 py_return_types = {
@@ -597,6 +598,7 @@
     "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
     "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
     "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
+    "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
 }
 
 converter_type = {
@@ -624,6 +626,7 @@
 #    "outputBuffer": "xmlOutputBufferClose",
     "inputBuffer": "xmlFreeParserInputBuffer",
     "xmlReg": "xmlRegFreeRegexp",
+    "xmlTextReader": "xmlFreeTextReader",
 }
 
 functions_noexcept = {
@@ -676,6 +679,9 @@
         func = "regexp" + name[9:]
     elif name[0:6] == "xmlReg" and file == "xmlregexp":
         func = "regexp" + name[6:]
+    elif name[0:13] == "xmlTextReader" and file == "xmlreader":
+        func = name[13:]
+        func = string.lower(func[0:1]) + func[1:]
     elif name[0:11] == "xmlACatalog":
         func = name[11:]
         func = string.lower(func[0:1]) + func[1:]
diff --git a/python/libxml2class.txt b/python/libxml2class.txt
index e15f599..6127f7b 100644
--- a/python/libxml2class.txt
+++ b/python/libxml2class.txt
@@ -165,6 +165,9 @@
 registerDefaultOutputCallbacks()
 registerHTTPPostCallbacks()
 
+# functions from module xmlreader
+newTextReaderFilename()
+
 # functions from module xmlregexp
 regexpCompile()
 
@@ -556,6 +559,30 @@
     freeProp()
     freePropList()
     removeProp()
+Class xmlTextReader()
+
+    # functions from module xmlreader
+    attributeCount()
+    baseUri()
+    close()
+    depth()
+    freeTextReader()
+    getAttribute()
+    getAttributeNo()
+    getAttributeNs()
+    hasAttributes()
+    hasValue()
+    isDefault()
+    isEmptyElement()
+    localName()
+    name()
+    namespaceUri()
+    nodeType()
+    prefix()
+    quoteChar()
+    read()
+    value()
+    xmlLang()
 Class xmlReg()
 
     # functions from module xmlregexp
@@ -731,6 +758,9 @@
     push()
     read()
 
+    # functions from module xmlreader
+    newTextReader()
+
 
 Class outputBuffer(ioWriteWrapper)
 
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index efa79d0..7a38f54 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -17,6 +17,26 @@
 #include <libxml/xmlunicode.h>
 #include <libxml/xmlregexp.h>
 #include <libxml/xmlautomata.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * ATTRIBUTE_UNUSED:
+ *
+ * Macro used to signal to GCC unused function parameters
+ * Repeated here since the definition is not available when
+ * compiled outside the libxml2 build tree.
+ */
+#ifdef __GNUC__
+#ifdef ATTRIBUTE_UNUSED
+#undef ATTRIBUTE_UNUSED
+#endif
+#include <ansidecl.h>
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED
+#endif
+#else
+#define ATTRIBUTE_UNUSED
+#endif
 
 #define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \
 	(((PyxmlNode_Object *)(v))->obj))
@@ -66,6 +86,14 @@
     xmlRegexpPtr obj;
 } PyxmlReg_Object;
 
+#define PyxmlTextReader_Get(v) (((v) == Py_None) ? NULL : \
+        (((PyxmlTextReader_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
+    xmlTextReaderPtr obj;
+} PyxmlTextReader_Object;
+
 #define PyURI_Get(v) (((v) == Py_None) ? NULL : \
 	(((PyURI_Object *)(v))->obj))
 
@@ -119,5 +147,6 @@
 PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer);
 PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer);
 PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp);
+PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader);
 
 xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj);
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index 96cb033..c6bef2c 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -19,7 +19,8 @@
     outbuf.py	\
     inbuf.py	\
     resolver.py \
-    regexp.py
+    regexp.py	\
+    reader.py
 
 XMLS=		\
     tst.xml	\
diff --git a/python/tests/reader.py b/python/tests/reader.py
new file mode 100755
index 0000000..1817fe9
--- /dev/null
+++ b/python/tests/reader.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python -u
+import libxml2
+import StringIO
+import sys
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+f = StringIO.StringIO("""<a><b b1="b1"/><c>content of c</c></a>""")
+input = libxml2.inputBuffer(f)
+reader = input.newTextReader()
+ret = reader.read()
+if ret != 1:
+    print "Error reading to first element"
+    sys.exit(1)
+if reader.name() != "a" or reader.isEmptyElement() != 0 or \
+   reader.nodeType() != 1 or reader.hasAttributes() != 0:
+    print "Error reading the first element"
+    sys.exit(1)
+ret = reader.read()
+if ret != 1:
+    print "Error reading to second element"
+    sys.exit(1)
+if reader.name() != "b" or reader.isEmptyElement() != 1 or \
+   reader.nodeType() != 1 or reader.hasAttributes() != 1:
+    print "Error reading the second element"
+    sys.exit(1)
+ret = reader.read()
+if ret != 1:
+    print "Error reading to third element"
+    sys.exit(1)
+if reader.name() != "c" or reader.isEmptyElement() != 0 or \
+   reader.nodeType() != 1 or reader.hasAttributes() != 0:
+    print "Error reading the third element"
+    sys.exit(1)
+ret = reader.read()
+if ret != 1:
+    print "Error reading to text node"
+    sys.exit(1)
+if reader.name() != "#text" or reader.isEmptyElement() != 0 or \
+   reader.nodeType() != 3 or reader.hasAttributes() != 0 or \
+   reader.value() != "content of c":
+    print "Error reading the text node"
+    sys.exit(1)
+ret = reader.read()
+if ret != 1:
+    print "Error reading to end of third element"
+    sys.exit(1)
+if reader.name() != "c" or reader.isEmptyElement() != 0 or \
+   reader.nodeType() != 15 or reader.hasAttributes() != 0:
+    print "Error reading the end of third element"
+    sys.exit(1)
+ret = reader.read()
+if ret != 1:
+    print "Error reading to end of first element"
+    sys.exit(1)
+if reader.name() != "a" or reader.isEmptyElement() != 0 or \
+   reader.nodeType() != 15 or reader.hasAttributes() != 0:
+    print "Error reading the end of first element"
+    sys.exit(1)
+ret = reader.read()
+if ret != 0:
+    print "Error reading to end of document"
+    sys.exit(1)
+
+#
+# example from the XmlTextReader docs
+#
+f = StringIO.StringIO("""<test xmlns:dt="urn:datatypes" dt:type="int"/>""")
+input = libxml2.inputBuffer(f)
+reader = input.newTextReader()
+
+ret = reader.read()
+if ret != 1:
+    print "Error reading test element"
+    sys.exit(1)
+if reader.getAttributeNo(0) != "urn:datatypes" or \
+   reader.getAttributeNo(1) != "int" or \
+   reader.getAttributeNs("type", "urn:datatypes") != "int" or \
+   reader.getAttribute("dt:type") != "int":
+    print "error reading test attributes"
+    sys.exit(1)
+
+del f
+del input
+del reader
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+    print "OK"
+else:
+    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    libxml2.dumpMemory()
diff --git a/python/types.c b/python/types.c
index 3f49028..2c5a13e 100644
--- a/python/types.c
+++ b/python/types.c
@@ -547,3 +547,21 @@
                                      (char *) "xmlRegexpPtr", NULL);
     return (ret);
 }
+
+PyObject *
+libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libxml_xmlTextReaderPtrWrap: reader = %p\n", reader);
+#endif
+    if (reader == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret =
+        PyCObject_FromVoidPtrAndDesc((void *) reader,
+                                     (char *) "xmlTextReaderPtr", NULL);
+    return (ret);
+}
diff --git a/xmlreader.c b/xmlreader.c
index 65ca8e8..0b6b13a 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -53,7 +53,8 @@
 
 typedef enum {
     XML_TEXTREADER_MODE_NORMAL = 0,
-    XML_TEXTREADER_MODE_EOF = 1
+    XML_TEXTREADER_MODE_EOF = 1,
+    XML_TEXTREADER_MODE_CLOSED = 1
 } xmlTextReaderMode;
 
 typedef enum {
@@ -475,6 +476,163 @@
 
 /************************************************************************
  *									*
+ *			Methods for XmlTextReader			*
+ *									*
+ ************************************************************************/
+/**
+ * xmlTextReaderClose:
+ * @reader:  the xmlTextReaderPtr used
+ *
+ * This method releases any resources allocated by the current instance
+ * changes the state to Closed and close any underlying input.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlTextReaderClose(xmlTextReaderPtr reader) {
+    if (reader == NULL)
+	return(-1);
+    reader->node = NULL;
+    reader->mode = XML_TEXTREADER_MODE_CLOSED;
+    if (reader->ctxt != NULL) {
+	if (reader->ctxt->myDoc != NULL) {
+	    xmlFreeDoc(reader->ctxt->myDoc);
+	    reader->ctxt->myDoc = NULL;
+	}
+	if (reader->allocs & XML_TEXTREADER_CTXT) {
+	    xmlFreeParserCtxt(reader->ctxt);
+	    reader->allocs -= XML_TEXTREADER_CTXT;
+	}
+    }
+    if (reader->sax != NULL) {
+        xmlFree(reader->sax);
+	reader->sax = NULL;
+    }
+    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
+	xmlFreeParserInputBuffer(reader->input);
+	reader->allocs -= XML_TEXTREADER_INPUT;
+    }
+    return(0);
+}
+
+/**
+ * xmlTextReaderGetAttributeNo:
+ * @reader:  the xmlTextReaderPtr used
+ * @no: the zero-based index of the attribute relative to the containing element
+ *
+ * Provides the value of the attribute with the specified index relative
+ * to the containing element.
+ *
+ * Returns a string containing the value of the specified attribute, or NULL
+ *    in case of error. The string must be deallocated by the caller.
+ */
+xmlChar *
+xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
+    xmlChar *ret;
+    int i;
+    xmlAttrPtr cur;
+    xmlNsPtr ns;
+
+    if (reader == NULL)
+	return(NULL);
+    if (reader->node == NULL)
+	return(NULL);
+    /* TODO: handle the xmlDecl */
+    if (reader->node->type != XML_ELEMENT_NODE) 
+	return(NULL);
+
+    ns = reader->node->nsDef;
+    for (i = 0;(i < no) && (ns != NULL);i++) {
+	ns = ns->next;
+    }
+    if (ns != NULL)
+	return(xmlStrdup(ns->href));
+
+    cur = reader->node->properties;
+    if (cur == NULL)
+	return(NULL);
+    for (;i < no;i++) {
+	cur = cur->next;
+	if (cur == NULL)
+	    return(NULL);
+    }
+    /* TODO walk the DTD if present */
+
+    ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
+    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
+    return(ret);
+}
+
+/**
+ * xmlTextReaderGetAttribute:
+ * @reader:  the xmlTextReaderPtr used
+ * @name: the qualified name of the attribute.
+ *
+ * Provides the value of the attribute with the specified qualified name.
+ *
+ * Returns a string containing the value of the specified attribute, or NULL
+ *    in case of error. The string must be deallocated by the caller.
+ */
+xmlChar *
+xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
+    xmlChar *prefix = NULL;
+    xmlChar *localname;
+    xmlNsPtr ns;
+    xmlChar *ret = NULL;
+
+    if ((reader == NULL) || (name == NULL))
+	return(NULL);
+    if (reader->node == NULL)
+	return(NULL);
+
+    /* TODO: handle the xmlDecl */
+    if (reader->node->type != XML_ELEMENT_NODE)
+	return(NULL);
+
+    localname = xmlSplitQName2(name, &prefix);
+    if (localname == NULL)
+	return(xmlGetProp(reader->node, name));
+    
+    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
+    if (ns != NULL)
+        ret = xmlGetNsProp(reader->node, localname, ns->href);
+
+    if (localname != NULL)
+        xmlFree(localname);
+    if (prefix != NULL)
+        xmlFree(prefix);
+    return(ret);
+}
+
+
+/**
+ * xmlTextReaderGetAttributeNs:
+ * @reader:  the xmlTextReaderPtr used
+ * @localName: the local name of the attribute.
+ * @namespaceURI: the namespace URI of the attribute.
+ *
+ * Provides the value of the specified attribute
+ *
+ * Returns a string containing the value of the specified attribute, or NULL
+ *    in case of error. The string must be deallocated by the caller.
+ */
+xmlChar *
+xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
+			    const xmlChar *namespaceURI) {
+    if ((reader == NULL) || (localName == NULL))
+	return(NULL);
+    if (reader->node == NULL)
+	return(NULL);
+
+    /* TODO: handle the xmlDecl */
+    if (reader->node->type != XML_ELEMENT_NODE)
+	return(NULL);
+
+    return(xmlGetNsProp(reader->node, localName, namespaceURI));
+}
+
+/************************************************************************
+ *									*
  *			Acces API to the current node			*
  *									*
  ************************************************************************/