source: trunk/third/libxslt/libxslt/extensions.c @ 19102

Revision 19102, 41.9 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19101, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * extensions.c: Implemetation of the extensions support
3 *
4 * Reference:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#include <string.h>
16
17#include <libxml/xmlmemory.h>
18#include <libxml/tree.h>
19#include <libxml/hash.h>
20#include <libxml/xmlerror.h>
21#include <libxml/parserInternals.h>
22#include <libxml/xpathInternals.h>
23#include "xslt.h"
24#include "xsltInternals.h"
25#include "xsltutils.h"
26#include "imports.h"
27#include "extensions.h"
28
29#ifdef WITH_XSLT_DEBUG
30#define WITH_XSLT_DEBUG_EXTENSIONS
31#endif
32
33/************************************************************************
34 *                                                                      *
35 *                      Private Types and Globals                       *
36 *                                                                      *
37 ************************************************************************/
38
39typedef struct _xsltExtDef xsltExtDef;
40typedef xsltExtDef *xsltExtDefPtr;
41struct _xsltExtDef {
42    struct _xsltExtDef *next;
43    xmlChar *prefix;
44    xmlChar *URI;
45    void    *data;
46};
47
48typedef struct _xsltExtModule xsltExtModule;
49typedef xsltExtModule *xsltExtModulePtr;
50struct _xsltExtModule {
51    xsltExtInitFunction initFunc;
52    xsltExtShutdownFunction shutdownFunc;
53    xsltStyleExtInitFunction styleInitFunc;
54    xsltStyleExtShutdownFunction styleShutdownFunc;
55};
56
57typedef struct _xsltExtData xsltExtData;
58typedef xsltExtData *xsltExtDataPtr;
59struct _xsltExtData {
60    xsltExtModulePtr extModule;
61    void *extData;
62};
63
64typedef struct _xsltExtElement xsltExtElement;
65typedef xsltExtElement *xsltExtElementPtr;
66struct _xsltExtElement {
67    xsltPreComputeFunction precomp;
68    xsltTransformFunction  transform;
69};
70
71static xmlHashTablePtr xsltExtensionsHash = NULL;
72static xmlHashTablePtr xsltFunctionsHash = NULL;
73static xmlHashTablePtr xsltElementsHash = NULL;
74static xmlHashTablePtr xsltTopLevelsHash = NULL;
75
76/************************************************************************
77 *                                                                      *
78 *                      Type functions                                  *
79 *                                                                      *
80 ************************************************************************/
81
82/**
83 * xsltNewExtDef:
84 * @prefix:  the extension prefix
85 * @URI:  the namespace URI
86 *
87 * Create a new XSLT ExtDef
88 *
89 * Returns the newly allocated xsltExtDefPtr or NULL in case of error
90 */
91static xsltExtDefPtr
92xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
93{
94    xsltExtDefPtr cur;
95
96    cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
97    if (cur == NULL) {
98        xsltTransformError(NULL, NULL, NULL,
99                         "xsltNewExtDef : malloc failed\n");
100        return (NULL);
101    }
102    memset(cur, 0, sizeof(xsltExtDef));
103    if (prefix != NULL)
104        cur->prefix = xmlStrdup(prefix);
105    if (URI != NULL)
106        cur->URI = xmlStrdup(URI);
107    return (cur);
108}
109
110/**
111 * xsltFreeExtDef:
112 * @extensiond:  an XSLT extension definition
113 *
114 * Free up the memory allocated by @extensiond
115 */
116static void
117xsltFreeExtDef(xsltExtDefPtr extensiond) {
118    if (extensiond == NULL)
119        return;
120    if (extensiond->prefix != NULL)
121        xmlFree(extensiond->prefix);
122    if (extensiond->URI != NULL)
123        xmlFree(extensiond->URI);
124    xmlFree(extensiond);
125}
126
127/**
128 * xsltFreeExtDefList:
129 * @extensiond:  an XSLT extension definition list
130 *
131 * Free up the memory allocated by all the elements of @extensiond
132 */
133static void
134xsltFreeExtDefList(xsltExtDefPtr extensiond) {
135    xsltExtDefPtr cur;
136
137    while (extensiond != NULL) {
138        cur = extensiond;
139        extensiond = extensiond->next;
140        xsltFreeExtDef(cur);
141    }
142}
143
144/**
145 * xsltNewExtModule:
146 * @initFunc:  the module initialization function
147 * @shutdownFunc:  the module shutdown function
148 * @styleInitFunc:  the stylesheet module data allocator function
149 * @styleShutdownFunc:  the stylesheet module data free function
150 *
151 * Create a new XSLT extension module
152 *
153 * Returns the newly allocated xsltExtModulePtr or NULL in case of error
154 */
155static xsltExtModulePtr
156xsltNewExtModule(xsltExtInitFunction initFunc,
157                 xsltExtShutdownFunction shutdownFunc,
158                 xsltStyleExtInitFunction styleInitFunc,
159                 xsltStyleExtShutdownFunction styleShutdownFunc)
160{
161    xsltExtModulePtr cur;
162
163    cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
164    if (cur == NULL) {
165        xsltTransformError(NULL, NULL, NULL,
166                         "xsltNewExtModule : malloc failed\n");
167        return (NULL);
168    }
169    cur->initFunc = initFunc;
170    cur->shutdownFunc = shutdownFunc;
171    cur->styleInitFunc = styleInitFunc;
172    cur->styleShutdownFunc = styleShutdownFunc;
173    return (cur);
174}
175
176/**
177 * xsltFreeExtModule:
178 * @ext:  an XSLT extension module
179 *
180 * Free up the memory allocated by @ext
181 */
182static void
183xsltFreeExtModule(xsltExtModulePtr ext) {
184    if (ext == NULL)
185        return;
186    xmlFree(ext);
187}
188
189/**
190 * xsltNewExtData:
191 * @extModule:  the module
192 * @extData:  the associated data
193 *
194 * Create a new XSLT extension module data wrapper
195 *
196 * Returns the newly allocated xsltExtDataPtr or NULL in case of error
197 */
198static xsltExtDataPtr
199xsltNewExtData(xsltExtModulePtr extModule, void *extData)
200{
201    xsltExtDataPtr cur;
202
203    if (extModule == NULL)
204        return(NULL);
205    cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
206    if (cur == NULL) {
207        xsltTransformError(NULL, NULL, NULL,
208                         "xsltNewExtData : malloc failed\n");
209        return (NULL);
210    }
211    cur->extModule = extModule;
212    cur->extData = extData;
213    return (cur);
214}
215
216/**
217 * xsltFreeExtData:
218 * @ext:  an XSLT extension module data wrapper
219 *
220 * Free up the memory allocated by @ext
221 */
222static void
223xsltFreeExtData(xsltExtDataPtr ext) {
224    if (ext == NULL)
225        return;
226    xmlFree(ext);
227}
228
229/**
230 * xsltNewExtElement:
231 * @precomp:  the pre-computation function
232 * @transform:  the transformation function
233 *
234 * Create a new XSLT extension element
235 *
236 * Returns the newly allocated xsltExtElementPtr or NULL in case of
237 * error
238 */
239static xsltExtElementPtr
240xsltNewExtElement (xsltPreComputeFunction precomp,
241                   xsltTransformFunction transform) {
242    xsltExtElementPtr cur;
243
244    if (transform == NULL)
245        return(NULL);
246
247    cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
248    if (cur == NULL) {
249        xsltTransformError(NULL, NULL, NULL,
250                         "xsltNewExtElement : malloc failed\n");
251        return (NULL);
252    }
253    cur->precomp = precomp;
254    cur->transform = transform;
255    return(cur);
256}
257
258/**
259 * xsltFreeExtElement:
260 * @ext: an XSLT extension element
261 *
262 * Frees up the memory allocated by @ext
263 */
264static void
265xsltFreeExtElement (xsltExtElementPtr ext) {
266    if (ext == NULL)
267        return;
268    xmlFree(ext);
269}
270
271
272/************************************************************************
273 *                                                                      *
274 *              The stylesheet extension prefixes handling              *
275 *                                                                      *
276 ************************************************************************/
277
278
279/**
280 * xsltFreeExts:
281 * @style: an XSLT stylesheet
282 *
283 * Free up the memory used by XSLT extensions in a stylesheet
284 */
285void
286xsltFreeExts(xsltStylesheetPtr style) {
287    if (style->nsDefs != NULL)
288        xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs);
289}
290
291/**
292 * xsltRegisterExtPrefix:
293 * @style: an XSLT stylesheet
294 * @prefix: the prefix used
295 * @URI: the URI associated to the extension
296 *
297 * Registers an extension namespace
298 *
299 * Returns 0 in case of success, -1 in case of failure
300 */
301int
302xsltRegisterExtPrefix(xsltStylesheetPtr style,
303                      const xmlChar *prefix, const xmlChar *URI) {
304    xsltExtDefPtr def, ret;
305
306    if ((style == NULL) || (prefix == NULL) | (URI == NULL))
307        return(-1);
308
309#ifdef WITH_XSLT_DEBUG_EXTENSIONS
310    xsltGenericDebug(xsltGenericDebugContext,
311         "Registering extension prefix %s : %s\n", prefix, URI);
312#endif
313    def = (xsltExtDefPtr) style->nsDefs;
314    while (def != NULL) {
315        if (xmlStrEqual(prefix, def->prefix))
316            return(-1);
317        def = def->next;
318    }
319    ret = xsltNewExtDef(prefix, URI);
320    if (ret == NULL)
321        return(-1);
322    ret->next = (xsltExtDefPtr) style->nsDefs;
323    style->nsDefs = ret;
324
325    /*
326     * check wether there is an extension module with a stylesheet
327     * initialization function.
328     */
329    if (xsltExtensionsHash != NULL) {
330        xsltExtModulePtr module;
331
332        module = xmlHashLookup(xsltExtensionsHash, URI);
333        if (module != NULL) {
334            xsltExtDataPtr data;
335
336            data = xsltStyleGetExtData(style, URI);
337        }
338    }
339    return(0);
340}
341
342/************************************************************************
343 *                                                                      *
344 *              The extensions modules interfaces                       *
345 *                                                                      *
346 ************************************************************************/
347
348/**
349 * xsltRegisterExtFunction:
350 * @ctxt: an XSLT transformation context
351 * @name: the name of the element
352 * @URI: the URI associated to the element
353 * @function: the actual implementation which should be called
354 *
355 * Registers an extension function
356 *
357 * Returns 0 in case of success, -1 in case of failure
358 */
359int
360xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar *name,
361                        const xmlChar *URI, xmlXPathFunction function) {
362    if ((ctxt == NULL) || (name == NULL) ||
363        (URI == NULL) || (function == NULL))
364        return(-1);
365    if (ctxt->xpathCtxt != NULL) {
366        xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function);
367    }
368    if (ctxt->extFunctions == NULL)
369        ctxt->extFunctions = xmlHashCreate(10);
370    if (ctxt->extFunctions == NULL)
371        return(-1);
372    return(xmlHashAddEntry2(ctxt->extFunctions, name, URI, (void *) function));
373}
374
375/**
376 * xsltRegisterExtElement:
377 * @ctxt: an XSLT transformation context
378 * @name: the name of the element
379 * @URI: the URI associated to the element
380 * @function: the actual implementation which should be called
381 *
382 * Registers an extension element
383 *
384 * Returns 0 in case of success, -1 in case of failure
385 */
386int     
387xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar *name,
388                       const xmlChar *URI, xsltTransformFunction function) {
389    if ((ctxt == NULL) || (name == NULL) ||
390        (URI == NULL) || (function == NULL))
391        return(-1);
392    if (ctxt->extElements == NULL)
393        ctxt->extElements = xmlHashCreate(10);
394    if (ctxt->extElements == NULL)
395        return(-1);
396    return(xmlHashAddEntry2(ctxt->extElements, name, URI, (void *) function));
397}
398
399/**
400 * xsltFreeCtxtExts:
401 * @ctxt: an XSLT transformation context
402 *
403 * Free the XSLT extension data
404 */
405void
406xsltFreeCtxtExts(xsltTransformContextPtr ctxt) {
407    if (ctxt->extElements != NULL)
408        xmlHashFree(ctxt->extElements, NULL);
409    if (ctxt->extFunctions != NULL)
410        xmlHashFree(ctxt->extFunctions, NULL);
411}
412
413/**
414 * xsltStyleGetExtData:
415 * @style: an XSLT stylesheet
416 * @URI:  the URI associated to the exension module
417 *
418 * Retrieve the data associated to the extension module in this given
419 * stylesheet.
420 *
421 * Returns the pointer or NULL if not present
422 */
423void *
424xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) {
425    xsltExtDataPtr data = NULL;
426    xsltStylesheetPtr tmp;
427
428
429    if ((style == NULL) || (URI == NULL))
430        return (NULL);
431
432    tmp = style;
433    while (tmp != NULL) {
434        if (tmp->extInfos != NULL) {
435            data = (xsltExtDataPtr) xmlHashLookup(tmp->extInfos, URI);
436            if (data != NULL)
437                break;
438        }
439        tmp = xsltNextImport(tmp);
440    }
441    if (data == NULL) {
442        if (style->extInfos == NULL) {
443            style->extInfos = xmlHashCreate(10);
444            if (style->extInfos == NULL)
445                return(NULL);
446        }
447    }
448    if (data == NULL) {
449        void *extData;
450        xsltExtModulePtr module;
451
452        module = xmlHashLookup(xsltExtensionsHash, URI);
453        if (module == NULL) {
454#ifdef WITH_XSLT_DEBUG_EXTENSIONS
455            xsltGenericDebug(xsltGenericDebugContext,
456                             "Not registered extension module: %s\n", URI);
457#endif
458            return(NULL);
459        } else {
460            if (module->styleInitFunc == NULL) {
461#ifdef WITH_XSLT_DEBUG_EXTENSIONS
462                xsltGenericDebug(xsltGenericDebugContext,
463                             "Registering style module: %s\n", URI);
464#endif
465                extData = NULL;
466            } else {
467#ifdef WITH_XSLT_DEBUG_EXTENSIONS
468                xsltGenericDebug(xsltGenericDebugContext,
469                                 "Initializing module: %s\n", URI);
470#endif
471                extData = module->styleInitFunc(style, URI);
472            }
473
474            data = xsltNewExtData(module, extData);
475            if (data == NULL)
476                return (NULL);
477            if (xmlHashAddEntry(style->extInfos, URI,
478                                (void *) data) < 0) {
479                xsltGenericError(xsltGenericErrorContext,
480                                 "Failed to register module data: %s\n", URI);
481                if (module->styleShutdownFunc)
482                    module->styleShutdownFunc(style, URI, extData);
483                xsltFreeExtData(data);
484                return(NULL);
485            }
486        }
487    }
488    return (data->extData);
489}
490
491/**
492 * xsltGetExtData:
493 * @ctxt: an XSLT transformation context
494 * @URI:  the URI associated to the exension module
495 *
496 * Retrieve the data associated to the extension module in this given
497 * transformation.
498 *
499 * Returns the pointer or NULL if not present
500 */
501void *
502xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI) {
503    xsltExtDataPtr data;
504
505    if ((ctxt == NULL) || (URI == NULL))
506        return (NULL);
507    if (ctxt->extInfos == NULL) {
508        ctxt->extInfos = xmlHashCreate(10);
509        if (ctxt->extInfos == NULL)
510            return(NULL);
511        data = NULL;
512    } else {
513        data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
514    }
515    if (data == NULL) {
516        void *extData;
517        xsltExtModulePtr module;
518
519        module = xmlHashLookup(xsltExtensionsHash, URI);
520        if (module == NULL) {
521#ifdef WITH_XSLT_DEBUG_EXTENSIONS
522            xsltGenericDebug(xsltGenericDebugContext,
523                             "Not registered extension module: %s\n", URI);
524#endif
525            return(NULL);
526        } else {
527            if (module->initFunc == NULL)
528                return(NULL);
529
530#ifdef WITH_XSLT_DEBUG_EXTENSIONS
531            xsltGenericDebug(xsltGenericDebugContext,
532                             "Initializing module: %s\n", URI);
533#endif
534
535            extData = module->initFunc(ctxt, URI);
536            if (extData == NULL)
537                return(NULL);
538
539            data = xsltNewExtData(module, extData);
540            if (data == NULL)
541                return (NULL);
542            if (xmlHashAddEntry(ctxt->extInfos, URI,
543                                (void *) data) < 0) {
544                xsltTransformError(ctxt, NULL, NULL,
545                                 "Failed to register module data: %s\n", URI);
546                if (module->shutdownFunc)
547                    module->shutdownFunc(ctxt, URI, extData);
548                xsltFreeExtData(data);
549                return(NULL);
550            }
551        }
552    }
553    return (data->extData);
554}
555
556typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
557struct _xsltInitExtCtxt {
558    xsltTransformContextPtr ctxt;
559    int ret;
560};
561
562/**
563 * xsltInitCtxtExt:
564 * @styleData:  the registered stylesheet data for the module
565 * @ctxt:  the XSLT transformation context + the return value
566 * @URI:  the extension URI
567 *
568 * Initializes an extension module
569 */
570static void
571xsltInitCtxtExt (xsltExtDataPtr styleData, xsltInitExtCtxt *ctxt,
572                 const xmlChar *URI) {
573    xsltExtModulePtr module;
574    xsltExtDataPtr ctxtData;
575    void *extData;
576
577    if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
578        (ctxt->ret == -1)) {
579#ifdef WITH_XSLT_DEBUG_EXTENSIONS
580    xsltGenericDebug(xsltGenericDebugContext,
581                     "xsltInitCtxtExt: NULL param or error\n");
582#endif
583        return;
584    }
585    module = styleData->extModule;
586    if ((module == NULL) || (module->initFunc == NULL)) {
587#ifdef WITH_XSLT_DEBUG_EXTENSIONS
588        xsltGenericDebug(xsltGenericDebugContext,
589                         "xsltInitCtxtExt: no module or no initFunc\n");
590#endif
591        return;
592    }
593
594    extData = module->initFunc(ctxt->ctxt, URI);
595    if (extData == NULL) {
596#ifdef WITH_XSLT_DEBUG_EXTENSIONS
597        xsltGenericDebug(xsltGenericDebugContext,
598                         "xsltInitCtxtExt: no extData\n");
599#endif
600    }
601    ctxtData = xsltNewExtData(module, extData);
602    if (ctxtData == NULL) {
603        ctxt->ret = -1;
604        return;
605    }
606
607    if (ctxt->ctxt->extInfos == NULL)
608        ctxt->ctxt->extInfos = xmlHashCreate(10);
609    if (ctxt->ctxt->extInfos == NULL) {
610        ctxt->ret = -1;
611        return;
612    }
613
614    if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
615        xsltGenericError(xsltGenericErrorContext,
616                         "Failed to register module data: %s\n", URI);
617        if (module->shutdownFunc)
618            module->shutdownFunc(ctxt->ctxt, URI, extData);
619        xsltFreeExtData(ctxtData);
620        ctxt->ret = -1;
621        return;
622    }
623#ifdef WITH_XSLT_DEBUG_EXTENSIONS
624    xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
625                     URI);
626#endif
627    ctxt->ret++;
628}
629
630/**
631 * xsltInitCtxtExts:
632 * @ctxt: an XSLT transformation context
633 *
634 * Initialize the set of modules with registered stylesheet data
635 *
636 * Returns the number of modules initialized or -1 in case of error
637 */
638int
639xsltInitCtxtExts(xsltTransformContextPtr ctxt)
640{
641    xsltStylesheetPtr style;
642    xsltInitExtCtxt ctx;
643
644    if (ctxt == NULL)
645        return (-1);
646
647    style = ctxt->style;
648    if (style == NULL)
649        return (-1);
650
651    ctx.ctxt = ctxt;
652    ctx.ret = 0;
653
654    while (style != NULL) {
655        if (style->extInfos != NULL) {
656            xmlHashScan(style->extInfos,
657                        (xmlHashScanner) xsltInitCtxtExt, &ctx);
658            if (ctx.ret == -1)
659                return(-1);
660        }
661        style = xsltNextImport(style);
662    }
663#ifdef WITH_XSLT_DEBUG_EXTENSIONS
664    xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
665                     ctx.ret);
666#endif
667    return (ctx.ret);
668}
669
670/**
671 * xsltShutdownCtxtExt:
672 * @data:  the registered data for the module
673 * @ctxt:  the XSLT transformation context
674 * @URI:  the extension URI
675 *
676 * Shutdown an extension module loaded
677 */
678static void
679xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt,
680                    const xmlChar * URI)
681{
682    xsltExtModulePtr module;
683
684    if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
685        return;
686    module = data->extModule;
687    if ((module == NULL) || (module->shutdownFunc == NULL))
688        return;
689
690#ifdef WITH_XSLT_DEBUG_EXTENSIONS
691    xsltGenericDebug(xsltGenericDebugContext,
692                     "Shutting down module : %s\n", URI);
693#endif
694    module->shutdownFunc(ctxt, URI, data->extData);
695    xmlHashRemoveEntry(ctxt->extInfos, URI,
696                       (xmlHashDeallocator) xsltFreeExtData);
697}
698
699/**
700 * xsltShutdownCtxtExts:
701 * @ctxt: an XSLT transformation context
702 *
703 * Shutdown the set of modules loaded
704 */
705void
706xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
707{
708    if (ctxt == NULL)
709        return;
710    if (ctxt->extInfos == NULL)
711        return;
712    xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt, ctxt);
713    xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData);
714    ctxt->extInfos = NULL;
715}
716
717/**
718 * xsltShutdownExt:
719 * @data:  the registered data for the module
720 * @ctxt:  the XSLT stylesheet
721 * @URI:  the extension URI
722 *
723 * Shutdown an extension module loaded
724 */
725static void
726xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style,
727                const xmlChar * URI)
728{
729    xsltExtModulePtr module;
730
731    if ((data == NULL) || (style == NULL) || (URI == NULL))
732        return;
733    module = data->extModule;
734    if ((module == NULL) || (module->styleShutdownFunc == NULL))
735        return;
736
737#ifdef WITH_XSLT_DEBUG_EXTENSIONS
738    xsltGenericDebug(xsltGenericDebugContext,
739                     "Shutting down module : %s\n", URI);
740#endif
741    module->styleShutdownFunc(style, URI, data->extData);
742    xmlHashRemoveEntry(style->extInfos, URI,
743                       (xmlHashDeallocator) xsltFreeExtData);
744}
745
746/**
747 * xsltShutdownExts:
748 * @style: an XSLT stylesheet
749 *
750 * Shutdown the set of modules loaded
751 */
752void
753xsltShutdownExts(xsltStylesheetPtr style)
754{
755    if (style == NULL)
756        return;
757    if (style->extInfos == NULL)
758        return;
759    xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style);
760    xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData);
761    style->extInfos = NULL;
762}
763
764/**
765 * xsltCheckExtPrefix:
766 * @style: the stylesheet
767 * @prefix: the namespace prefix (possibly NULL)
768 *
769 * Check if the given prefix is one of the declared extensions
770 *
771 * Returns 1 if this is an extension, 0 otherwise
772 */
773int
774xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar *prefix) {
775    xsltExtDefPtr cur;
776
777    if ((style == NULL) || (style->nsDefs == NULL))
778        return(0);
779
780    if (prefix == NULL)
781        prefix = BAD_CAST "#default";
782
783    cur = (xsltExtDefPtr) style->nsDefs;
784    while (cur != NULL) {
785        if (xmlStrEqual(prefix, cur->prefix))
786            return(1);
787        cur = cur->next;
788    }
789    return(0);
790}
791
792/**
793 * xsltRegisterExtModuleFull:
794 * @URI:  URI associated to this module
795 * @initFunc:  the module initialization function
796 * @shutdownFunc:  the module shutdown function
797 * @styleInitFunc:  the module initialization function
798 * @styleShutdownFunc:  the module shutdown function
799 *
800 * Register an XSLT extension module to the library.
801 *
802 * Returns 0 if sucessful, -1 in case of error
803 */
804int
805xsltRegisterExtModuleFull(const xmlChar * URI,
806                          xsltExtInitFunction initFunc,
807                          xsltExtShutdownFunction shutdownFunc,
808                          xsltStyleExtInitFunction styleInitFunc,
809                          xsltStyleExtShutdownFunction styleShutdownFunc)
810{
811    int ret;
812    xsltExtModulePtr module;
813
814    if ((URI == NULL) || (initFunc == NULL))
815        return (-1);
816    if (xsltExtensionsHash == NULL)
817        xsltExtensionsHash = xmlHashCreate(10);
818
819    if (xsltExtensionsHash == NULL)
820        return (-1);
821
822    module = xmlHashLookup(xsltExtensionsHash, URI);
823    if (module != NULL) {
824        if ((module->initFunc == initFunc) &&
825            (module->shutdownFunc == shutdownFunc))
826            return (0);
827        return (-1);
828    }
829    module = xsltNewExtModule(initFunc, shutdownFunc,
830                              styleInitFunc, styleShutdownFunc);
831    if (module == NULL)
832        return (-1);
833    ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
834    return (ret);
835}
836
837/**
838 * xsltRegisterExtModule:
839 * @URI:  URI associated to this module
840 * @initFunc:  the module initialization function
841 * @shutdownFunc:  the module shutdown function
842 *
843 * Register an XSLT extension module to the library.
844 *
845 * Returns 0 if sucessful, -1 in case of error
846 */
847int
848xsltRegisterExtModule(const xmlChar * URI,
849                      xsltExtInitFunction initFunc,
850                      xsltExtShutdownFunction shutdownFunc) {
851    return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
852                                     NULL, NULL);
853}
854
855/**
856 * xsltUnregisterExtModule:
857 * @URI:  URI associated to this module
858 *
859 * Unregister an XSLT extension module from the library.
860 *
861 * Returns 0 if sucessful, -1 in case of error
862 */
863int
864xsltUnregisterExtModule(const xmlChar * URI)
865{
866    int ret;
867
868    if (URI == NULL)
869        return (-1);
870    if (xsltExtensionsHash == NULL)
871        return (-1);
872
873    ret =
874        xmlHashRemoveEntry(xsltExtensionsHash, URI,
875                           (xmlHashDeallocator) xsltFreeExtModule);
876    return (ret);
877}
878
879/**
880 * xsltUnregisterAllExtModules:
881 *
882 * Unregister all the XSLT extension module from the library.
883 */
884static void
885xsltUnregisterAllExtModules(void)
886{
887    if (xsltExtensionsHash == NULL)
888        return;
889
890    xmlHashFree(xsltExtensionsHash, (xmlHashDeallocator) xsltFreeExtModule);
891    xsltExtensionsHash = NULL;
892}
893
894/**
895 * xsltXPathGetTransformContext:
896 * @ctxt:  an XPath transformation context
897 *
898 * Provides the XSLT transformation context from the XPath transformation
899 * context. This is useful when an XPath function in the extension module
900 * is called by the XPath interpreter and that the XSLT context is needed
901 * for example to retrieve the associated data pertaining to this XSLT
902 * transformation.
903 *
904 * Returns the XSLT transformation context or NULL in case of error.
905 */
906xsltTransformContextPtr
907xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
908{
909    if ((ctxt == NULL) || (ctxt->context == NULL))
910        return(NULL);
911    return(ctxt->context->extra);
912}
913
914/**
915 * xsltRegisterExtModuleFunction:
916 * @name:  the function name
917 * @URI:  the function namespace URI
918 * @function:  the function callback
919 *
920 * Registers an extension module function.
921 *
922 * Returns 0 if successful, -1 in case of error.
923 */
924int
925xsltRegisterExtModuleFunction (const xmlChar *name, const xmlChar *URI,
926                               xmlXPathFunction function) {
927    if ((name == NULL) || (URI == NULL) || (function == NULL))
928        return(-1);
929
930    if (xsltFunctionsHash == NULL)
931        xsltFunctionsHash = xmlHashCreate(10);
932    if (xsltFunctionsHash == NULL)
933        return(-1);
934
935    xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
936                        (void *) function, NULL);
937
938    return(0);
939}
940
941/**
942 * xsltExtModuleFunctionLookup:
943 * @name:  the function name
944 * @URI:  the function namespace URI
945 *
946 * Looks up an extension module function
947 *
948 * Returns the function if found, NULL otherwise.
949 */
950xmlXPathFunction
951xsltExtModuleFunctionLookup (const xmlChar *name, const xmlChar *URI) {
952    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
953        return(NULL);
954
955    return (xmlXPathFunction) xmlHashLookup2(xsltFunctionsHash, name, URI);
956}
957
958/**
959 * xsltUnregisterExtModuleFunction:
960 * @name:  the function name
961 * @URI:  the function namespace URI
962 *
963 * Unregisters an extension module function
964 *
965 * Returns 0 if successful, -1 in case of error.
966 */
967int
968xsltUnregisterExtModuleFunction (const xmlChar *name,
969                                 const xmlChar *URI) {
970    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
971        return(-1);
972
973    return xmlHashRemoveEntry2 (xsltFunctionsHash, name, URI, NULL);
974}
975
976/**
977 * xsltUnregisterAllExtModuleFunction:
978 *
979 * Unregisters all extension module function
980 */
981static void
982xsltUnregisterAllExtModuleFunction (void) {
983    xmlHashFree(xsltFunctionsHash, NULL);
984    xsltFunctionsHash = NULL;
985}
986
987
988/**
989 * xsltNewElemPreComp:
990 * @style:  the XSLT stylesheet
991 * @inst:  the element node
992 * @function: the transform function
993 *
994 * Creates and initializes an #xsltElemPreComp
995 *
996 * Returns the new and initialized #xsltElemPreComp
997 */
998xsltElemPreCompPtr
999xsltNewElemPreComp (xsltStylesheetPtr style, xmlNodePtr inst,
1000                    xsltTransformFunction function) {
1001    xsltElemPreCompPtr cur;
1002
1003    cur = (xsltElemPreCompPtr) xmlMalloc (sizeof(xsltElemPreComp));
1004    if (cur == NULL) {
1005        xsltTransformError(NULL, style, NULL,
1006                         "xsltNewExtElement : malloc failed\n");
1007        return (NULL);
1008    }
1009    memset(cur, 0, sizeof(xsltElemPreComp));
1010
1011    xsltInitElemPreComp (cur, style, inst, function,
1012                         (xsltElemPreCompDeallocator) xmlFree);
1013
1014    return (cur);
1015}
1016
1017/**
1018 * xsltInitElemPreComp:
1019 * @comp:  an #xsltElemPreComp (or generally a derived structure)
1020 * @style:  the XSLT stylesheet
1021 * @inst:  the element node
1022 * @function:  the transform function
1023 * @freeFunc:  the @comp deallocator
1024 *
1025 * Initializes an existing #xsltElemPreComp structure. This is usefull
1026 * when extending an #xsltElemPreComp to store precomputed data.
1027 * This function MUST be called on any extension element precomputed
1028 * data struct.
1029 */
1030void
1031xsltInitElemPreComp (xsltElemPreCompPtr comp, xsltStylesheetPtr style,
1032                     xmlNodePtr inst, xsltTransformFunction function,
1033                     xsltElemPreCompDeallocator freeFunc) {
1034    comp->type = XSLT_FUNC_EXTENSION;
1035    comp->func = function;
1036    comp->inst = inst;
1037    comp->free = freeFunc;
1038
1039    comp->next = style->preComps;
1040    style->preComps = comp;
1041}
1042
1043/**
1044 * xsltPreComputeExtModuleElement:
1045 * @style:  the stylesheet
1046 * @inst:  the element node
1047 *
1048 * Precomputes an extension module element
1049 *
1050 * Returns the precomputed data
1051 */
1052xsltElemPreCompPtr
1053xsltPreComputeExtModuleElement (xsltStylesheetPtr style,
1054                                xmlNodePtr inst) {
1055    xsltExtElementPtr ext;
1056    xsltElemPreCompPtr comp = NULL;
1057
1058    if ((style == NULL) || (inst == NULL) ||
1059        (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
1060        return (NULL);
1061
1062    ext = (xsltExtElementPtr)
1063        xmlHashLookup2 (xsltElementsHash, inst->name,
1064                        inst->ns->href);
1065    if (ext == NULL)
1066        return (NULL);
1067
1068    if (ext->precomp != NULL)
1069        comp = ext->precomp(style, inst, ext->transform);
1070    if (comp == NULL)
1071        comp = xsltNewElemPreComp (style, inst, ext->transform);
1072
1073    return (comp);
1074}
1075
1076/**
1077 * xsltRegisterExtModuleElement:
1078 * @name:  the element name
1079 * @URI:  the element namespace URI
1080 * @precomp:  the pre-computation callback
1081 * @transform:  the transformation callback
1082 *
1083 * Registers an extension module element.
1084 *
1085 * Returns 0 if successful, -1 in case of error.
1086 */
1087int
1088xsltRegisterExtModuleElement (const xmlChar *name, const xmlChar *URI,
1089                              xsltPreComputeFunction precomp,
1090                              xsltTransformFunction transform) {
1091    xsltExtElementPtr ext;
1092
1093    if ((name == NULL) || (URI == NULL) || (transform == NULL))
1094        return(-1);
1095
1096    if (xsltElementsHash == NULL)
1097        xsltElementsHash = xmlHashCreate(10);
1098    if (xsltElementsHash == NULL)
1099        return(-1);
1100
1101    ext = xsltNewExtElement(precomp, transform);
1102    if (ext == NULL)
1103        return(-1);
1104
1105    xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
1106                        (xmlHashDeallocator) xsltFreeExtElement);
1107
1108    return(0);
1109}
1110
1111/**
1112 * xsltExtElementLookup:
1113 * @ctxt:  an XSLT process context
1114 * @name:  the element name
1115 * @URI:  the element namespace URI
1116 *
1117 * Looks up an extension element. @ctxt can be NULL to search only in
1118 * module elements.
1119 *
1120 * Returns the element callback or NULL if not found
1121 */
1122xsltTransformFunction
1123xsltExtElementLookup (xsltTransformContextPtr ctxt,
1124                      const xmlChar *name, const xmlChar *URI) {
1125    xsltTransformFunction ret;
1126
1127    if ((name == NULL) || (URI == NULL))
1128        return(NULL);
1129
1130    if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
1131        ret = (xsltTransformFunction)
1132            xmlHashLookup2(ctxt->extElements, name, URI);
1133        if (ret != NULL)
1134            return(ret);
1135    }
1136    return xsltExtModuleElementLookup(name, URI);
1137}
1138
1139/**
1140 * xsltExtModuleElementLookup:
1141 * @name:  the element name
1142 * @URI:  the element namespace URI
1143 *
1144 * Looks up an extension module element
1145 *
1146 * Returns the callback function if found, NULL otherwise.
1147 */
1148xsltTransformFunction
1149xsltExtModuleElementLookup (const xmlChar *name, const xmlChar *URI) {
1150    xsltExtElementPtr ext;
1151
1152    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1153        return(NULL);
1154
1155    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1156
1157    if (ext == NULL)
1158        return(NULL);
1159    return(ext->transform);
1160}
1161
1162/**
1163 * xsltExtModuleElementPreComputeLookup:
1164 * @name:  the element name
1165 * @URI:  the element namespace URI
1166 *
1167 * Looks up an extension module element pre-computation function
1168 *
1169 * Returns the callback function if found, NULL otherwise.
1170 */
1171xsltPreComputeFunction
1172xsltExtModuleElementPreComputeLookup (const xmlChar *name,
1173                                      const xmlChar *URI) {
1174    xsltExtElementPtr ext;
1175
1176    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1177        return(NULL);
1178
1179    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1180
1181    if (ext == NULL)
1182        return(NULL);
1183    return(ext->precomp);
1184}
1185
1186/**
1187 * xsltUnregisterExtModuleElement:
1188 * @name:  the element name
1189 * @URI:  the element namespace URI
1190 *
1191 * Unregisters an extension module element
1192 *
1193 * Returns 0 if successful, -1 in case of error.
1194 */
1195int
1196xsltUnregisterExtModuleElement (const xmlChar *name,
1197                                const xmlChar *URI) {
1198    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1199        return(-1);
1200
1201    return xmlHashRemoveEntry2 (xsltElementsHash, name, URI,
1202                                (xmlHashDeallocator) xsltFreeExtElement);
1203}
1204
1205/**
1206 * xsltUnregisterAllExtModuleElement:
1207 *
1208 * Unregisters all extension module element
1209 */
1210static void
1211xsltUnregisterAllExtModuleElement (void) {
1212    xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement);
1213    xsltElementsHash = NULL;
1214}
1215
1216/**
1217 * xsltRegisterExtModuleTopLevel:
1218 * @name:  the top-level element name
1219 * @URI:  the top-level element namespace URI
1220 * @function:  the top-level element callback
1221 *
1222 * Registers an extension module top-level element.
1223 *
1224 * Returns 0 if successful, -1 in case of error.
1225 */
1226int
1227xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI,
1228                               xsltTopLevelFunction function) {
1229    if ((name == NULL) || (URI == NULL) || (function == NULL))
1230        return(-1);
1231
1232    if (xsltTopLevelsHash == NULL)
1233        xsltTopLevelsHash = xmlHashCreate(10);
1234    if (xsltTopLevelsHash == NULL)
1235        return(-1);
1236
1237    xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
1238                        (void *) function, NULL);
1239
1240    return(0);
1241}
1242
1243/**
1244 * xsltExtModuleTopLevelLookup:
1245 * @name:  the top-level element name
1246 * @URI:  the top-level element namespace URI
1247 *
1248 * Looks up an extension module top-level element
1249 *
1250 * Returns the callback function if found, NULL otherwise.
1251 */
1252xsltTopLevelFunction
1253xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI) {
1254    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1255        return(NULL);
1256
1257    return((xsltTopLevelFunction)
1258            xmlHashLookup2(xsltTopLevelsHash, name, URI));
1259}
1260
1261/**
1262 * xsltUnregisterExtModuleTopLevel:
1263 * @name:  the top-level element name
1264 * @URI:  the top-level element namespace URI
1265 *
1266 * Unregisters an extension module top-level element
1267 *
1268 * Returns 0 if successful, -1 in case of error.
1269 */
1270int
1271xsltUnregisterExtModuleTopLevel (const xmlChar *name,
1272                                 const xmlChar *URI) {
1273    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1274        return(-1);
1275
1276    return xmlHashRemoveEntry2 (xsltTopLevelsHash, name, URI, NULL);
1277}
1278
1279/**
1280 * xsltUnregisterAllExtModuleTopLevel:
1281 *
1282 * Unregisters all extension module function
1283 */
1284static void
1285xsltUnregisterAllExtModuleTopLevel (void) {
1286    xmlHashFree(xsltTopLevelsHash, NULL);
1287    xsltTopLevelsHash = NULL;
1288}
1289
1290
1291/************************************************************************
1292 *                                                                      *
1293 *              Test module http://xmlsoft.org/XSLT/                    *
1294 *                                                                      *
1295 ************************************************************************/
1296
1297/************************************************************************
1298 *                                                                      *
1299 *              Test of the extension module API                        *
1300 *                                                                      *
1301 ************************************************************************/
1302
1303static xmlChar *testData = NULL;
1304static xmlChar *testStyleData = NULL;
1305
1306/**
1307 * xsltExtFunctionTest:
1308 * @ctxt:  the XPath Parser context
1309 * @nargs:  the number of arguments
1310 *
1311 * function libxslt:test() for testing the extensions support.
1312 */
1313static void
1314xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs ATTRIBUTE_UNUSED)
1315{
1316    xsltTransformContextPtr tctxt;
1317    void *data = NULL;
1318
1319    tctxt = xsltXPathGetTransformContext(ctxt);
1320
1321    if (testData == NULL) {
1322        xsltGenericDebug(xsltGenericDebugContext,
1323                         "xsltExtFunctionTest: not initialized,"
1324                         " calling xsltGetExtData\n");
1325        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1326        if (data == NULL) {
1327            xsltTransformError(tctxt, NULL, NULL,
1328                             "xsltExtElementTest: not initialized\n");
1329            return;
1330        }
1331    }
1332    if (tctxt == NULL) {
1333        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1334                         "xsltExtFunctionTest: failed to get the transformation context\n");
1335        return;
1336    }
1337    if (data == NULL)
1338        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1339    if (data == NULL) {
1340        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1341                         "xsltExtFunctionTest: failed to get module data\n");
1342        return;
1343    }
1344    if (data != testData) {
1345        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1346                         "xsltExtFunctionTest: got wrong module data\n");
1347        return;
1348    }
1349#ifdef WITH_XSLT_DEBUG_FUNCTION
1350    xsltGenericDebug(xsltGenericDebugContext,
1351                     "libxslt:test() called with %d args\n", nargs);
1352#endif
1353}
1354
1355/**
1356 * xsltExtElementPreCompTest:
1357 * @style:  the stylesheet
1358 * @inst:  the instruction in the stylesheet
1359 *
1360 * Process a libxslt:test node
1361 */
1362static xsltElemPreCompPtr
1363xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
1364                          xsltTransformFunction function) {
1365    xsltElemPreCompPtr ret;
1366
1367    if (style == NULL) {
1368        xsltTransformError(NULL, NULL, inst,
1369                 "xsltExtElementTest: no transformation context\n");
1370        return (NULL);
1371    }
1372    if (testStyleData == NULL) {
1373        xsltGenericDebug(xsltGenericDebugContext,
1374                 "xsltExtElementPreCompTest: not initialized,"
1375                 " calling xsltStyleGetExtData\n");
1376        xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
1377        if (testStyleData == NULL) {
1378            xsltTransformError(NULL, style, inst,
1379                 "xsltExtElementPreCompTest: not initialized\n");
1380            if (style != NULL) style->errors++;
1381            return (NULL);
1382        }
1383    }
1384    if (inst == NULL) {
1385        xsltTransformError(NULL, style, inst,
1386                 "xsltExtElementPreCompTest: no instruction\n");
1387        if (style != NULL) style->errors++;
1388        return (NULL);
1389    }
1390    ret = xsltNewElemPreComp (style, inst, function);
1391    return (ret);
1392}
1393
1394/**
1395 * xsltExtElementTest:
1396 * @ctxt:  an XSLT processing context
1397 * @node:  The current node
1398 * @inst:  the instruction in the stylesheet
1399 * @comp:  precomputed informations
1400 *
1401 * Process a libxslt:test node
1402 */
1403static void
1404xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
1405                   xmlNodePtr inst,
1406                   xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
1407{
1408    xmlNodePtr commentNode;
1409
1410    if (testData == NULL) {
1411        xsltGenericDebug(xsltGenericDebugContext,
1412                         "xsltExtElementTest: not initialized,"
1413                         " calling xsltGetExtData\n");
1414        xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1415        if (testData == NULL) {
1416            xsltTransformError(ctxt, NULL, inst,
1417                             "xsltExtElementTest: not initialized\n");
1418            return;
1419        }
1420    }
1421    if (ctxt == NULL) {
1422        xsltTransformError(ctxt, NULL, inst,
1423                         "xsltExtElementTest: no transformation context\n");
1424        return;
1425    }
1426    if (node == NULL) {
1427        xsltTransformError(ctxt, NULL, inst,
1428                         "xsltExtElementTest: no current node\n");
1429        return;
1430    }
1431    if (inst == NULL) {
1432        xsltTransformError(ctxt, NULL, inst,
1433                         "xsltExtElementTest: no instruction\n");
1434        return;
1435    }
1436    if (ctxt->insert == NULL) {
1437        xsltTransformError(ctxt, NULL, inst,
1438                         "xsltExtElementTest: no insertion point\n");
1439        return;
1440    }
1441    commentNode =
1442        xmlNewComment((const xmlChar *)
1443                      "libxslt:test element test worked");
1444    xmlAddChild(ctxt->insert, commentNode);
1445}
1446
1447/**
1448 * xsltExtInitTest:
1449 * @ctxt:  an XSLT transformation context
1450 * @URI:  the namespace URI for the extension
1451 *
1452 * A function called at initialization time of an XSLT extension module
1453 *
1454 * Returns a pointer to the module specific data for this transformation
1455 */
1456static void *
1457xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) {
1458    if (testStyleData == NULL) {
1459        xsltGenericDebug(xsltGenericErrorContext,
1460                         "xsltExtInitTest: not initialized,"
1461                         " calling xsltStyleGetExtData\n");
1462        xsltStyleGetExtData(ctxt->style, URI);
1463        if (testStyleData == NULL) {
1464            xsltTransformError(ctxt, NULL, NULL,
1465                             "xsltExtInitTest: not initialized\n");
1466            return (NULL);
1467        }
1468    }   
1469    if (testData != NULL) {
1470        xsltTransformError(ctxt, NULL, NULL,
1471                         "xsltExtInitTest: already initialized\n");
1472        return (NULL);
1473    }
1474    testData = (void *) "test data";
1475    xsltGenericDebug(xsltGenericDebugContext,
1476                     "Registered test module : %s\n", URI);
1477    return (testData);
1478}
1479
1480
1481/**
1482 * xsltExtShutdownTest:
1483 * @ctxt:  an XSLT transformation context
1484 * @URI:  the namespace URI for the extension
1485 * @data:  the data associated to this module
1486 *
1487 * A function called at shutdown time of an XSLT extension module
1488 */
1489static void
1490xsltExtShutdownTest(xsltTransformContextPtr ctxt,
1491                    const xmlChar * URI, void *data) {
1492    if (testData == NULL) {
1493        xsltTransformError(ctxt, NULL, NULL,
1494                         "xsltExtShutdownTest: not initialized\n");
1495        return;
1496    }
1497    if (data != testData) {
1498        xsltTransformError(ctxt, NULL, NULL,
1499                         "xsltExtShutdownTest: wrong data\n");
1500    }
1501    testData = NULL;
1502    xsltGenericDebug(xsltGenericDebugContext,
1503                     "Unregistered test module : %s\n", URI);
1504}
1505/**
1506 * xsltExtStyleInitTest:
1507 * @style:  an XSLT stylesheet
1508 * @URI:  the namespace URI for the extension
1509 *
1510 * A function called at initialization time of an XSLT extension module
1511 *
1512 * Returns a pointer to the module specific data for this transformation
1513 */
1514static void *
1515xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
1516                     const xmlChar * URI)
1517{
1518    if (testStyleData != NULL) {
1519        xsltTransformError(NULL, NULL, NULL,
1520                         "xsltExtInitTest: already initialized\n");
1521        return (NULL);
1522    }
1523    testStyleData = (void *) "test data";
1524    xsltGenericDebug(xsltGenericDebugContext,
1525                     "Registered test module : %s\n", URI);
1526    return (testStyleData);
1527}
1528
1529
1530/**
1531 * xsltExtStyleShutdownTest:
1532 * @style:  an XSLT stylesheet
1533 * @URI:  the namespace URI for the extension
1534 * @data:  the data associated to this module
1535 *
1536 * A function called at shutdown time of an XSLT extension module
1537 */
1538static void
1539xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
1540                         const xmlChar * URI, void *data) {
1541    if (testStyleData == NULL) {
1542        xsltGenericError(xsltGenericErrorContext,
1543                         "xsltExtShutdownTest: not initialized\n");
1544        return;
1545    }
1546    if (data != testStyleData) {
1547        xsltTransformError(NULL, NULL, NULL,
1548                         "xsltExtShutdownTest: wrong data\n");
1549    }
1550    testStyleData = NULL;
1551    xsltGenericDebug(xsltGenericDebugContext,
1552                     "Unregistered test module : %s\n", URI);
1553}
1554
1555/**
1556 * xsltRegisterTestModule:
1557 *
1558 * Registers the test module
1559 */
1560void
1561xsltRegisterTestModule (void) {
1562    xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
1563                              xsltExtInitTest, xsltExtShutdownTest,
1564                              xsltExtStyleInitTest,
1565                              xsltExtStyleShutdownTest);
1566    xsltRegisterExtModuleFunction((const xmlChar *) "test",
1567                            (const xmlChar *) XSLT_DEFAULT_URL,
1568                            xsltExtFunctionTest);
1569    xsltRegisterExtModuleElement((const xmlChar *) "test",
1570                                 (const xmlChar *) XSLT_DEFAULT_URL,
1571                                 xsltExtElementPreCompTest ,
1572                                 xsltExtElementTest);
1573}
1574
1575/**
1576 * xsltCleanupGlobals:
1577 *
1578 * Unregister all global variables set up by the XSLT library
1579 */
1580void
1581xsltCleanupGlobals(void)
1582{
1583    xsltUnregisterAllExtModules();
1584    xsltUnregisterAllExtModuleFunction();
1585    xsltUnregisterAllExtModuleElement();
1586    xsltUnregisterAllExtModuleTopLevel();
1587}
1588
1589static void
1590xsltDebugDumpExtensionsCallback(void* function ATTRIBUTE_UNUSED,
1591                                FILE *output, const xmlChar* name,
1592                                const xmlChar* URI,
1593                                const xmlChar* not_used ATTRIBUTE_UNUSED) {
1594        if (!name||!URI)
1595                return;
1596        fprintf(output,"{%s}%s\n",URI,name);
1597}
1598
1599/**
1600 * xsltDebugDumpExtensions:
1601 * @output:  the FILE * for the output, if NULL stdout is used
1602 *
1603 * Dumps a list of the registered XSLT extension functions and elements
1604 */
1605void
1606xsltDebugDumpExtensions(FILE * output)
1607{
1608        if (output == NULL)
1609                output = stdout;
1610    fprintf(output,"Registered XSLT Extensions\n--------------------------\n");
1611        if (!xsltFunctionsHash)
1612                fprintf(output,"No registered extension functions\n");
1613        else {
1614                fprintf(output,"Registered Extension Functions:\n");
1615                xmlHashScanFull(xsltFunctionsHash,(xmlHashScannerFull)xsltDebugDumpExtensionsCallback,output);
1616        }
1617        if (!xsltElementsHash)
1618                fprintf(output,"\nNo registered extension elements\n");
1619        else {
1620                fprintf(output,"\nRegistered Extension Elements:\n");
1621                xmlHashScanFull(xsltElementsHash,(xmlHashScannerFull)xsltDebugDumpExtensionsCallback,output);
1622        }
1623
1624}
1625
Note: See TracBrowser for help on using the repository browser.