# HG changeset patch
# User Daniel Veillard <veillard@src.gnome.org>
# Date 1042496914 0
#      Mon Jan 13 22:28:34 2003 +0000
# Node ID aff45361f72a4dffe1b94e6aaf409f92daca482b
# Parent  f15da7b56debabf12178452578d2ec346d55e437
fixing bug #101602 for extension modules init and shutdown callbacks,

* libxslt/extensions.c libxslt/transform.c: fixing bug #101602
  for extension modules init and shutdown callbacks, check that
  they are now called when needed.
* python/libxsl.py python/libxslt-python-api.xml python/libxslt.c:
  started adding the extension module support at the Python level.
  Still a strange bug to hunt down left.
Daniel

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Mon Jan 13 23:25:59 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+	* libxslt/extensions.c libxslt/transform.c: fixing bug #101602
+	  for extension modules init and shutdown callbacks, check that
+	  they are now called when needed.
+	* python/libxsl.py python/libxslt-python-api.xml python/libxslt.c:
+	  started adding the extension module support at the Python level.
+	  Still a strange bug to hunt down left.
+
 Sun Jan 12 23:56:18 CET 2003 Daniel Veillard <daniel@veillard.com>
 
 	* libxslt/attributes.c libxslt/xsltInternals.h libxslt/imports.c
diff --git a/libxslt/extensions.c b/libxslt/extensions.c
--- a/libxslt/extensions.c
+++ b/libxslt/extensions.c
@@ -306,6 +306,10 @@
     if ((style == NULL) || (prefix == NULL) | (URI == NULL))
 	return(-1);
 
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+	 "Registering extension prefix %s : %s\n", prefix, URI);
+#endif
     def = (xsltExtDefPtr) style->nsDefs;
     while (def != NULL) {
 	if (xmlStrEqual(prefix, def->prefix))
@@ -317,6 +321,21 @@
 	return(-1);
     ret->next = (xsltExtDefPtr) style->nsDefs;
     style->nsDefs = ret;
+
+    /*
+     * check wether there is an extension module with a stylesheet
+     * initialization function.
+     */
+    if (xsltExtensionsHash != NULL) {
+	xsltExtModulePtr module;
+
+	module = xmlHashLookup(xsltExtensionsHash, URI);
+	if (module != NULL) {
+	    xsltExtDataPtr data;
+
+	    data = xsltStyleGetExtData(style, URI);
+	}
+    }
     return(0);
 }
 
@@ -438,17 +457,19 @@
 #endif
 	    return(NULL);
 	} else {
-	    if (module->styleInitFunc == NULL)
-		return(NULL);
-
+	    if (module->styleInitFunc == NULL) {
 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
-	    xsltGenericDebug(xsltGenericDebugContext,
-			     "Initializing module: %s\n", URI);
+		xsltGenericDebug(xsltGenericDebugContext,
+			     "Registering style module: %s\n", URI);
 #endif
-
-	    extData = module->styleInitFunc(style, URI);
-	    if (extData == NULL)
-		return(NULL);
+		extData = NULL;
+	    } else {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+		xsltGenericDebug(xsltGenericDebugContext,
+				 "Initializing module: %s\n", URI);
+#endif
+		extData = module->styleInitFunc(style, URI);
+	    }
 
 	    data = xsltNewExtData(module, extData);
 	    if (data == NULL)
@@ -576,7 +597,6 @@
 	xsltGenericDebug(xsltGenericDebugContext,
 			 "xsltInitCtxtExt: no extData\n");
 #endif
-	return;
     }
     ctxtData = xsltNewExtData(module, extData);
     if (ctxtData == NULL) {
diff --git a/libxslt/transform.c b/libxslt/transform.c
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -401,7 +401,6 @@
 	cur->extrasMax = 0;
     }
 
-
     XSLT_REGISTER_VARIABLE_LOOKUP(cur);
     XSLT_REGISTER_FUNCTION_LOOKUP(cur);
     cur->xpathCtxt->nsHash = style->nsHash;
@@ -420,6 +419,7 @@
     cur->xinclude = xsltDoXIncludeDefault;
     cur->outputFile = NULL;
     cur->sec = xsltGetDefaultSecurityPrefs();
+
     return(cur);
 }
 
@@ -433,6 +433,13 @@
 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
     if (ctxt == NULL)
 	return;
+
+    /*
+     * Shutdown the extension modules associated to the stylesheet
+     * used if needed.
+     */
+    xsltShutdownCtxtExts(ctxt);
+
     if (ctxt->xpathCtxt != NULL) {
 	ctxt->xpathCtxt->nsHash = NULL;
 	xmlXPathFreeContext(ctxt->xpathCtxt);
diff --git a/python/libxsl.py b/python/libxsl.py
--- a/python/libxsl.py
+++ b/python/libxsl.py
@@ -49,6 +49,37 @@
         import libxsltmod
         import libxml2
 
+class extensionModule:
+    def _styleInit(self, style, URI):
+        return self.styleInit(stylesheet(_obj=style), URI)
+
+    def _styleShutdown(self, style, URI, data):
+        return self.styleShutdown(stylesheet(_obj=style), URI, data)
+
+    def _ctxtInit(self, ctxt, URI):
+        return self.ctxtInit(transformCtxt(_obj=ctxt), URI)
+
+    def _ctxtShutdown(self, ctxt, URI, data):
+        return self.ctxtShutdown(transformCtxt(_obj=ctxt), URI, data)
+
+    def styleInit(self, style, URI):
+        """Callback function when used in a newly compiled stylesheet,
+	   the return value is passed in subsequent calls"""
+	pass
+
+    def styleShutdown(self, style, URI, data):
+        """Callback function when a stylesheet using it is destroyed"""
+	pass
+
+    def ctxtInit(self, ctxt, URI):
+        """Callback function when used in a new transformation process,
+	   the return value is passed in subsequent calls"""
+	pass
+
+    def ctxtShutdown(self, ctxt, URI, data):
+        """Callback function when a transformation using it finishes"""
+	pass
+
 #
 # Everything below this point is automatically generated
 #
diff --git a/python/libxslt-python-api.xml b/python/libxslt-python-api.xml
--- a/python/libxslt-python-api.xml
+++ b/python/libxslt-python-api.xml
@@ -31,6 +31,12 @@
       <arg name='URI' type='xmlChar *' info='the namespace or NULL'/>
       <arg name='f' type='pythonObject' info='the python function'/>
     </function>
+    <function name='xsltRegisterExtensionClass' file='python'>
+      <info>Register a Python written extension class to the XSLT engine</info>
+      <return type='int' info="0 in case of success, -1 in case of error"/>
+      <arg name='URI' type='xmlChar *' info='the namespace or NULL'/>
+      <arg name='c' type='pythonObject' info='the python class instance'/>
+    </function>
     <function name='xsltCleanup' file='python'>
       <info>Cleanup all libxslt and libxml2 memory allocated</info>
       <return type='void'/>
diff --git a/python/libxslt.c b/python/libxslt.c
--- a/python/libxslt.c
+++ b/python/libxslt.c
@@ -24,9 +24,10 @@
 #endif
 
 /* #define DEBUG */
-/* #define DEBUG_XPATH */
+#define DEBUG_XPATH */
 /* #define DEBUG_ERROR */
 /* #define DEBUG_MEMORY */
+#define DEBUG_EXTENSIONS */
 
 void initlibxsltmod(void);
 
@@ -131,7 +132,7 @@
     xmlChar *ns_uri;
     PyObject *pyobj_f;
 
-    if (!PyArg_ParseTuple(args, (char *)"szO:registerXPathFunction",
+    if (!PyArg_ParseTuple(args, (char *)"szO:registerExtModuleFunction",
 		          &name, &ns_uri, &pyobj_f))
         return(NULL);
 
@@ -411,6 +412,195 @@
 
 /************************************************************************
  *									*
+ *			Extension classes				*
+ *									*
+ ************************************************************************/
+
+static xmlHashTablePtr libxslt_extModuleClasses = NULL;
+
+static void *
+libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style,
+	                            const xmlChar * URI) {
+    PyObject *result;
+    PyObject *class = NULL;
+
+#ifdef DEBUG_EXTENSIONS
+    printf("libxslt_xsltPythonExtModuleStyleInit(%p, %s) called\n",
+	   style, URI);
+#endif
+
+    if ((style == NULL) || (URI == NULL))
+	return(NULL);
+
+    /*
+     * Find the function, it should be there it was there at lookup
+     */
+    class = xmlHashLookup(libxslt_extModuleClasses, URI);
+    if (class == NULL) {
+	fprintf(stderr, "libxslt_xsltPythonExtModuleStyleInit: internal error %s not found !\n", URI);
+	return(NULL);
+    }
+
+    if (PyObject_HasAttrString(class, (char *) "_styleInit")) {
+	result = PyObject_CallMethod(class, (char *) "_styleInit",
+		     (char *) "Os", libxslt_xsltStylesheetPtrWrap(style), URI);
+    }
+    return((void *)result);
+}
+static void
+libxslt_xsltPythonExtModuleStyleShutdown(xsltStylesheetPtr style,
+	                                const xmlChar * URI, void *data) {
+    PyObject *class = NULL;
+    PyObject *result;
+
+#ifdef DEBUG_EXTENSIONS
+    printf("libxslt_xsltPythonExtModuleStyleShutdown(%p, %s, %p) called\n",
+	   style, URI, data);
+#endif
+
+    if ((style == NULL) || (URI == NULL))
+	return;
+
+    /*
+     * Find the function, it should be there it was there at lookup
+     */
+    class = xmlHashLookup(libxslt_extModuleClasses, URI);
+    if (class == NULL) {
+	fprintf(stderr, "libxslt_xsltPythonExtModuleStyleShutdown: internal error %s not found !\n", URI);
+	return(NULL);
+    }
+
+    if (PyObject_HasAttrString(class, (char *) "_styleShutdown")) {
+	result = PyObject_CallMethod(class, (char *) "_styleShutdown",
+		     (char *) "OsO", libxslt_xsltStylesheetPtrWrap(style),
+		     URI, (PyObject *) data);
+	Py_XDECREF(result);
+	Py_XDECREF((PyObject *)data);
+    }
+}
+
+static void *
+libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt,
+	                            const xmlChar * URI) {
+    PyObject *result;
+    PyObject *class = NULL;
+
+#ifdef DEBUG_EXTENSIONS
+    printf("libxslt_xsltPythonExtModuleCtxtInit(%p, %s) called\n",
+	   ctxt, URI);
+#endif
+
+    if ((ctxt == NULL) || (URI == NULL))
+	return(NULL);
+
+    /*
+     * Find the function, it should be there it was there at lookup
+     */
+    class = xmlHashLookup(libxslt_extModuleClasses, URI);
+    if (class == NULL) {
+	fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtInit: internal error %s not found !\n", URI);
+	return(NULL);
+    }
+
+    if (PyObject_HasAttrString(class, (char *) "_ctxtInit")) {
+	result = PyObject_CallMethod(class, (char *) "_ctxtInit",
+		     (char *) "Os", libxslt_xsltTransformContextPtrWrap(ctxt),
+		     URI);
+    }
+    return((void *)result);
+}
+static void
+libxslt_xsltPythonExtModuleCtxtShutdown(xsltTransformContextPtr ctxt,
+	                                const xmlChar * URI, void *data) {
+    PyObject *class = NULL;
+    PyObject *result;
+
+#ifdef DEBUG_EXTENSIONS
+    printf("libxslt_xsltPythonExtModuleCtxtShutdown(%p, %s, %p) called\n",
+	   ctxt, URI, data);
+#endif
+
+    if ((ctxt == NULL) || (URI == NULL))
+	return;
+
+    /*
+     * Find the function, it should be there it was there at lookup
+     */
+    class = xmlHashLookup(libxslt_extModuleClasses, URI);
+    if (class == NULL) {
+	fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtShutdown: internal error %s not found !\n", URI);
+	return(NULL);
+    }
+
+    if (PyObject_HasAttrString(class, (char *) "_ctxtShutdown")) {
+	result = PyObject_CallMethod(class, (char *) "_ctxtShutdown",
+		     (char *) "OsO", libxslt_xsltTransformContextPtrWrap(ctxt),
+		     URI, (PyObject *) data);
+	Py_XDECREF(result);
+	Py_XDECREF((PyObject *)data);
+    }
+}
+
+PyObject *
+libxslt_xsltRegisterExtensionClass(PyObject *self ATTRIBUTE_UNUSED,
+	                           PyObject *args) {
+    PyObject *py_retval;
+    int ret = 0;
+    xmlChar *name;
+    xmlChar *ns_uri;
+    PyObject *pyobj_c;
+
+    if (!PyArg_ParseTuple(args, (char *)"zO:registerExtensionClass",
+		          &ns_uri, &pyobj_c))
+        return(NULL);
+
+    if ((ns_uri == NULL) || (pyobj_c == NULL)) {
+	py_retval = libxml_intWrap(-1);
+	return(py_retval);
+    }
+
+#ifdef DEBUG_EXTENSIONS
+    printf("libxslt_xsltRegisterExtensionClass(%s) called\n", ns_uri);
+#endif
+
+    if (libxslt_extModuleClasses == NULL)
+	libxslt_extModuleClasses = xmlHashCreate(10);
+    if (libxslt_extModuleClasses == NULL) {
+	py_retval = libxml_intWrap(-1);
+	return(py_retval);
+    }
+    ret = xmlHashAddEntry(libxslt_extModuleClasses, ns_uri, pyobj_c);
+    if (ret != 0) {
+	py_retval = libxml_intWrap(-1);
+	return(py_retval);
+    }
+    Py_XINCREF(pyobj_c);
+
+    ret = xsltRegisterExtModuleFull(ns_uri, 
+       (xsltExtInitFunction) libxslt_xsltPythonExtModuleCtxtInit,
+       (xsltExtShutdownFunction) libxslt_xsltPythonExtModuleCtxtShutdown,
+       (xsltStyleExtInitFunction) libxslt_xsltPythonExtModuleStyleInit,
+       (xsltStyleExtShutdownFunction) libxslt_xsltPythonExtModuleStyleShutdown);
+    py_retval = libxml_intWrap((int) ret);
+    if (ret < 0) {
+	Py_XDECREF(pyobj_c);
+    }
+    return(py_retval);
+}
+
+static void
+deallocateClasse(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
+    PyObject *class = (PyObject *) payload;
+
+#ifdef DEBUG_EXTENSIONS
+    printf("deallocateClasse(%s) called\n", name);
+#endif
+
+    Py_XDECREF(class);
+}
+
+/************************************************************************
+ *									*
  *			Integrated cleanup				*
  *									*
  ************************************************************************/
@@ -422,6 +612,9 @@
     if (libxslt_extModuleFunctions != NULL) {
 	xmlHashFree(libxslt_extModuleFunctions, deallocateCallback);
     }
+    if (libxslt_extModuleClasses != NULL) {
+	xmlHashFree(libxslt_extModuleClasses, deallocateClasse);
+    }
     xsltCleanupGlobals();
     xmlCleanupParser();
     Py_INCREF(Py_None);
diff --git a/python/libxsltclass.txt b/python/libxsltclass.txt
--- a/python/libxsltclass.txt
+++ b/python/libxsltclass.txt
@@ -20,6 +20,7 @@
 cleanup()
 registerErrorHandler()
 registerExtModuleFunction()
+registerExtensionClass()
 
 # functions from module transform
 setXIncludeDefault()