diff --git a/ChangeLog b/ChangeLog index ba6c7876..24dfa201 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Sun Feb 3 21:10:39 CET 2002 Daniel Veillard + + * parserInternals.c: change a small bit in the way valididy + error messages get initialized + * python/TODO python/libxml.c python/libxml2-python-api.xml + python/libxml2class.txt python/libxml_wrap.h python/types.c: + added some memory debugging to track leaks at the libxml2 level + * python/tests/*.py: changed all tests to check for leaks, + there is just one left in XPath extension registrations. + Sun Feb 3 17:50:46 CET 2002 Daniel Veillard * python/TODO python/generator.py python/libxml2-python-api.xml diff --git a/parserInternals.c b/parserInternals.c index b8bdaa9d..91eeae10 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -2257,16 +2257,14 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) sax->ignorableWhitespace = ignorableWhitespace; ctxt->vctxt.userData = ctxt; + ctxt->vctxt.error = xmlParserValidityError; + ctxt->vctxt.warning = xmlParserValidityWarning; if (ctxt->validate) { - ctxt->vctxt.error = xmlParserValidityError; if (xmlGetWarningsDefaultValue == 0) ctxt->vctxt.warning = NULL; else ctxt->vctxt.warning = xmlParserValidityWarning; ctxt->vctxt.nodeMax = 0; - } else { - ctxt->vctxt.error = NULL; - ctxt->vctxt.warning = NULL; } ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue; ctxt->record_info = 0; diff --git a/python/TODO b/python/TODO index d1799fb5..24f94d1c 100644 --- a/python/TODO +++ b/python/TODO @@ -6,17 +6,11 @@ Things to do: ------------- - SAX interfaces -- memory debug interfaces - enums -> libxml.py - access to XPath variables -- parserCtxt exposure: - - entry points - - wrappers - - decent interface for setting/getting behaviour - xmlBuffer exposure - xpathContext, being able to set/get info and clean it up - add regression tests - - check memory - build tree - saving - SAX flow @@ -33,6 +27,7 @@ Done: - tests/Makefile.am: export the Python class path - xpath queries - xpath extension + - check memory - extensions based on a python.xml description of the new specific interfaces file libxml2-python-api.xml , first entry is xmlRegisterXPathFunction @@ -43,5 +38,9 @@ Done: - handling of node.content - access to xmlParserCtxt and push mode - needed for SAX too + - entry points + - wrappers + - decent interface for setting/getting behaviour +- memory debug interfaces Daniel Veillard diff --git a/python/libxml.c b/python/libxml.c index 57e370f0..e37038ad 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -15,12 +15,99 @@ #include #include #include +#include #include "libxml_wrap.h" #include "libxml2-py.h" /* #define DEBUG */ /* #define DEBUG_XPATH */ /* #define DEBUG_ERROR */ +/* #define DEBUG_MEMORY */ + +/************************************************************************ + * * + * Memory debug interface * + * * + ************************************************************************/ + +extern void xmlMemFree(void *ptr); +extern void *xmlMemMalloc(size_t size); +extern void *xmlMemRealloc(void *ptr,size_t size); +extern char *xmlMemoryStrdup(const char *str); + +static int libxmlMemoryDebugActivated = 0; +static long libxmlMemoryAllocatedBase = 0; + +static int libxmlMemoryDebug = 0; +static xmlFreeFunc freeFunc = NULL; +static xmlMallocFunc mallocFunc = NULL; +static xmlReallocFunc reallocFunc = NULL; +static xmlStrdupFunc strdupFunc = NULL; + +PyObject * +libxml_xmlDebugMemory(PyObject *self, PyObject *args) { + int activate; + PyObject *py_retval; + long ret; + + if (!PyArg_ParseTuple(args, "i:xmlDebugMemory", &activate)) + return(NULL); + +#ifdef DEBUG_MEMORY + printf("libxml_xmlDebugMemory(%d) called\n", activate); +#endif + + if (activate != 0) { + if (libxmlMemoryDebug == 0) { + /* + * First initialize the library and grab the old memory handlers + * and switch the library to memory debugging + */ + xmlMemGet((xmlFreeFunc *) &freeFunc, + (xmlMallocFunc *)&mallocFunc, + (xmlReallocFunc *)&reallocFunc, + (xmlStrdupFunc *) &strdupFunc); + if ((freeFunc == xmlMemFree) && (mallocFunc == xmlMemMalloc) && + (reallocFunc == xmlMemRealloc) && + (strdupFunc == xmlMemoryStrdup)) { + libxmlMemoryAllocatedBase = xmlMemUsed(); + } else { + ret = (long) xmlMemSetup(xmlMemFree, xmlMemMalloc, + xmlMemRealloc, xmlMemoryStrdup); + if (ret < 0) + goto error; + libxmlMemoryAllocatedBase = xmlMemUsed(); + } + xmlInitParser(); + ret = 0; + } else if (libxmlMemoryDebugActivated == 0) { + libxmlMemoryAllocatedBase = xmlMemUsed(); + ret = 0; + } else { + ret = xmlMemUsed() - libxmlMemoryAllocatedBase; + } + libxmlMemoryDebug = 1; + libxmlMemoryDebugActivated = 1; + } else { + if (libxmlMemoryDebugActivated == 1) + ret = xmlMemUsed() - libxmlMemoryAllocatedBase; + else + ret = 0; + libxmlMemoryDebugActivated = 0; + } +error: + py_retval = libxml_longWrap(ret); + return(py_retval); +} + +PyObject * +libxml_xmlDumpMemory(PyObject *self, PyObject *args) { + + if (libxmlMemoryDebug != 0) + xmlMemoryDump(); + Py_INCREF(Py_None); + return(Py_None); +} /************************************************************************ * * @@ -68,6 +155,36 @@ libxml_xmlCreatePushParser(PyObject *self, PyObject *args) { return(pyret); } +PyObject * +libxml_htmlCreatePushParser(PyObject *self, PyObject *args) { + xmlChar *chunk; + int size; + xmlChar *URI; + PyObject *pyobj_SAX; + xmlSAXHandlerPtr SAX = NULL; + pySAXhandlerPtr SAXdata = NULL; + xmlParserCtxtPtr ret; + PyObject *pyret; + + if (!PyArg_ParseTuple(args, "Oziz:htmlCreatePushParser", &pyobj_SAX, + &chunk, &size, &URI)) + return(NULL); + +#ifdef DEBUG_ERROR + printf("libxml_htmlCreatePushParser(%p, %s, %d, %s) called\n", + pyobj_SAX, chunk, size, URI); +#endif + if (pyobj_SAX != Py_None) { + printf("htmlCreatePushParser: event interface not supported yet !\n"); + Py_INCREF(Py_None); + return(Py_None); + } + ret = htmlCreatePushParserCtxt(SAX, SAXdata, chunk, size, URI, + XML_CHAR_ENCODING_NONE); + pyret = libxml_xmlParserCtxtPtrWrap(ret); + return(pyret); +} + /************************************************************************ * * * Error message callback * diff --git a/python/libxml2-python-api.xml b/python/libxml2-python-api.xml index 2c5eb048..a830c755 100644 --- a/python/libxml2-python-api.xml +++ b/python/libxml2-python-api.xml @@ -21,7 +21,15 @@ - Create a progressive parser context to build either an event flow if the SAX object is not None, or a DOM tree otherwise. + Create a progressive XML parser context to build either an event flow if the SAX object is not None, or a DOM tree otherwise. + + + + + + + + Create a progressive HTML parser context to build either an event flow if the SAX object is not None, or a DOM tree otherwise. @@ -73,5 +81,14 @@ + + Switch on the generation of line number for elements nodes. Also returns the number of bytes allocated and not freed by libxml2 since memory debugging was switched on. + + + + + dump the memory allocated in the file .memdump + + diff --git a/python/libxml2class.txt b/python/libxml2class.txt index 374fe485..cb12a2f4 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -115,6 +115,9 @@ nodePush() # functions from module python createPushParser() +debugMemory() +dumpMemory() +htmlCreatePushParser() registerErrorHandler() # functions from module tree diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h index d6d89aa4..68daf019 100644 --- a/python/libxml_wrap.h +++ b/python/libxml_wrap.h @@ -35,6 +35,7 @@ typedef struct { } PyparserCtxt_Object; PyObject * libxml_intWrap(int val); +PyObject * libxml_longWrap(long val); PyObject * libxml_xmlCharPtrWrap(xmlChar *str); PyObject * libxml_constxmlCharPtrWrap(const xmlChar *str); PyObject * libxml_charPtrWrap(char *str); diff --git a/python/tests/error.py b/python/tests/error.py index 21cf5589..93379450 100755 --- a/python/tests/error.py +++ b/python/tests/error.py @@ -6,6 +6,9 @@ import sys import libxml2 +# Memory debug specific +libxml2.debugMemory(1) + expect='--> warning: --> failed to load external entity "missing.xml"\n' err="" def callback(ctx, str): @@ -27,4 +30,10 @@ while i > 0: err = "" i = i - 1 -print "OK" +# 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/tests/push.py b/python/tests/push.py index 738d3e95..5b60a164 100755 --- a/python/tests/push.py +++ b/python/tests/push.py @@ -2,6 +2,9 @@ import sys import libxml2 +# Memory debug specific +libxml2.debugMemory(1) + ctxt = libxml2.createPushParser(None, "", 2, 1) doc = ctxt.doc() @@ -22,4 +25,11 @@ while i > 0: doc.freeDoc() i = i -1 ctxt=None -print "OK" + +# 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/tests/tst.py b/python/tests/tst.py index dc6e4d4e..9540cda7 100755 --- a/python/tests/tst.py +++ b/python/tests/tst.py @@ -2,6 +2,9 @@ import sys import libxml2 +# Memory debug specific +libxml2.debugMemory(1) + doc = libxml2.parseFile("tst.xml") if doc.name != "tst.xml": print "doc.name failed" @@ -15,4 +18,11 @@ if child.name != "foo": print "child.name failed" sys.exit(1) doc.freeDoc() -print "OK" + +# 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/tests/tstxpath.py b/python/tests/tstxpath.py index 97d392c3..9fc3d4c4 100755 --- a/python/tests/tstxpath.py +++ b/python/tests/tstxpath.py @@ -2,6 +2,10 @@ import sys import libxml2 +#memory debug specific +libxml2.debugMemory(1) + + def foo(x): return x + 1 @@ -35,4 +39,12 @@ while i > 0: sys.exit(1) i = i - 1 doc.freeDoc() -print "OK" +del ctxt + +#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/tests/validate.py b/python/tests/validate.py index 5762f609..e9841a91 100755 --- a/python/tests/validate.py +++ b/python/tests/validate.py @@ -2,6 +2,9 @@ import sys import libxml2 +# Memory debug specific +libxml2.debugMemory(1) + ctxt = libxml2.createFileParserCtxt("valid.xml") ctxt.validate(1) ctxt.parseDocument() @@ -68,5 +71,12 @@ while i > 0: print "validity check failed" sys.exit(1) i = i - 1 +del ctxt -print "OK" +# 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/tests/xpath.py b/python/tests/xpath.py index 49a697f6..0d35a99e 100755 --- a/python/tests/xpath.py +++ b/python/tests/xpath.py @@ -6,6 +6,9 @@ import sys import libxml2 +# Memory debug specific +libxml2.debugMemory(1) + doc = libxml2.parseFile("tst.xml") if doc.name != "tst.xml": print "doc.name error" @@ -27,4 +30,12 @@ while i > 0: res = ctxt.xpathEval("//*") doc.freeDoc() i = i -1 -print "OK" +del ctxt + +# 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/tests/xpathext.py b/python/tests/xpathext.py index 97d392c3..14cb69fb 100755 --- a/python/tests/xpathext.py +++ b/python/tests/xpathext.py @@ -2,6 +2,9 @@ import sys import libxml2 +# Memory debug specific +libxml2.debugMemory(1) + def foo(x): return x + 1 @@ -35,4 +38,12 @@ while i > 0: sys.exit(1) i = i - 1 doc.freeDoc() -print "OK" +del ctxt + +# 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 07a178eb..56f472f3 100644 --- a/python/types.c +++ b/python/types.c @@ -19,6 +19,17 @@ libxml_intWrap(int val) { return(ret); } +PyObject * +libxml_longWrap(long val) { + PyObject *ret; + +#ifdef DEBUG + printf("libxml_longWrap: val = %ld\n", val); +#endif + ret = PyInt_FromLong(val); + return(ret); +} + PyObject * libxml_doubleWrap(double val) { PyObject *ret;