source: trunk/third/libxslt/python/libxslt.c @ 18543

Revision 18543, 18.2 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18542, which included commits to RCS files with non-trunk default branches.
Line 
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 "libxslt_wrap.h"
20#include "libxslt-py.h"
21
22#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(vsnprintf)
23#define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
24#endif
25
26/* #define DEBUG */
27/* #define DEBUG_XPATH */
28/* #define DEBUG_ERROR */
29/* #define DEBUG_MEMORY */
30/* #define DEBUG_EXTENSIONS */
31
32void initlibxsltmod(void);
33
34/************************************************************************
35 *                                                                      *
36 *                      Per type specific glue                          *
37 *                                                                      *
38 ************************************************************************/
39
40PyObject *
41libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr style) {
42    PyObject *ret;
43
44#ifdef DEBUG
45    printf("libxslt_xsltStylesheetPtrWrap: style = %p\n", style);
46#endif
47    if (style == NULL) {
48        Py_INCREF(Py_None);
49        return(Py_None);
50    }
51    ret = PyCObject_FromVoidPtrAndDesc((void *) style,
52                                       (char *)"xsltStylesheetPtr", NULL);
53    return(ret);
54}
55
56PyObject *
57libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt) {
58    PyObject *ret;
59
60#ifdef DEBUG
61    printf("libxslt_xsltTransformContextPtrWrap: ctxt = %p\n", ctxt);
62#endif
63    if (ctxt == NULL) {
64        Py_INCREF(Py_None);
65        return(Py_None);
66    }
67    ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
68                                       (char *)"xsltTransformContextPtr", NULL);
69    return(ret);
70}
71
72/************************************************************************
73 *                                                                      *
74 *                      Extending the API                               *
75 *                                                                      *
76 ************************************************************************/
77
78static xmlHashTablePtr libxslt_extModuleFunctions = NULL;
79
80static void
81libxslt_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs) {
82    PyObject *list, *cur, *result;
83    xmlXPathObjectPtr obj;
84    xmlXPathContextPtr rctxt;
85    PyObject *current_function = NULL;
86    const xmlChar *name;
87    const xmlChar *ns_uri;
88    int i;
89
90    if (ctxt == NULL)
91        return;
92    rctxt = ctxt->context;
93    if (rctxt == NULL)
94        return;
95    name = rctxt->function;
96    ns_uri = rctxt->functionURI;
97#ifdef DEBUG_XPATH
98    printf("libxslt_xmlXPathFuncCallback called name %s URI %s\n", name, ns_uri);
99#endif
100
101    /*
102     * Find the function, it should be there it was there at lookup
103     */
104    current_function = xmlHashLookup2(libxslt_extModuleFunctions,
105                                      name, ns_uri);
106    if (current_function == NULL) {
107        printf("libxslt_xmlXPathFuncCallback: internal error %s not found !\n",
108               name);
109        return;
110    }
111
112    list = PyTuple_New(nargs + 1);
113    PyTuple_SetItem(list, 0, libxml_xmlXPathParserContextPtrWrap(ctxt));
114    for (i = nargs - 1;i >= 0;i--) {
115        obj = valuePop(ctxt);
116        cur = libxml_xmlXPathObjectPtrWrap(obj);
117        PyTuple_SetItem(list, i + 1, cur);
118    }
119    result = PyEval_CallObject(current_function, list);
120    Py_DECREF(list);
121
122    obj = libxml_xmlXPathObjectPtrConvert(result);
123    valuePush(ctxt, obj);
124}
125
126PyObject *
127libxslt_xsltRegisterExtModuleFunction(PyObject *self ATTRIBUTE_UNUSED,
128                                      PyObject *args) {
129    PyObject *py_retval;
130    int ret = 0;
131    xmlChar *name;
132    xmlChar *ns_uri;
133    PyObject *pyobj_f;
134
135    if (!PyArg_ParseTuple(args, (char *)"szO:registerExtModuleFunction",
136                          &name, &ns_uri, &pyobj_f))
137        return(NULL);
138
139    if ((name == NULL) || (pyobj_f == NULL)) {
140        py_retval = libxml_intWrap(-1);
141        return(py_retval);
142    }
143
144#ifdef DEBUG_XPATH
145    printf("libxslt_xsltRegisterExtModuleFunction(%s, %s) called\n",
146           name, ns_uri);
147#endif
148
149    if (libxslt_extModuleFunctions == NULL)
150        libxslt_extModuleFunctions = xmlHashCreate(10);
151    if (libxslt_extModuleFunctions == NULL) {
152        py_retval = libxml_intWrap(-1);
153        return(py_retval);
154    }
155    ret = xmlHashAddEntry2(libxslt_extModuleFunctions, name, ns_uri, pyobj_f);
156    if (ret != 0) {
157        py_retval = libxml_intWrap(-1);
158        return(py_retval);
159    }
160    Py_XINCREF(pyobj_f);
161
162    ret = xsltRegisterExtModuleFunction(name, ns_uri,
163                                             libxslt_xmlXPathFuncCallback);
164    py_retval = libxml_intWrap((int) ret);
165    return(py_retval);
166}
167
168static void
169deallocateCallback(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
170    PyObject *function = (PyObject *) payload;
171
172#ifdef DEBUG_XPATH
173    printf("deallocateCallback(%s) called\n", name);
174#endif
175
176    Py_XDECREF(function);
177}
178
179/************************************************************************
180 *                                                                      *
181 *                      Some customized front-ends                      *
182 *                                                                      *
183 ************************************************************************/
184
185PyObject *
186libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
187    PyObject *py_retval;
188    xmlDocPtr c_retval;
189    xsltStylesheetPtr style;
190    PyObject *pyobj_style;
191    xmlDocPtr doc;
192    PyObject *pyobj_doc;
193    PyObject *pyobj_params;
194    const char **params = NULL;
195    int len = 0, i = 0, j;
196    PyObject *name;
197    PyObject *value;
198
199    if (!PyArg_ParseTuple(args, (char *) "OOO:xsltApplyStylesheet",
200                          &pyobj_style, &pyobj_doc, &pyobj_params))
201        return(NULL);
202
203    if (pyobj_params != Py_None) {
204        if (PyDict_Check(pyobj_params)) {
205            len = PyDict_Size(pyobj_params);
206            if (len > 0) {
207                params = (const char **) xmlMalloc((len + 1) * 2 *
208                                                   sizeof(char *));
209                if (params == NULL) {
210                    printf("libxslt_xsltApplyStylesheet: out of memory\n");
211                    Py_INCREF(Py_None);
212                    return(Py_None);
213                }
214                j = 0;
215                while (PyDict_Next(pyobj_params, &i, &name, &value)) {
216                    const char *tmp;
217                    int size;
218
219                    tmp = PyString_AS_STRING(name);
220                    size = PyString_GET_SIZE(name);
221                    params[j * 2] = (char *) xmlCharStrndup(tmp, size);
222                    if (PyString_Check(value)) {
223                        tmp = PyString_AS_STRING(value);
224                        size = PyString_GET_SIZE(value);
225                        params[(j * 2) + 1] = (char *)
226                            xmlCharStrndup(tmp, size);
227                    } else {
228                        params[(j * 2) + 1] = NULL;
229                    }
230                    j = j + 1;
231                }
232                params[j * 2] = NULL;
233                params[(j * 2) + 1] = NULL;
234            }
235        } else {
236            printf("libxslt_xsltApplyStylesheet: parameters not a dict\n");
237            Py_INCREF(Py_None);
238            return(Py_None);
239        }
240    }
241    style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
242    doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
243
244    c_retval = xsltApplyStylesheet(style, doc, params);
245    py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval);
246    if (params != NULL) {
247        if (len > 0) {
248            for (i = 0;i < 2 * len;i++) {
249                if (params[i] != NULL)
250                    xmlFree((char *)params[i]);
251            }
252            xmlFree(params);
253        }
254    }
255    return(py_retval);
256}
257
258PyObject *
259libxslt_xsltSaveResultToString(PyObject *self, PyObject *args) {
260    PyObject *py_retval;        /* our final return value, a python string   */
261    xmlChar  *buffer;
262    xmlChar  *tmp;
263    int       size    = 0;
264    int       emitted = 0;
265    xmlDocPtr result;
266    PyObject *pyobj_result;
267    xsltStylesheetPtr style;
268    PyObject *pyobj_style;
269
270    if (!PyArg_ParseTuple(args, (char *)"OO:xsltSaveResultToString", &pyobj_style, &pyobj_result))
271      goto FAIL;
272    result = (xmlDocPtr) PyxmlNode_Get(pyobj_result);
273    style  = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
274
275     
276    /* FIXME: We should probably add more restrictive error checking
277     * and raise an error instead of "just" returning NULL.
278     * FIXME: Documentation and code for xsltSaveResultToString diff
279     * -> emmitted will never be positive non-null.
280     */
281    emitted = xsltSaveResultToString(&buffer, &size, result, style);
282    if(!buffer || emitted < 0)
283      goto FAIL;
284    /* We haven't tested the aberrant case of a transformation that
285     * renders to an empty string. For now we try to play it save.
286     */
287    if(size)
288      {
289      buffer[size] = '\0';
290      py_retval = PyString_FromString((char *) buffer);
291      xmlFree(buffer);
292      }
293    else
294      py_retval = PyString_FromString("");
295    return(py_retval);
296 FAIL:
297    return(0);
298}
299
300
301/************************************************************************
302 *                                                                      *
303 *                      Error message callback                          *
304 *                                                                      *
305 ************************************************************************/
306
307static PyObject *libxslt_xsltPythonErrorFuncHandler = NULL;
308static PyObject *libxslt_xsltPythonErrorFuncCtxt = NULL;
309
310static void
311libxslt_xsltErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg,
312                           ...)
313{
314    int size;
315    int chars;
316    char *larger;
317    va_list ap;
318    char *str;
319    PyObject *list;
320    PyObject *message;
321    PyObject *result;
322
323#ifdef DEBUG_ERROR
324    printf("libxslt_xsltErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
325#endif
326
327
328    if (libxslt_xsltPythonErrorFuncHandler == NULL) {
329        va_start(ap, msg);
330        vfprintf(stdout, msg, ap);
331        va_end(ap);
332    } else {
333        str = (char *) xmlMalloc(150);
334        if (str == NULL)
335            return;
336
337        size = 150;
338
339        while (1) {
340            va_start(ap, msg);
341            chars = vsnprintf(str, size, msg, ap);
342            va_end(ap);
343            if ((chars > -1) && (chars < size))
344                break;
345            if (chars > -1)
346                size += chars + 1;
347            else
348                size += 100;
349            if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
350                xmlFree(str);
351                return;
352            }
353            str = larger;
354        }
355
356        list = PyTuple_New(2);
357        PyTuple_SetItem(list, 0, libxslt_xsltPythonErrorFuncCtxt);
358        Py_XINCREF(libxslt_xsltPythonErrorFuncCtxt);
359        message = libxml_charPtrWrap(str);
360        PyTuple_SetItem(list, 1, message);
361        result = PyEval_CallObject(libxslt_xsltPythonErrorFuncHandler, list);
362        Py_XDECREF(list);
363        Py_XDECREF(result);
364    }
365}
366
367static void
368libxslt_xsltErrorInitialize(void)
369{
370#ifdef DEBUG_ERROR
371    printf("libxslt_xsltErrorInitialize() called\n");
372#endif
373    xmlSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler);
374    xsltSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler);
375}
376
377PyObject *
378libxslt_xsltRegisterErrorHandler(ATTRIBUTE_UNUSED PyObject * self,
379                               PyObject * args)
380{
381    PyObject *py_retval;
382    PyObject *pyobj_f;
383    PyObject *pyobj_ctx;
384
385    if (!PyArg_ParseTuple
386        (args, (char *) "OO:xmlRegisterErrorHandler", &pyobj_f,
387         &pyobj_ctx))
388        return (NULL);
389
390#ifdef DEBUG_ERROR
391    printf("libxml_registerXPathFunction(%p, %p) called\n", pyobj_ctx,
392           pyobj_f);
393#endif
394
395    if (libxslt_xsltPythonErrorFuncHandler != NULL) {
396        Py_XDECREF(libxslt_xsltPythonErrorFuncHandler);
397    }
398    if (libxslt_xsltPythonErrorFuncCtxt != NULL) {
399        Py_XDECREF(libxslt_xsltPythonErrorFuncCtxt);
400    }
401
402    Py_XINCREF(pyobj_ctx);
403    Py_XINCREF(pyobj_f);
404
405    /* TODO: check f is a function ! */
406    libxslt_xsltPythonErrorFuncHandler = pyobj_f;
407    libxslt_xsltPythonErrorFuncCtxt = pyobj_ctx;
408
409    py_retval = libxml_intWrap(1);
410    return (py_retval);
411}
412
413/************************************************************************
414 *                                                                      *
415 *                      Extension classes                               *
416 *                                                                      *
417 ************************************************************************/
418
419static xmlHashTablePtr libxslt_extModuleClasses = NULL;
420
421static void *
422libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style,
423                                    const xmlChar * URI) {
424    PyObject *result;
425    PyObject *class = NULL;
426
427#ifdef DEBUG_EXTENSIONS
428    printf("libxslt_xsltPythonExtModuleStyleInit(%p, %s) called\n",
429           style, URI);
430#endif
431
432    if ((style == NULL) || (URI == NULL))
433        return(NULL);
434
435    /*
436     * Find the function, it should be there it was there at lookup
437     */
438    class = xmlHashLookup(libxslt_extModuleClasses, URI);
439    if (class == NULL) {
440        fprintf(stderr, "libxslt_xsltPythonExtModuleStyleInit: internal error %s not found !\n", URI);
441        return(NULL);
442    }
443
444    if (PyObject_HasAttrString(class, (char *) "_styleInit")) {
445        result = PyObject_CallMethod(class, (char *) "_styleInit",
446                     (char *) "Os", libxslt_xsltStylesheetPtrWrap(style), URI);
447    }
448    return((void *)result);
449}
450static void
451libxslt_xsltPythonExtModuleStyleShutdown(xsltStylesheetPtr style,
452                                        const xmlChar * URI, void *data) {
453    PyObject *class = NULL;
454    PyObject *result;
455
456#ifdef DEBUG_EXTENSIONS
457    printf("libxslt_xsltPythonExtModuleStyleShutdown(%p, %s, %p) called\n",
458           style, URI, data);
459#endif
460
461    if ((style == NULL) || (URI == NULL))
462        return;
463
464    /*
465     * Find the function, it should be there it was there at lookup
466     */
467    class = xmlHashLookup(libxslt_extModuleClasses, URI);
468    if (class == NULL) {
469        fprintf(stderr, "libxslt_xsltPythonExtModuleStyleShutdown: internal error %s not found !\n", URI);
470        return(NULL);
471    }
472
473    if (PyObject_HasAttrString(class, (char *) "_styleShutdown")) {
474        result = PyObject_CallMethod(class, (char *) "_styleShutdown",
475                     (char *) "OsO", libxslt_xsltStylesheetPtrWrap(style),
476                     URI, (PyObject *) data);
477        Py_XDECREF(result);
478        Py_XDECREF((PyObject *)data);
479    }
480}
481
482static void *
483libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt,
484                                    const xmlChar * URI) {
485    PyObject *result;
486    PyObject *class = NULL;
487
488#ifdef DEBUG_EXTENSIONS
489    printf("libxslt_xsltPythonExtModuleCtxtInit(%p, %s) called\n",
490           ctxt, URI);
491#endif
492
493    if ((ctxt == NULL) || (URI == NULL))
494        return(NULL);
495
496    /*
497     * Find the function, it should be there it was there at lookup
498     */
499    class = xmlHashLookup(libxslt_extModuleClasses, URI);
500    if (class == NULL) {
501        fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtInit: internal error %s not found !\n", URI);
502        return(NULL);
503    }
504
505    if (PyObject_HasAttrString(class, (char *) "_ctxtInit")) {
506        result = PyObject_CallMethod(class, (char *) "_ctxtInit",
507                     (char *) "Os", libxslt_xsltTransformContextPtrWrap(ctxt),
508                     URI);
509    }
510    return((void *)result);
511}
512static void
513libxslt_xsltPythonExtModuleCtxtShutdown(xsltTransformContextPtr ctxt,
514                                        const xmlChar * URI, void *data) {
515    PyObject *class = NULL;
516    PyObject *result;
517
518#ifdef DEBUG_EXTENSIONS
519    printf("libxslt_xsltPythonExtModuleCtxtShutdown(%p, %s, %p) called\n",
520           ctxt, URI, data);
521#endif
522
523    if ((ctxt == NULL) || (URI == NULL))
524        return;
525
526    /*
527     * Find the function, it should be there it was there at lookup
528     */
529    class = xmlHashLookup(libxslt_extModuleClasses, URI);
530    if (class == NULL) {
531        fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtShutdown: internal error %s not found !\n", URI);
532        return(NULL);
533    }
534
535    if (PyObject_HasAttrString(class, (char *) "_ctxtShutdown")) {
536        result = PyObject_CallMethod(class, (char *) "_ctxtShutdown",
537                     (char *) "OsO", libxslt_xsltTransformContextPtrWrap(ctxt),
538                     URI, (PyObject *) data);
539        Py_XDECREF(result);
540        Py_XDECREF((PyObject *)data);
541    }
542}
543
544PyObject *
545libxslt_xsltRegisterExtensionClass(PyObject *self ATTRIBUTE_UNUSED,
546                                   PyObject *args) {
547    PyObject *py_retval;
548    int ret = 0;
549    xmlChar *name;
550    xmlChar *ns_uri;
551    PyObject *pyobj_c;
552
553    if (!PyArg_ParseTuple(args, (char *)"zO:registerExtensionClass",
554                          &ns_uri, &pyobj_c))
555        return(NULL);
556
557    if ((ns_uri == NULL) || (pyobj_c == NULL)) {
558        py_retval = libxml_intWrap(-1);
559        return(py_retval);
560    }
561
562#ifdef DEBUG_EXTENSIONS
563    printf("libxslt_xsltRegisterExtensionClass(%s) called\n", ns_uri);
564#endif
565
566    if (libxslt_extModuleClasses == NULL)
567        libxslt_extModuleClasses = xmlHashCreate(10);
568    if (libxslt_extModuleClasses == NULL) {
569        py_retval = libxml_intWrap(-1);
570        return(py_retval);
571    }
572    ret = xmlHashAddEntry(libxslt_extModuleClasses, ns_uri, pyobj_c);
573    if (ret != 0) {
574        py_retval = libxml_intWrap(-1);
575        return(py_retval);
576    }
577    Py_XINCREF(pyobj_c);
578
579    ret = xsltRegisterExtModuleFull(ns_uri,
580       (xsltExtInitFunction) libxslt_xsltPythonExtModuleCtxtInit,
581       (xsltExtShutdownFunction) libxslt_xsltPythonExtModuleCtxtShutdown,
582       (xsltStyleExtInitFunction) libxslt_xsltPythonExtModuleStyleInit,
583       (xsltStyleExtShutdownFunction) libxslt_xsltPythonExtModuleStyleShutdown);
584    py_retval = libxml_intWrap((int) ret);
585    if (ret < 0) {
586        Py_XDECREF(pyobj_c);
587    }
588    return(py_retval);
589}
590
591static void
592deallocateClasse(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
593    PyObject *class = (PyObject *) payload;
594
595#ifdef DEBUG_EXTENSIONS
596    printf("deallocateClasse(%s) called\n", name);
597#endif
598
599    Py_XDECREF(class);
600}
601
602/************************************************************************
603 *                                                                      *
604 *                      Integrated cleanup                              *
605 *                                                                      *
606 ************************************************************************/
607
608PyObject *
609libxslt_xsltCleanup(PyObject *self ATTRIBUTE_UNUSED,
610                    PyObject *args ATTRIBUTE_UNUSED) {
611
612    if (libxslt_extModuleFunctions != NULL) {
613        xmlHashFree(libxslt_extModuleFunctions, deallocateCallback);
614    }
615    if (libxslt_extModuleClasses != NULL) {
616        xmlHashFree(libxslt_extModuleClasses, deallocateClasse);
617    }
618    xsltCleanupGlobals();
619    xmlCleanupParser();
620    Py_INCREF(Py_None);
621    return(Py_None);
622}
623
624/************************************************************************
625 *                                                                      *
626 *                      The registration stuff                          *
627 *                                                                      *
628 ************************************************************************/
629static PyMethodDef libxsltMethods[] = {
630#include "libxslt-export.c"
631    { NULL, NULL, 0, NULL }
632};
633
634#ifdef MERGED_MODULES
635extern void initlibxml2mod(void);
636#endif
637
638void initlibxsltmod(void) {
639    static int initialized = 0;
640    PyObject *m;
641
642#ifdef MERGED_MODULES
643    initlibxml2mod();
644#endif
645
646    if (initialized != 0)
647        return;
648    m = Py_InitModule((char *)"libxsltmod", libxsltMethods);
649    initialized = 1;
650    /*
651     * Specific XSLT initializations
652     */
653    libxslt_xsltErrorInitialize();
654    xmlInitMemory();
655    xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
656    xmlDefaultSAXHandler.cdataBlock = NULL;
657    /*
658     * Register the EXSLT extensions and the test module
659     */
660    exsltRegisterAll();
661}
662
663
Note: See TracBrowser for help on using the repository browser.