minor cleanup for various compilation warnings (AIX as well as gcc)
[platform/upstream/libxslt.git] / python / libxslt.c
1 /*
2  * libxslt.c: this modules implements the main part of the glue of the
3  *           libxslt library and the Python interpreter. It provides the
4  *           entry points where an automatically generated stub is either
5  *           unpractical or would not match cleanly the Python model.
6  *
7  * If compiled with MERGED_MODULES, the entry point will be used to
8  * initialize both the libxml2 and the libxslt wrappers
9  *
10  * See Copyright for the status of this software.
11  *
12  * daniel@veillard.com
13  */
14 #include <Python.h>
15 /* #include "config.h" */
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/xpath.h>
19 #include "libexslt/exslt.h"
20 #include "libxslt_wrap.h"
21 #include "libxslt-py.h"
22
23 #if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(vsnprintf)
24 #define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
25 #elif defined(XSLT_NEED_TRIO)
26 #include "trio.h"
27 #define vsnprintf trio_vsnprintf
28 #endif
29
30 /* #define DEBUG */
31 /* #define DEBUG_XPATH */
32 /* #define DEBUG_ERROR */
33 /* #define DEBUG_MEMORY */
34 /* #define DEBUG_EXTENSIONS */
35 /* #define DEBUG_EXTENSIONS */
36
37 void initlibxsltmod(void);
38
39 /************************************************************************
40  *                                                                      *
41  *                      Per type specific glue                          *
42  *                                                                      *
43  ************************************************************************/
44
45 PyObject *
46 libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr style) {
47     PyObject *ret;
48
49 #ifdef DEBUG
50     printf("libxslt_xsltStylesheetPtrWrap: style = %p\n", style);
51 #endif
52     if (style == NULL) {
53         Py_INCREF(Py_None);
54         return(Py_None);
55     }
56     ret = PyCObject_FromVoidPtrAndDesc((void *) style,
57                                        (char *)"xsltStylesheetPtr", NULL);
58     return(ret);
59 }
60
61 PyObject *
62 libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt) {
63     PyObject *ret;
64
65 #ifdef DEBUG
66     printf("libxslt_xsltTransformContextPtrWrap: ctxt = %p\n", ctxt);
67 #endif
68     if (ctxt == NULL) {
69         Py_INCREF(Py_None);
70         return(Py_None);
71     }
72     ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
73                                        (char *)"xsltTransformContextPtr", NULL);
74     return(ret);
75 }
76
77 PyObject *
78 libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr ctxt) {
79     PyObject *ret;
80
81 #ifdef DEBUG
82     printf("libxslt_xsltElemPreCompPtrWrap: ctxt = %p\n", ctxt);
83 #endif
84     if (ctxt == NULL) {
85         Py_INCREF(Py_None);
86         return(Py_None);
87     }
88     ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
89                                        (char *)"xsltElemPreCompPtr", NULL);
90     return(ret);
91 }
92
93 /************************************************************************
94  *                                                                      *
95  *                      Extending the API                               *
96  *                                                                      *
97  ************************************************************************/
98
99 static xmlHashTablePtr libxslt_extModuleFunctions = NULL;
100 static xmlHashTablePtr libxslt_extModuleElements = NULL;
101 static xmlHashTablePtr libxslt_extModuleElementPreComp = NULL;
102
103 static void
104 deallocateCallback(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
105     PyObject *function = (PyObject *) payload;
106
107 #ifdef DEBUG_EXTENSIONS
108     printf("deallocateCallback(%s) called\n", name);
109 #endif
110
111     Py_XDECREF(function);
112 }
113
114 static void
115 deallocateClasse(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
116     PyObject *class = (PyObject *) payload;
117
118 #ifdef DEBUG_EXTENSIONS
119     printf("deallocateClasse(%s) called\n", name);
120 #endif
121
122     Py_XDECREF(class);
123 }
124
125
126 /**
127  * libxslt_xsltElementPreCompCallback
128  * @style:  the stylesheet
129  * @inst:  the instruction in the stylesheet
130  *
131  * Callback for preprocessing of a custom element
132  */
133 static xsltElemPreCompPtr
134 libxslt_xsltElementPreCompCallback(xsltStylesheetPtr style, xmlNodePtr inst,
135               xsltTransformFunction function) {
136     xsltElemPreCompPtr ret;
137     const xmlChar *name;
138     PyObject *args;
139     PyObject *result;
140     PyObject *pyobj_element_f;
141     PyObject *pyobj_precomp_f;
142
143    const xmlChar *ns_uri;
144
145
146 #ifdef DEBUG_EXTENSIONS
147     printf("libxslt_xsltElementPreCompCallback called\n");
148 #endif
149
150     if (style == NULL) {
151         xsltTransformError(NULL, NULL, inst,
152              "libxslt_xsltElementPreCompCallback: no transformation context\n");
153             return (NULL);
154     }
155
156     if (inst == NULL) {
157         xsltTransformError(NULL, style, inst,
158              "libxslt_xsltElementPreCompCallback: no instruction\n");
159         if (style != NULL) style->errors++;
160         return (NULL);
161     }
162
163     if (style == NULL)
164         return (NULL);
165     
166     if (inst != NULL && inst->ns != NULL) {
167         name = inst->name;
168         ns_uri = inst->ns->href;
169     } else {
170         xsltTransformError(NULL, style, inst, 
171                 "libxslt_xsltElementPreCompCallback: internal error bad parameter\n");
172                 printf("libxslt_xsltElementPreCompCallback: internal error bad parameter\n");
173         if (style != NULL) style->errors++;
174         return (NULL);
175     }
176
177     /*
178      * Find the functions, they should be there it was there at lookup
179      */
180     pyobj_precomp_f = xmlHashLookup2(libxslt_extModuleElementPreComp,
181                                       name, ns_uri);
182     if (pyobj_precomp_f == NULL) {
183         xsltTransformError(NULL, style, inst, 
184                 "libxslt_xsltElementPreCompCallback: internal error, could not find precompile python function!\n");
185         if (style != NULL) style->errors++;
186         return (NULL);
187     }
188
189     pyobj_element_f = xmlHashLookup2(libxslt_extModuleElements,
190                                       name, ns_uri);
191     if (pyobj_element_f == NULL) {
192         xsltTransformError(NULL, style, inst, 
193                 "libxslt_xsltElementPreCompCallback: internal error, could not find element python function!\n");
194         if (style != NULL) style->errors++;
195         return (NULL);
196     }
197
198     args = Py_BuildValue("(OOO)", 
199             libxslt_xsltStylesheetPtrWrap(style),
200             libxml_xmlNodePtrWrap(inst),
201             pyobj_element_f);
202
203     Py_INCREF(pyobj_precomp_f); /* Protect refcount against reentrant manipulation of callback hash */
204     result = PyEval_CallObject(pyobj_precomp_f, args);
205     Py_DECREF(pyobj_precomp_f);
206     Py_DECREF(args);
207
208     /* FIXME allow callbacks to return meaningful information to modify compile process */
209     /* If error, do we need to check the result and throw exception? */
210
211     Py_XDECREF(result);
212
213     ret = xsltNewElemPreComp (style, inst, function);
214     return (ret);
215 }
216
217
218 static void
219 libxslt_xsltElementTransformCallback(xsltTransformContextPtr ctxt,
220                                     xmlNodePtr node, 
221                                     xmlNodePtr inst,
222                                     xsltElemPreCompPtr comp) 
223 {
224     PyObject *args, *result;
225     PyObject *func = NULL;
226     const xmlChar *name;
227     const xmlChar *ns_uri;
228
229     if (ctxt == NULL)
230         return;
231     
232     if (inst != NULL && inst->name != NULL && inst->ns != NULL && inst->ns->href != NULL) {
233         name = inst->name;
234         ns_uri = inst->ns->href;
235     } else {
236         printf("libxslt_xsltElementTransformCallback: internal error bad parameter\n");
237         return;
238     }
239
240 #ifdef DEBUG_EXTENSIONS
241     printf("libxslt_xsltElementTransformCallback called name %s URI %s\n", name, ns_uri);
242 #endif
243
244     /*
245      * Find the function, it should be there it was there at lookup
246      */
247     func = xmlHashLookup2(libxslt_extModuleElements,
248                                       name, ns_uri);
249     if (func == NULL) {
250         printf("libxslt_xsltElementTransformCallback: internal error %s not found !\n",
251                name);
252         return;
253     }
254
255     args = Py_BuildValue("OOOO",
256         libxslt_xsltTransformContextPtrWrap(ctxt),
257         libxml_xmlNodePtrWrap(node),
258         libxml_xmlNodePtrWrap(inst),
259         libxslt_xsltElemPreCompPtrWrap(comp));
260
261     Py_INCREF(func); /* Protect refcount against reentrant manipulation of callback hash */
262     result = PyEval_CallObject(func, args);
263     Py_DECREF(func);
264     Py_DECREF(args);
265
266     /* FIXME Check result of callobject and set exception if fail */
267
268     Py_XDECREF(result);
269 }
270
271 PyObject *
272 libxslt_xsltRegisterExtModuleElement(PyObject *self ATTRIBUTE_UNUSED,
273                                       PyObject *args) {
274     PyObject *py_retval;
275     int ret = 0;
276     xmlChar *name;
277     xmlChar *ns_uri;
278     PyObject *pyobj_element_f;
279     PyObject *pyobj_precomp_f;
280
281 #ifdef DEBUG_EXTENSIONS
282     printf("libxslt_xsltRegisterExtModuleElement called\n",
283            name, ns_uri);
284 #endif
285
286     if (!PyArg_ParseTuple(args, (char *)"szOO:registerExtModuleElement",
287                           &name, &ns_uri, &pyobj_precomp_f, &pyobj_element_f))
288         return(NULL);
289
290     if ((name == NULL) || (pyobj_element_f == NULL) || (pyobj_precomp_f == NULL)) {
291         py_retval = libxml_intWrap(-1);
292         return(py_retval);
293     }
294
295 #ifdef DEBUG_EXTENSIONS
296     printf("libxslt_xsltRegisterExtModuleElement(%s, %s) called\n",
297            name, ns_uri);
298 #endif
299
300     if (libxslt_extModuleElements == NULL)
301         libxslt_extModuleElements = xmlHashCreate(10);
302
303     if (libxslt_extModuleElementPreComp == NULL)
304         libxslt_extModuleElementPreComp = xmlHashCreate(10);
305
306     if (libxslt_extModuleElements == NULL || libxslt_extModuleElementPreComp == NULL) {
307         py_retval = libxml_intWrap(-1);
308         return(py_retval);
309     }
310
311     ret = xmlHashAddEntry2(libxslt_extModuleElements, name, ns_uri, pyobj_element_f);
312     if (ret != 0) {
313         py_retval = libxml_intWrap(-1);
314         return(py_retval);
315     }
316     Py_XINCREF(pyobj_element_f);
317
318     ret = xmlHashAddEntry2(libxslt_extModuleElementPreComp, name, ns_uri, pyobj_precomp_f);
319     if (ret != 0) {
320         xmlHashRemoveEntry2(libxslt_extModuleElements, name, ns_uri, deallocateCallback);
321         py_retval = libxml_intWrap(-1);
322         return(py_retval);
323     }
324     Py_XINCREF(pyobj_precomp_f);
325
326     ret = xsltRegisterExtModuleElement(name, ns_uri, 
327                                         libxslt_xsltElementPreCompCallback,
328                                         libxslt_xsltElementTransformCallback);
329     py_retval = libxml_intWrap((int) ret);
330     return(py_retval);
331 }
332 static void
333 libxslt_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs) {
334     PyObject *list, *cur, *result;
335     xmlXPathObjectPtr obj;
336     xmlXPathContextPtr rctxt;
337     PyObject *current_function = NULL;
338     const xmlChar *name;
339     const xmlChar *ns_uri;
340     int i;
341
342     if (ctxt == NULL)
343         return;
344     rctxt = ctxt->context;
345     if (rctxt == NULL)
346         return;
347     name = rctxt->function;
348     ns_uri = rctxt->functionURI;
349 #ifdef DEBUG_XPATH
350     printf("libxslt_xmlXPathFuncCallback called name %s URI %s\n", name, ns_uri);
351 #endif
352
353     /*
354      * Find the function, it should be there it was there at lookup
355      */
356     current_function = xmlHashLookup2(libxslt_extModuleFunctions,
357                                       name, ns_uri);
358     if (current_function == NULL) {
359         printf("libxslt_xmlXPathFuncCallback: internal error %s not found !\n",
360                name);
361         return;
362     }
363
364     list = PyTuple_New(nargs + 1);
365     PyTuple_SetItem(list, 0, libxml_xmlXPathParserContextPtrWrap(ctxt));
366     for (i = nargs - 1;i >= 0;i--) {
367         obj = valuePop(ctxt);
368         cur = libxml_xmlXPathObjectPtrWrap(obj);
369         PyTuple_SetItem(list, i + 1, cur);
370     }
371
372     Py_INCREF(current_function);
373     result = PyEval_CallObject(current_function, list);
374     Py_DECREF(current_function);
375     Py_DECREF(list);
376
377     /* Check for null in case of exception */
378     if (result != NULL) {
379         obj = libxml_xmlXPathObjectPtrConvert(result);
380         valuePush(ctxt, obj);
381     }
382 }
383
384 PyObject *
385 libxslt_xsltRegisterExtModuleFunction(PyObject *self ATTRIBUTE_UNUSED,
386                                       PyObject *args) {
387     PyObject *py_retval;
388     int ret = 0;
389     xmlChar *name;
390     xmlChar *ns_uri;
391     PyObject *pyobj_f;
392
393     if (!PyArg_ParseTuple(args, (char *)"szO:registerExtModuleFunction",
394                           &name, &ns_uri, &pyobj_f))
395         return(NULL);
396
397     if ((name == NULL) || (pyobj_f == NULL)) {
398         py_retval = libxml_intWrap(-1);
399         return(py_retval);
400     }
401
402 #ifdef DEBUG_XPATH
403     printf("libxslt_xsltRegisterExtModuleFunction(%s, %s) called\n",
404            name, ns_uri);
405 #endif
406
407     if (libxslt_extModuleFunctions == NULL)
408         libxslt_extModuleFunctions = xmlHashCreate(10);
409     if (libxslt_extModuleFunctions == NULL) {
410         py_retval = libxml_intWrap(-1);
411         return(py_retval);
412     }
413     ret = xmlHashAddEntry2(libxslt_extModuleFunctions, name, ns_uri, pyobj_f);
414     if (ret != 0) {
415         py_retval = libxml_intWrap(-1);
416         return(py_retval);
417     }
418     Py_XINCREF(pyobj_f);
419
420     ret = xsltRegisterExtModuleFunction(name, ns_uri, 
421                                              libxslt_xmlXPathFuncCallback);
422     py_retval = libxml_intWrap((int) ret);
423     return(py_retval);
424 }
425
426 /************************************************************************
427  *                                                                      *
428  *                      Some customized front-ends                      *
429  *                                                                      *
430  ************************************************************************/
431
432 PyObject *
433 libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
434     PyObject *py_retval;
435     xmlDocPtr c_retval;
436     xsltStylesheetPtr style;
437     PyObject *pyobj_style;
438     xmlDocPtr doc;
439     PyObject *pyobj_doc;
440     PyObject *pyobj_params;
441     const char **params = NULL;
442     int len = 0, i = 0, j;
443     PyObject *name;
444     PyObject *value;
445
446     if (!PyArg_ParseTuple(args, (char *) "OOO:xsltApplyStylesheet",
447                           &pyobj_style, &pyobj_doc, &pyobj_params))
448         return(NULL);
449
450     if (pyobj_params != Py_None) {
451         if (PyDict_Check(pyobj_params)) {
452             len = PyDict_Size(pyobj_params);
453             if (len > 0) {
454                 params = (const char **) xmlMalloc((len + 1) * 2 *
455                                                    sizeof(char *));
456                 if (params == NULL) {
457                     printf("libxslt_xsltApplyStylesheet: out of memory\n");
458                     Py_INCREF(Py_None);
459                     return(Py_None);
460                 }
461                 j = 0;
462                 while (PyDict_Next(pyobj_params, &i, &name, &value)) {
463                     const char *tmp;
464                     int size;
465
466                     tmp = PyString_AS_STRING(name);
467                     size = PyString_GET_SIZE(name);
468                     params[j * 2] = (char *) xmlCharStrndup(tmp, size);
469                     if (PyString_Check(value)) {
470                         tmp = PyString_AS_STRING(value);
471                         size = PyString_GET_SIZE(value);
472                         params[(j * 2) + 1] = (char *)
473                             xmlCharStrndup(tmp, size);
474                     } else {
475                         params[(j * 2) + 1] = NULL;
476                     }
477                     j = j + 1;
478                 }
479                 params[j * 2] = NULL;
480                 params[(j * 2) + 1] = NULL;
481             }
482         } else {
483             printf("libxslt_xsltApplyStylesheet: parameters not a dict\n");
484             Py_INCREF(Py_None);
485             return(Py_None);
486         }
487     }
488     style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
489     doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
490
491     c_retval = xsltApplyStylesheet(style, doc, params);
492     py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval);
493     if (params != NULL) {
494         if (len > 0) {
495             for (i = 0;i < 2 * len;i++) {
496                 if (params[i] != NULL)
497                     xmlFree((char *)params[i]);
498             }
499             xmlFree(params);
500         }
501     }
502     return(py_retval);
503 }
504
505 PyObject *
506 libxslt_xsltSaveResultToString(PyObject *self, PyObject *args) {
507     PyObject *py_retval;        /* our final return value, a python string   */ 
508     xmlChar  *buffer;
509     int       size    = 0;
510     int       emitted = 0;
511     xmlDocPtr result;
512     PyObject *pyobj_result;
513     xsltStylesheetPtr style;
514     PyObject *pyobj_style;
515
516     if (!PyArg_ParseTuple(args, (char *)"OO:xsltSaveResultToString", &pyobj_style, &pyobj_result))
517       goto FAIL;
518     result = (xmlDocPtr) PyxmlNode_Get(pyobj_result);
519     style  = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
520
521      
522     /* FIXME: We should probably add more restrictive error checking
523      * and raise an error instead of "just" returning NULL.
524      * FIXME: Documentation and code for xsltSaveResultToString diff
525      * -> emmitted will never be positive non-null. 
526      */
527     emitted = xsltSaveResultToString(&buffer, &size, result, style);
528     if(!buffer || emitted < 0) 
529       goto FAIL;
530     /* We haven't tested the aberrant case of a transformation that
531      * renders to an empty string. For now we try to play it save.
532      */
533     if(size)
534       {
535       buffer[size] = '\0';
536       py_retval = PyString_FromString((char *) buffer); 
537       xmlFree(buffer);
538       }
539     else
540       py_retval = PyString_FromString("");
541     return(py_retval);
542  FAIL:
543     return(0);
544 }
545
546
547 /************************************************************************
548  *                                                                      *
549  *                      Error message callback                          *
550  *                                                                      *
551  ************************************************************************/
552
553 static PyObject *libxslt_xsltPythonErrorFuncHandler = NULL;
554 static PyObject *libxslt_xsltPythonErrorFuncCtxt = NULL;
555
556 static void
557 libxslt_xsltErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg,
558                            ...)
559 {
560     int size;
561     int chars;
562     char *larger;
563     va_list ap;
564     char *str;
565     PyObject *list;
566     PyObject *message;
567     PyObject *result;
568
569 #ifdef DEBUG_ERROR
570     printf("libxslt_xsltErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
571 #endif
572
573
574     if (libxslt_xsltPythonErrorFuncHandler == NULL) {
575         va_start(ap, msg);
576         vfprintf(stderr, msg, ap);
577         va_end(ap);
578     } else {
579         str = (char *) xmlMalloc(150);
580         if (str == NULL)
581             return;
582
583         size = 150;
584
585         while (1) {
586             va_start(ap, msg);
587             chars = vsnprintf(str, size, msg, ap);
588             va_end(ap);
589             if ((chars > -1) && (chars < size))
590                 break;
591             if (chars > -1)
592                 size += chars + 1;
593             else
594                 size += 100;
595             if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
596                 xmlFree(str);
597                 return;
598             }
599             str = larger;
600         }
601
602         list = PyTuple_New(2);
603         PyTuple_SetItem(list, 0, libxslt_xsltPythonErrorFuncCtxt);
604         Py_XINCREF(libxslt_xsltPythonErrorFuncCtxt);
605         message = libxml_charPtrWrap(str);
606         PyTuple_SetItem(list, 1, message);
607         result = PyEval_CallObject(libxslt_xsltPythonErrorFuncHandler, list);
608         Py_XDECREF(list);
609         Py_XDECREF(result);
610     }
611 }
612
613 static void
614 libxslt_xsltErrorInitialize(void)
615 {
616 #ifdef DEBUG_ERROR
617     printf("libxslt_xsltErrorInitialize() called\n");
618 #endif
619     xmlSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler);
620     xsltSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler);
621 }
622
623 PyObject *
624 libxslt_xsltRegisterErrorHandler(ATTRIBUTE_UNUSED PyObject * self,
625                                PyObject * args)
626 {
627     PyObject *py_retval;
628     PyObject *pyobj_f;
629     PyObject *pyobj_ctx;
630
631     if (!PyArg_ParseTuple
632         (args, (char *) "OO:xmlRegisterErrorHandler", &pyobj_f,
633          &pyobj_ctx))
634         return (NULL);
635
636 #ifdef DEBUG_ERROR
637     printf("libxml_registerXPathFunction(%p, %p) called\n", pyobj_ctx,
638            pyobj_f);
639 #endif
640
641     if (libxslt_xsltPythonErrorFuncHandler != NULL) {
642         Py_XDECREF(libxslt_xsltPythonErrorFuncHandler);
643     }
644     if (libxslt_xsltPythonErrorFuncCtxt != NULL) {
645         Py_XDECREF(libxslt_xsltPythonErrorFuncCtxt);
646     }
647
648     Py_XINCREF(pyobj_ctx);
649     Py_XINCREF(pyobj_f);
650
651     /* TODO: check f is a function ! */
652     libxslt_xsltPythonErrorFuncHandler = pyobj_f;
653     libxslt_xsltPythonErrorFuncCtxt = pyobj_ctx;
654
655     py_retval = libxml_intWrap(1);
656     return (py_retval);
657 }
658
659 /************************************************************************
660  *                                                                      *
661  *                      Extension classes                               *
662  *                                                                      *
663  ************************************************************************/
664
665 static xmlHashTablePtr libxslt_extModuleClasses = NULL;
666
667 static void *
668 libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style,
669                                     const xmlChar * URI) {
670     PyObject *result = NULL;
671     PyObject *class = NULL;
672
673 #ifdef DEBUG_EXTENSIONS
674     printf("libxslt_xsltPythonExtModuleStyleInit(%p, %s) called\n",
675            style, URI);
676 #endif
677
678     if ((style == NULL) || (URI == NULL))
679         return(NULL);
680
681     /*
682      * Find the function, it should be there it was there at lookup
683      */
684     class = xmlHashLookup(libxslt_extModuleClasses, URI);
685     if (class == NULL) {
686         fprintf(stderr, "libxslt_xsltPythonExtModuleStyleInit: internal error %s not found !\n", URI);
687         return(NULL);
688     }
689
690     if (PyObject_HasAttrString(class, (char *) "_styleInit")) {
691         result = PyObject_CallMethod(class, (char *) "_styleInit",
692                      (char *) "Os", libxslt_xsltStylesheetPtrWrap(style), URI);
693     }
694     return((void *)result);
695 }
696 static void
697 libxslt_xsltPythonExtModuleStyleShutdown(xsltStylesheetPtr style,
698                                         const xmlChar * URI, void *data) {
699     PyObject *class = NULL;
700     PyObject *result;
701
702 #ifdef DEBUG_EXTENSIONS
703     printf("libxslt_xsltPythonExtModuleStyleShutdown(%p, %s, %p) called\n",
704            style, URI, data);
705 #endif
706
707     if ((style == NULL) || (URI == NULL))
708         return;
709
710     /*
711      * Find the function, it should be there it was there at lookup
712      */
713     class = xmlHashLookup(libxslt_extModuleClasses, URI);
714     if (class == NULL) {
715         fprintf(stderr, "libxslt_xsltPythonExtModuleStyleShutdown: internal error %s not found !\n", URI);
716         return;
717     }
718
719     if (PyObject_HasAttrString(class, (char *) "_styleShutdown")) {
720         result = PyObject_CallMethod(class, (char *) "_styleShutdown",
721                      (char *) "OsO", libxslt_xsltStylesheetPtrWrap(style),
722                      URI, (PyObject *) data);
723         Py_XDECREF(result);
724         Py_XDECREF((PyObject *)data);
725     }
726 }
727
728 static void *
729 libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt,
730                                     const xmlChar * URI) {
731     PyObject *result = NULL;
732     PyObject *class = NULL;
733
734 #ifdef DEBUG_EXTENSIONS
735     printf("libxslt_xsltPythonExtModuleCtxtInit(%p, %s) called\n",
736            ctxt, URI);
737 #endif
738
739     if ((ctxt == NULL) || (URI == NULL))
740         return(NULL);
741
742     /*
743      * Find the function, it should be there it was there at lookup
744      */
745     class = xmlHashLookup(libxslt_extModuleClasses, URI);
746     if (class == NULL) {
747         fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtInit: internal error %s not found !\n", URI);
748         return(NULL);
749     }
750
751     if (PyObject_HasAttrString(class, (char *) "_ctxtInit")) {
752         result = PyObject_CallMethod(class, (char *) "_ctxtInit",
753                      (char *) "Os", libxslt_xsltTransformContextPtrWrap(ctxt),
754                      URI);
755     }
756     return((void *)result);
757 }
758 static void
759 libxslt_xsltPythonExtModuleCtxtShutdown(xsltTransformContextPtr ctxt,
760                                         const xmlChar * URI, void *data) {
761     PyObject *class = NULL;
762     PyObject *result;
763
764 #ifdef DEBUG_EXTENSIONS
765     printf("libxslt_xsltPythonExtModuleCtxtShutdown(%p, %s, %p) called\n",
766            ctxt, URI, data);
767 #endif
768
769     if ((ctxt == NULL) || (URI == NULL))
770         return;
771
772     /*
773      * Find the function, it should be there it was there at lookup
774      */
775     class = xmlHashLookup(libxslt_extModuleClasses, URI);
776     if (class == NULL) {
777         fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtShutdown: internal error %s not found !\n", URI);
778         return;
779     }
780
781     if (PyObject_HasAttrString(class, (char *) "_ctxtShutdown")) {
782         result = PyObject_CallMethod(class, (char *) "_ctxtShutdown",
783                      (char *) "OsO", libxslt_xsltTransformContextPtrWrap(ctxt),
784                      URI, (PyObject *) data);
785         Py_XDECREF(result);
786         Py_XDECREF((PyObject *)data);
787     }
788 }
789
790 PyObject *
791 libxslt_xsltRegisterExtensionClass(PyObject *self ATTRIBUTE_UNUSED,
792                                    PyObject *args) {
793     PyObject *py_retval;
794     int ret = 0;
795     xmlChar *ns_uri;
796     PyObject *pyobj_c;
797
798     if (!PyArg_ParseTuple(args, (char *)"zO:registerExtensionClass",
799                           &ns_uri, &pyobj_c))
800         return(NULL);
801
802     if ((ns_uri == NULL) || (pyobj_c == NULL)) {
803         py_retval = libxml_intWrap(-1);
804         return(py_retval);
805     }
806
807 #ifdef DEBUG_EXTENSIONS
808     printf("libxslt_xsltRegisterExtensionClass(%s) called\n", ns_uri);
809 #endif
810
811     if (libxslt_extModuleClasses == NULL)
812         libxslt_extModuleClasses = xmlHashCreate(10);
813     if (libxslt_extModuleClasses == NULL) {
814         py_retval = libxml_intWrap(-1);
815         return(py_retval);
816     }
817     ret = xmlHashAddEntry(libxslt_extModuleClasses, ns_uri, pyobj_c);
818     if (ret != 0) {
819         py_retval = libxml_intWrap(-1);
820         return(py_retval);
821     }
822     Py_XINCREF(pyobj_c);
823
824     ret = xsltRegisterExtModuleFull(ns_uri, 
825        (xsltExtInitFunction) libxslt_xsltPythonExtModuleCtxtInit,
826        (xsltExtShutdownFunction) libxslt_xsltPythonExtModuleCtxtShutdown,
827        (xsltStyleExtInitFunction) libxslt_xsltPythonExtModuleStyleInit,
828        (xsltStyleExtShutdownFunction) libxslt_xsltPythonExtModuleStyleShutdown);
829     py_retval = libxml_intWrap((int) ret);
830     if (ret < 0) {
831         Py_XDECREF(pyobj_c);
832     }
833     return(py_retval);
834 }
835
836 /************************************************************************
837  *                                                                      *
838  *                      Integrated cleanup                              *
839  *                                                                      *
840  ************************************************************************/
841
842 PyObject *
843 libxslt_xsltCleanup(PyObject *self ATTRIBUTE_UNUSED,
844                     PyObject *args ATTRIBUTE_UNUSED) {
845
846     if (libxslt_extModuleFunctions != NULL) {
847         xmlHashFree(libxslt_extModuleFunctions, deallocateCallback);
848     }
849     if (libxslt_extModuleElements != NULL) {
850         xmlHashFree(libxslt_extModuleElements, deallocateCallback);
851     }
852     if (libxslt_extModuleElementPreComp != NULL) {
853         xmlHashFree(libxslt_extModuleElementPreComp, deallocateCallback);
854     }
855     if (libxslt_extModuleClasses != NULL) {
856         xmlHashFree(libxslt_extModuleClasses, deallocateClasse);
857     }
858     xsltCleanupGlobals();
859     xmlCleanupParser();
860     Py_INCREF(Py_None);
861     return(Py_None);
862 }
863
864 /************************************************************************
865  *                                                                      *
866  *                      The registration stuff                          *
867  *                                                                      *
868  ************************************************************************/
869 static PyMethodDef libxsltMethods[] = {
870 #include "libxslt-export.c"
871     { NULL, NULL, 0, NULL }
872 };
873
874 #ifdef MERGED_MODULES
875 extern void initlibxml2mod(void);
876 #endif
877
878 void initlibxsltmod(void) {
879     static int initialized = 0;
880     PyObject *m;
881
882 #ifdef MERGED_MODULES
883     initlibxml2mod();
884 #endif
885
886     if (initialized != 0)
887         return;
888     m = Py_InitModule((char *)"libxsltmod", libxsltMethods);
889     initialized = 1;
890     /*
891      * Specific XSLT initializations
892      */
893     libxslt_xsltErrorInitialize();
894     xmlInitMemory();
895     xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
896     xmlDefaultSAXHandler.cdataBlock = NULL;
897     /*
898      * Register the EXSLT extensions and the test module
899      */
900     exsltRegisterAll();
901 }
902
903