f000287c000adb9212eebcce41609d548a2f8800
[platform/upstream/libxslt.git] / libxslt / extensions.c
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
39 typedef struct _xsltExtDef xsltExtDef;
40 typedef xsltExtDef *xsltExtDefPtr;
41 struct _xsltExtDef {
42     struct _xsltExtDef *next;
43     xmlChar *prefix;
44     xmlChar *URI;
45     void    *data;
46 };
47
48 typedef struct _xsltExtModule xsltExtModule;
49 typedef xsltExtModule *xsltExtModulePtr;
50 struct _xsltExtModule {
51     xsltExtInitFunction initFunc;
52     xsltExtShutdownFunction shutdownFunc;
53     xsltStyleExtInitFunction styleInitFunc;
54     xsltStyleExtShutdownFunction styleShutdownFunc;
55 };
56
57 typedef struct _xsltExtData xsltExtData;
58 typedef xsltExtData *xsltExtDataPtr;
59 struct _xsltExtData {
60     xsltExtModulePtr extModule;
61     void *extData;
62 };
63
64 typedef struct _xsltExtElement xsltExtElement;
65 typedef xsltExtElement *xsltExtElementPtr;
66 struct _xsltExtElement {
67     xsltPreComputeFunction precomp;
68     xsltTransformFunction  transform;
69 };
70
71 static xmlHashTablePtr xsltExtensionsHash = NULL;
72 static xmlHashTablePtr xsltFunctionsHash = NULL;
73 static xmlHashTablePtr xsltElementsHash = NULL;
74 static 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  */
91 static xsltExtDefPtr
92 xsltNewExtDef(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  */
116 static void
117 xsltFreeExtDef(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  */
133 static void
134 xsltFreeExtDefList(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  */
155 static xsltExtModulePtr
156 xsltNewExtModule(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  */
182 static void
183 xsltFreeExtModule(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  */
198 static xsltExtDataPtr
199 xsltNewExtData(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  */
222 static void
223 xsltFreeExtData(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  */
239 static xsltExtElementPtr
240 xsltNewExtElement (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  */
264 static void
265 xsltFreeExtElement (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  */
285 void
286 xsltFreeExts(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  */
301 int
302 xsltRegisterExtPrefix(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  */
359 int
360 xsltRegisterExtFunction(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  */
386 int     
387 xsltRegisterExtElement(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  */
405 void
406 xsltFreeCtxtExts(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  */
423 void *
424 xsltStyleGetExtData(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  */
501 void *
502 xsltGetExtData(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
556 typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
557 struct _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  */
570 static void
571 xsltInitCtxtExt (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     ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI);
595     if (ctxtData != NULL) {
596 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
597         xsltGenericDebug(xsltGenericDebugContext,
598                          "xsltInitCtxtExt: already initialized\n");
599 #endif
600         return;
601     }
602
603     extData = module->initFunc(ctxt->ctxt, URI);
604     if (extData == NULL) {
605 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
606         xsltGenericDebug(xsltGenericDebugContext,
607                          "xsltInitCtxtExt: no extData\n");
608 #endif
609     }
610     ctxtData = xsltNewExtData(module, extData);
611     if (ctxtData == NULL) {
612         ctxt->ret = -1;
613         return;
614     }
615
616     if (ctxt->ctxt->extInfos == NULL)
617         ctxt->ctxt->extInfos = xmlHashCreate(10);
618     if (ctxt->ctxt->extInfos == NULL) {
619         ctxt->ret = -1;
620         return;
621     }
622
623     if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
624         xsltGenericError(xsltGenericErrorContext,
625                          "Failed to register module data: %s\n", URI);
626         if (module->shutdownFunc)
627             module->shutdownFunc(ctxt->ctxt, URI, extData);
628         xsltFreeExtData(ctxtData);
629         ctxt->ret = -1;
630         return;
631     }
632 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
633     xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
634                      URI);
635 #endif
636     ctxt->ret++;
637 }
638
639 /**
640  * xsltInitCtxtExts:
641  * @ctxt: an XSLT transformation context
642  *
643  * Initialize the set of modules with registered stylesheet data
644  *
645  * Returns the number of modules initialized or -1 in case of error
646  */
647 int
648 xsltInitCtxtExts(xsltTransformContextPtr ctxt)
649 {
650     xsltStylesheetPtr style;
651     xsltInitExtCtxt ctx;
652
653     if (ctxt == NULL)
654         return (-1);
655
656     style = ctxt->style;
657     if (style == NULL)
658         return (-1);
659
660     ctx.ctxt = ctxt;
661     ctx.ret = 0;
662
663     while (style != NULL) {
664         if (style->extInfos != NULL) {
665             xmlHashScan(style->extInfos,
666                         (xmlHashScanner) xsltInitCtxtExt, &ctx);
667             if (ctx.ret == -1)
668                 return(-1);
669         }
670         style = xsltNextImport(style);
671     }
672 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
673     xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
674                      ctx.ret);
675 #endif
676     return (ctx.ret);
677 }
678
679 /**
680  * xsltShutdownCtxtExt:
681  * @data:  the registered data for the module
682  * @ctxt:  the XSLT transformation context
683  * @URI:  the extension URI
684  *
685  * Shutdown an extension module loaded
686  */
687 static void
688 xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt,
689                     const xmlChar * URI)
690 {
691     xsltExtModulePtr module;
692
693     if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
694         return;
695     module = data->extModule;
696     if ((module == NULL) || (module->shutdownFunc == NULL))
697         return;
698
699 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
700     xsltGenericDebug(xsltGenericDebugContext,
701                      "Shutting down module : %s\n", URI);
702 #endif
703     module->shutdownFunc(ctxt, URI, data->extData);
704 }
705
706 /**
707  * xsltShutdownCtxtExts:
708  * @ctxt: an XSLT transformation context
709  *
710  * Shutdown the set of modules loaded
711  */
712 void
713 xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
714 {
715     if (ctxt == NULL)
716         return;
717     if (ctxt->extInfos == NULL)
718         return;
719     xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt, ctxt);
720     xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData);
721     ctxt->extInfos = NULL;
722 }
723
724 /**
725  * xsltShutdownExt:
726  * @data:  the registered data for the module
727  * @ctxt:  the XSLT stylesheet
728  * @URI:  the extension URI
729  *
730  * Shutdown an extension module loaded
731  */
732 static void
733 xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style,
734                 const xmlChar * URI)
735 {
736     xsltExtModulePtr module;
737
738     if ((data == NULL) || (style == NULL) || (URI == NULL))
739         return;
740     module = data->extModule;
741     if ((module == NULL) || (module->styleShutdownFunc == NULL))
742         return;
743
744 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
745     xsltGenericDebug(xsltGenericDebugContext,
746                      "Shutting down module : %s\n", URI);
747 #endif
748     module->styleShutdownFunc(style, URI, data->extData);
749     xmlHashRemoveEntry(style->extInfos, URI,
750                        (xmlHashDeallocator) xsltFreeExtData);
751 }
752
753 /**
754  * xsltShutdownExts:
755  * @style: an XSLT stylesheet
756  *
757  * Shutdown the set of modules loaded
758  */
759 void
760 xsltShutdownExts(xsltStylesheetPtr style)
761 {
762     if (style == NULL)
763         return;
764     if (style->extInfos == NULL)
765         return;
766     xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style);
767     xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData);
768     style->extInfos = NULL;
769 }
770
771 /**
772  * xsltCheckExtPrefix:
773  * @style: the stylesheet
774  * @prefix: the namespace prefix (possibly NULL)
775  *
776  * Check if the given prefix is one of the declared extensions
777  *
778  * Returns 1 if this is an extension, 0 otherwise
779  */
780 int
781 xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar *prefix) {
782     xsltExtDefPtr cur;
783
784     if ((style == NULL) || (style->nsDefs == NULL))
785         return(0);
786
787     if (prefix == NULL)
788         prefix = BAD_CAST "#default";
789
790     cur = (xsltExtDefPtr) style->nsDefs;
791     while (cur != NULL) {
792         if (xmlStrEqual(prefix, cur->prefix))
793             return(1);
794         cur = cur->next;
795     }
796     return(0);
797 }
798
799 /**
800  * xsltRegisterExtModuleFull:
801  * @URI:  URI associated to this module
802  * @initFunc:  the module initialization function
803  * @shutdownFunc:  the module shutdown function
804  * @styleInitFunc:  the module initialization function
805  * @styleShutdownFunc:  the module shutdown function
806  *
807  * Register an XSLT extension module to the library.
808  *
809  * Returns 0 if sucessful, -1 in case of error
810  */
811 int
812 xsltRegisterExtModuleFull(const xmlChar * URI,
813                           xsltExtInitFunction initFunc,
814                           xsltExtShutdownFunction shutdownFunc,
815                           xsltStyleExtInitFunction styleInitFunc,
816                           xsltStyleExtShutdownFunction styleShutdownFunc)
817 {
818     int ret;
819     xsltExtModulePtr module;
820
821     if ((URI == NULL) || (initFunc == NULL))
822         return (-1);
823     if (xsltExtensionsHash == NULL)
824         xsltExtensionsHash = xmlHashCreate(10);
825
826     if (xsltExtensionsHash == NULL)
827         return (-1);
828
829     module = xmlHashLookup(xsltExtensionsHash, URI);
830     if (module != NULL) {
831         if ((module->initFunc == initFunc) &&
832             (module->shutdownFunc == shutdownFunc))
833             return (0);
834         return (-1);
835     }
836     module = xsltNewExtModule(initFunc, shutdownFunc,
837                               styleInitFunc, styleShutdownFunc);
838     if (module == NULL)
839         return (-1);
840     ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
841     return (ret);
842 }
843
844 /**
845  * xsltRegisterExtModule:
846  * @URI:  URI associated to this module
847  * @initFunc:  the module initialization function
848  * @shutdownFunc:  the module shutdown function
849  *
850  * Register an XSLT extension module to the library.
851  *
852  * Returns 0 if sucessful, -1 in case of error
853  */
854 int
855 xsltRegisterExtModule(const xmlChar * URI,
856                       xsltExtInitFunction initFunc,
857                       xsltExtShutdownFunction shutdownFunc) {
858     return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
859                                      NULL, NULL);
860 }
861
862 /**
863  * xsltUnregisterExtModule:
864  * @URI:  URI associated to this module
865  *
866  * Unregister an XSLT extension module from the library.
867  *
868  * Returns 0 if sucessful, -1 in case of error
869  */
870 int
871 xsltUnregisterExtModule(const xmlChar * URI)
872 {
873     int ret;
874
875     if (URI == NULL)
876         return (-1);
877     if (xsltExtensionsHash == NULL)
878         return (-1);
879
880     ret =
881         xmlHashRemoveEntry(xsltExtensionsHash, URI,
882                            (xmlHashDeallocator) xsltFreeExtModule);
883     return (ret);
884 }
885
886 /**
887  * xsltUnregisterAllExtModules:
888  *
889  * Unregister all the XSLT extension module from the library.
890  */
891 static void
892 xsltUnregisterAllExtModules(void)
893 {
894     if (xsltExtensionsHash == NULL)
895         return;
896
897     xmlHashFree(xsltExtensionsHash, (xmlHashDeallocator) xsltFreeExtModule);
898     xsltExtensionsHash = NULL;
899 }
900
901 /**
902  * xsltXPathGetTransformContext:
903  * @ctxt:  an XPath transformation context
904  *
905  * Provides the XSLT transformation context from the XPath transformation
906  * context. This is useful when an XPath function in the extension module
907  * is called by the XPath interpreter and that the XSLT context is needed
908  * for example to retrieve the associated data pertaining to this XSLT
909  * transformation.
910  *
911  * Returns the XSLT transformation context or NULL in case of error.
912  */
913 xsltTransformContextPtr
914 xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
915 {
916     if ((ctxt == NULL) || (ctxt->context == NULL))
917         return(NULL);
918     return(ctxt->context->extra);
919 }
920
921 /**
922  * xsltRegisterExtModuleFunction:
923  * @name:  the function name
924  * @URI:  the function namespace URI
925  * @function:  the function callback
926  *
927  * Registers an extension module function.
928  *
929  * Returns 0 if successful, -1 in case of error.
930  */
931 int
932 xsltRegisterExtModuleFunction (const xmlChar *name, const xmlChar *URI,
933                                xmlXPathFunction function) {
934     if ((name == NULL) || (URI == NULL) || (function == NULL))
935         return(-1);
936
937     if (xsltFunctionsHash == NULL)
938         xsltFunctionsHash = xmlHashCreate(10);
939     if (xsltFunctionsHash == NULL)
940         return(-1);
941
942     xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
943                         (void *) function, NULL);
944
945     return(0);
946 }
947
948 /**
949  * xsltExtModuleFunctionLookup:
950  * @name:  the function name
951  * @URI:  the function namespace URI
952  *
953  * Looks up an extension module function
954  *
955  * Returns the function if found, NULL otherwise.
956  */
957 xmlXPathFunction
958 xsltExtModuleFunctionLookup (const xmlChar *name, const xmlChar *URI) {
959     if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
960         return(NULL);
961
962     return (xmlXPathFunction) xmlHashLookup2(xsltFunctionsHash, name, URI);
963 }
964
965 /**
966  * xsltUnregisterExtModuleFunction:
967  * @name:  the function name
968  * @URI:  the function namespace URI
969  *
970  * Unregisters an extension module function
971  *
972  * Returns 0 if successful, -1 in case of error.
973  */
974 int
975 xsltUnregisterExtModuleFunction (const xmlChar *name,
976                                  const xmlChar *URI) {
977     if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
978         return(-1);
979
980     return xmlHashRemoveEntry2 (xsltFunctionsHash, name, URI, NULL);
981 }
982
983 /**
984  * xsltUnregisterAllExtModuleFunction:
985  *
986  * Unregisters all extension module function
987  */
988 static void
989 xsltUnregisterAllExtModuleFunction (void) {
990     xmlHashFree(xsltFunctionsHash, NULL);
991     xsltFunctionsHash = NULL;
992 }
993
994
995 /**
996  * xsltNewElemPreComp:
997  * @style:  the XSLT stylesheet
998  * @inst:  the element node
999  * @function: the transform function
1000  *
1001  * Creates and initializes an #xsltElemPreComp
1002  *
1003  * Returns the new and initialized #xsltElemPreComp
1004  */
1005 xsltElemPreCompPtr
1006 xsltNewElemPreComp (xsltStylesheetPtr style, xmlNodePtr inst,
1007                     xsltTransformFunction function) {
1008     xsltElemPreCompPtr cur;
1009
1010     cur = (xsltElemPreCompPtr) xmlMalloc (sizeof(xsltElemPreComp));
1011     if (cur == NULL) {
1012         xsltTransformError(NULL, style, NULL,
1013                          "xsltNewExtElement : malloc failed\n");
1014         return (NULL);
1015     }
1016     memset(cur, 0, sizeof(xsltElemPreComp));
1017
1018     xsltInitElemPreComp (cur, style, inst, function,
1019                          (xsltElemPreCompDeallocator) xmlFree);
1020
1021     return (cur);
1022 }
1023
1024 /**
1025  * xsltInitElemPreComp:
1026  * @comp:  an #xsltElemPreComp (or generally a derived structure)
1027  * @style:  the XSLT stylesheet
1028  * @inst:  the element node
1029  * @function:  the transform function
1030  * @freeFunc:  the @comp deallocator
1031  *
1032  * Initializes an existing #xsltElemPreComp structure. This is usefull
1033  * when extending an #xsltElemPreComp to store precomputed data.
1034  * This function MUST be called on any extension element precomputed
1035  * data struct.
1036  */
1037 void
1038 xsltInitElemPreComp (xsltElemPreCompPtr comp, xsltStylesheetPtr style,
1039                      xmlNodePtr inst, xsltTransformFunction function,
1040                      xsltElemPreCompDeallocator freeFunc) {
1041     comp->type = XSLT_FUNC_EXTENSION;
1042     comp->func = function;
1043     comp->inst = inst;
1044     comp->free = freeFunc;
1045
1046     comp->next = style->preComps;
1047     style->preComps = comp;
1048 }
1049
1050 /**
1051  * xsltPreComputeExtModuleElement:
1052  * @style:  the stylesheet
1053  * @inst:  the element node
1054  *
1055  * Precomputes an extension module element
1056  *
1057  * Returns the precomputed data
1058  */
1059 xsltElemPreCompPtr
1060 xsltPreComputeExtModuleElement (xsltStylesheetPtr style,
1061                                 xmlNodePtr inst) {
1062     xsltExtElementPtr ext;
1063     xsltElemPreCompPtr comp = NULL;
1064
1065     if ((style == NULL) || (inst == NULL) ||
1066         (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
1067         return (NULL);
1068
1069     ext = (xsltExtElementPtr)
1070         xmlHashLookup2 (xsltElementsHash, inst->name,
1071                         inst->ns->href);
1072     if (ext == NULL)
1073         return (NULL);
1074
1075     if (ext->precomp != NULL)
1076         comp = ext->precomp(style, inst, ext->transform);
1077     if (comp == NULL)
1078         comp = xsltNewElemPreComp (style, inst, ext->transform);
1079
1080     return (comp);
1081 }
1082
1083 /**
1084  * xsltRegisterExtModuleElement:
1085  * @name:  the element name
1086  * @URI:  the element namespace URI
1087  * @precomp:  the pre-computation callback
1088  * @transform:  the transformation callback
1089  *
1090  * Registers an extension module element.
1091  *
1092  * Returns 0 if successful, -1 in case of error.
1093  */
1094 int
1095 xsltRegisterExtModuleElement (const xmlChar *name, const xmlChar *URI,
1096                               xsltPreComputeFunction precomp,
1097                               xsltTransformFunction transform) {
1098     xsltExtElementPtr ext;
1099
1100     if ((name == NULL) || (URI == NULL) || (transform == NULL))
1101         return(-1);
1102
1103     if (xsltElementsHash == NULL)
1104         xsltElementsHash = xmlHashCreate(10);
1105     if (xsltElementsHash == NULL)
1106         return(-1);
1107
1108     ext = xsltNewExtElement(precomp, transform);
1109     if (ext == NULL)
1110         return(-1);
1111
1112     xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
1113                         (xmlHashDeallocator) xsltFreeExtElement);
1114
1115     return(0);
1116 }
1117
1118 /**
1119  * xsltExtElementLookup:
1120  * @ctxt:  an XSLT process context
1121  * @name:  the element name
1122  * @URI:  the element namespace URI
1123  *
1124  * Looks up an extension element. @ctxt can be NULL to search only in
1125  * module elements.
1126  *
1127  * Returns the element callback or NULL if not found
1128  */
1129 xsltTransformFunction
1130 xsltExtElementLookup (xsltTransformContextPtr ctxt,
1131                       const xmlChar *name, const xmlChar *URI) {
1132     xsltTransformFunction ret;
1133
1134     if ((name == NULL) || (URI == NULL))
1135         return(NULL);
1136
1137     if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
1138         ret = (xsltTransformFunction)
1139             xmlHashLookup2(ctxt->extElements, name, URI);
1140         if (ret != NULL)
1141             return(ret);
1142     }
1143     return xsltExtModuleElementLookup(name, URI);
1144 }
1145
1146 /**
1147  * xsltExtModuleElementLookup:
1148  * @name:  the element name
1149  * @URI:  the element namespace URI
1150  *
1151  * Looks up an extension module element
1152  *
1153  * Returns the callback function if found, NULL otherwise.
1154  */
1155 xsltTransformFunction
1156 xsltExtModuleElementLookup (const xmlChar *name, const xmlChar *URI) {
1157     xsltExtElementPtr ext;
1158
1159     if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1160         return(NULL);
1161
1162     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1163
1164     if (ext == NULL)
1165         return(NULL);
1166     return(ext->transform);
1167 }
1168
1169 /**
1170  * xsltExtModuleElementPreComputeLookup:
1171  * @name:  the element name
1172  * @URI:  the element namespace URI
1173  *
1174  * Looks up an extension module element pre-computation function
1175  *
1176  * Returns the callback function if found, NULL otherwise.
1177  */
1178 xsltPreComputeFunction
1179 xsltExtModuleElementPreComputeLookup (const xmlChar *name,
1180                                       const xmlChar *URI) {
1181     xsltExtElementPtr ext;
1182
1183     if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1184         return(NULL);
1185
1186     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1187
1188     if (ext == NULL)
1189         return(NULL);
1190     return(ext->precomp);
1191 }
1192
1193 /**
1194  * xsltUnregisterExtModuleElement:
1195  * @name:  the element name
1196  * @URI:  the element namespace URI
1197  *
1198  * Unregisters an extension module element
1199  *
1200  * Returns 0 if successful, -1 in case of error.
1201  */
1202 int
1203 xsltUnregisterExtModuleElement (const xmlChar *name,
1204                                 const xmlChar *URI) {
1205     if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1206         return(-1);
1207
1208     return xmlHashRemoveEntry2 (xsltElementsHash, name, URI,
1209                                 (xmlHashDeallocator) xsltFreeExtElement);
1210 }
1211
1212 /**
1213  * xsltUnregisterAllExtModuleElement:
1214  *
1215  * Unregisters all extension module element
1216  */
1217 static void
1218 xsltUnregisterAllExtModuleElement (void) {
1219     xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement);
1220     xsltElementsHash = NULL;
1221 }
1222
1223 /**
1224  * xsltRegisterExtModuleTopLevel:
1225  * @name:  the top-level element name
1226  * @URI:  the top-level element namespace URI
1227  * @function:  the top-level element callback
1228  *
1229  * Registers an extension module top-level element.
1230  *
1231  * Returns 0 if successful, -1 in case of error.
1232  */
1233 int
1234 xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI,
1235                                xsltTopLevelFunction function) {
1236     if ((name == NULL) || (URI == NULL) || (function == NULL))
1237         return(-1);
1238
1239     if (xsltTopLevelsHash == NULL)
1240         xsltTopLevelsHash = xmlHashCreate(10);
1241     if (xsltTopLevelsHash == NULL)
1242         return(-1);
1243
1244     xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
1245                         (void *) function, NULL);
1246
1247     return(0);
1248 }
1249
1250 /**
1251  * xsltExtModuleTopLevelLookup:
1252  * @name:  the top-level element name
1253  * @URI:  the top-level element namespace URI
1254  *
1255  * Looks up an extension module top-level element
1256  *
1257  * Returns the callback function if found, NULL otherwise.
1258  */
1259 xsltTopLevelFunction
1260 xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI) {
1261     if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1262         return(NULL);
1263
1264     return((xsltTopLevelFunction)
1265             xmlHashLookup2(xsltTopLevelsHash, name, URI));
1266 }
1267
1268 /**
1269  * xsltUnregisterExtModuleTopLevel:
1270  * @name:  the top-level element name
1271  * @URI:  the top-level element namespace URI
1272  *
1273  * Unregisters an extension module top-level element
1274  *
1275  * Returns 0 if successful, -1 in case of error.
1276  */
1277 int
1278 xsltUnregisterExtModuleTopLevel (const xmlChar *name,
1279                                  const xmlChar *URI) {
1280     if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1281         return(-1);
1282
1283     return xmlHashRemoveEntry2 (xsltTopLevelsHash, name, URI, NULL);
1284 }
1285
1286 /**
1287  * xsltUnregisterAllExtModuleTopLevel:
1288  *
1289  * Unregisters all extension module function
1290  */
1291 static void
1292 xsltUnregisterAllExtModuleTopLevel (void) {
1293     xmlHashFree(xsltTopLevelsHash, NULL);
1294     xsltTopLevelsHash = NULL;
1295 }
1296
1297 /**
1298  * xsltGetExtInfo:
1299  * @style:  pointer to a stylesheet
1300  * @URI:    the namespace URI desired
1301  *
1302  * looks up URI in extInfos of the stylesheet
1303  *
1304  * returns a pointer to the hash table if found, else NULL
1305  */
1306 xmlHashTablePtr
1307 xsltGetExtInfo (xsltStylesheetPtr style, const xmlChar *URI) {
1308     xsltExtDataPtr data;
1309     
1310     if (style != NULL && style->extInfos != NULL) {
1311         data = xmlHashLookup(style->extInfos, URI);
1312         if (data != NULL && data->extData != NULL)
1313             return data->extData;
1314     }
1315     return NULL;
1316 }
1317
1318 /************************************************************************
1319  *                                                                      *
1320  *              Test module http://xmlsoft.org/XSLT/                    *
1321  *                                                                      *
1322  ************************************************************************/
1323
1324 /************************************************************************
1325  *                                                                      *
1326  *              Test of the extension module API                        *
1327  *                                                                      *
1328  ************************************************************************/
1329
1330 static xmlChar *testData = NULL;
1331 static xmlChar *testStyleData = NULL;
1332
1333 /**
1334  * xsltExtFunctionTest:
1335  * @ctxt:  the XPath Parser context
1336  * @nargs:  the number of arguments
1337  *
1338  * function libxslt:test() for testing the extensions support.
1339  */
1340 static void
1341 xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs ATTRIBUTE_UNUSED)
1342 {
1343     xsltTransformContextPtr tctxt;
1344     void *data = NULL;
1345
1346     tctxt = xsltXPathGetTransformContext(ctxt);
1347
1348     if (testData == NULL) {
1349         xsltGenericDebug(xsltGenericDebugContext,
1350                          "xsltExtFunctionTest: not initialized,"
1351                          " calling xsltGetExtData\n");
1352         data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1353         if (data == NULL) {
1354             xsltTransformError(tctxt, NULL, NULL,
1355                              "xsltExtElementTest: not initialized\n");
1356             return;
1357         }
1358     }
1359     if (tctxt == NULL) {
1360         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1361                          "xsltExtFunctionTest: failed to get the transformation context\n");
1362         return;
1363     }
1364     if (data == NULL)
1365         data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1366     if (data == NULL) {
1367         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1368                          "xsltExtFunctionTest: failed to get module data\n");
1369         return;
1370     }
1371     if (data != testData) {
1372         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1373                          "xsltExtFunctionTest: got wrong module data\n");
1374         return;
1375     }
1376 #ifdef WITH_XSLT_DEBUG_FUNCTION
1377     xsltGenericDebug(xsltGenericDebugContext,
1378                      "libxslt:test() called with %d args\n", nargs);
1379 #endif
1380 }
1381
1382 /**
1383  * xsltExtElementPreCompTest:
1384  * @style:  the stylesheet
1385  * @inst:  the instruction in the stylesheet
1386  *
1387  * Process a libxslt:test node
1388  */
1389 static xsltElemPreCompPtr
1390 xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
1391                           xsltTransformFunction function) {
1392     xsltElemPreCompPtr ret;
1393
1394     if (style == NULL) {
1395         xsltTransformError(NULL, NULL, inst,
1396                  "xsltExtElementTest: no transformation context\n");
1397         return (NULL);
1398     }
1399     if (testStyleData == NULL) {
1400         xsltGenericDebug(xsltGenericDebugContext,
1401                  "xsltExtElementPreCompTest: not initialized,"
1402                  " calling xsltStyleGetExtData\n");
1403         xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
1404         if (testStyleData == NULL) {
1405             xsltTransformError(NULL, style, inst,
1406                  "xsltExtElementPreCompTest: not initialized\n");
1407             if (style != NULL) style->errors++;
1408             return (NULL);
1409         }
1410     }
1411     if (inst == NULL) {
1412         xsltTransformError(NULL, style, inst,
1413                  "xsltExtElementPreCompTest: no instruction\n");
1414         if (style != NULL) style->errors++;
1415         return (NULL);
1416     }
1417     ret = xsltNewElemPreComp (style, inst, function);
1418     return (ret);
1419 }
1420
1421 /**
1422  * xsltExtElementTest:
1423  * @ctxt:  an XSLT processing context
1424  * @node:  The current node
1425  * @inst:  the instruction in the stylesheet
1426  * @comp:  precomputed informations
1427  *
1428  * Process a libxslt:test node
1429  */
1430 static void
1431 xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
1432                    xmlNodePtr inst,
1433                    xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
1434 {
1435     xmlNodePtr commentNode;
1436
1437     if (testData == NULL) {
1438         xsltGenericDebug(xsltGenericDebugContext,
1439                          "xsltExtElementTest: not initialized,"
1440                          " calling xsltGetExtData\n");
1441         xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1442         if (testData == NULL) {
1443             xsltTransformError(ctxt, NULL, inst,
1444                              "xsltExtElementTest: not initialized\n");
1445             return;
1446         }
1447     }
1448     if (ctxt == NULL) {
1449         xsltTransformError(ctxt, NULL, inst,
1450                          "xsltExtElementTest: no transformation context\n");
1451         return;
1452     }
1453     if (node == NULL) {
1454         xsltTransformError(ctxt, NULL, inst,
1455                          "xsltExtElementTest: no current node\n");
1456         return;
1457     }
1458     if (inst == NULL) {
1459         xsltTransformError(ctxt, NULL, inst,
1460                          "xsltExtElementTest: no instruction\n");
1461         return;
1462     }
1463     if (ctxt->insert == NULL) {
1464         xsltTransformError(ctxt, NULL, inst,
1465                          "xsltExtElementTest: no insertion point\n");
1466         return;
1467     }
1468     commentNode =
1469         xmlNewComment((const xmlChar *)
1470                       "libxslt:test element test worked");
1471     xmlAddChild(ctxt->insert, commentNode);
1472 }
1473
1474 /**
1475  * xsltExtInitTest:
1476  * @ctxt:  an XSLT transformation context
1477  * @URI:  the namespace URI for the extension
1478  *
1479  * A function called at initialization time of an XSLT extension module
1480  *
1481  * Returns a pointer to the module specific data for this transformation
1482  */
1483 static void *
1484 xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) {
1485     if (testStyleData == NULL) {
1486         xsltGenericDebug(xsltGenericErrorContext,
1487                          "xsltExtInitTest: not initialized,"
1488                          " calling xsltStyleGetExtData\n");
1489         xsltStyleGetExtData(ctxt->style, URI);
1490         if (testStyleData == NULL) {
1491             xsltTransformError(ctxt, NULL, NULL,
1492                              "xsltExtInitTest: not initialized\n");
1493             return (NULL);
1494         }
1495     }   
1496     if (testData != NULL) {
1497         xsltTransformError(ctxt, NULL, NULL,
1498                          "xsltExtInitTest: already initialized\n");
1499         return (NULL);
1500     }
1501     testData = (void *) "test data";
1502     xsltGenericDebug(xsltGenericDebugContext,
1503                      "Registered test module : %s\n", URI);
1504     return (testData);
1505 }
1506
1507
1508 /**
1509  * xsltExtShutdownTest:
1510  * @ctxt:  an XSLT transformation context
1511  * @URI:  the namespace URI for the extension
1512  * @data:  the data associated to this module
1513  *
1514  * A function called at shutdown time of an XSLT extension module
1515  */
1516 static void
1517 xsltExtShutdownTest(xsltTransformContextPtr ctxt,
1518                     const xmlChar * URI, void *data) {
1519     if (testData == NULL) {
1520         xsltTransformError(ctxt, NULL, NULL,
1521                          "xsltExtShutdownTest: not initialized\n");
1522         return;
1523     }
1524     if (data != testData) {
1525         xsltTransformError(ctxt, NULL, NULL,
1526                          "xsltExtShutdownTest: wrong data\n");
1527     }
1528     testData = NULL;
1529     xsltGenericDebug(xsltGenericDebugContext,
1530                      "Unregistered test module : %s\n", URI);
1531 }
1532 /**
1533  * xsltExtStyleInitTest:
1534  * @style:  an XSLT stylesheet
1535  * @URI:  the namespace URI for the extension
1536  *
1537  * A function called at initialization time of an XSLT extension module
1538  *
1539  * Returns a pointer to the module specific data for this transformation
1540  */
1541 static void *
1542 xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
1543                      const xmlChar * URI)
1544 {
1545     if (testStyleData != NULL) {
1546         xsltTransformError(NULL, NULL, NULL,
1547                          "xsltExtInitTest: already initialized\n");
1548         return (NULL);
1549     }
1550     testStyleData = (void *) "test data";
1551     xsltGenericDebug(xsltGenericDebugContext,
1552                      "Registered test module : %s\n", URI);
1553     return (testStyleData);
1554 }
1555
1556
1557 /**
1558  * xsltExtStyleShutdownTest:
1559  * @style:  an XSLT stylesheet
1560  * @URI:  the namespace URI for the extension
1561  * @data:  the data associated to this module
1562  *
1563  * A function called at shutdown time of an XSLT extension module
1564  */
1565 static void
1566 xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
1567                          const xmlChar * URI, void *data) {
1568     if (testStyleData == NULL) {
1569         xsltGenericError(xsltGenericErrorContext,
1570                          "xsltExtShutdownTest: not initialized\n");
1571         return;
1572     }
1573     if (data != testStyleData) {
1574         xsltTransformError(NULL, NULL, NULL,
1575                          "xsltExtShutdownTest: wrong data\n");
1576     }
1577     testStyleData = NULL;
1578     xsltGenericDebug(xsltGenericDebugContext,
1579                      "Unregistered test module : %s\n", URI);
1580 }
1581
1582 /**
1583  * xsltRegisterTestModule:
1584  *
1585  * Registers the test module
1586  */
1587 void
1588 xsltRegisterTestModule (void) {
1589     xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
1590                               xsltExtInitTest, xsltExtShutdownTest,
1591                               xsltExtStyleInitTest,
1592                               xsltExtStyleShutdownTest);
1593     xsltRegisterExtModuleFunction((const xmlChar *) "test",
1594                             (const xmlChar *) XSLT_DEFAULT_URL,
1595                             xsltExtFunctionTest);
1596     xsltRegisterExtModuleElement((const xmlChar *) "test",
1597                                  (const xmlChar *) XSLT_DEFAULT_URL,
1598                                  xsltExtElementPreCompTest ,
1599                                  xsltExtElementTest);
1600 }
1601
1602 /**
1603  * xsltCleanupGlobals:
1604  *
1605  * Unregister all global variables set up by the XSLT library
1606  */
1607 void
1608 xsltCleanupGlobals(void)
1609 {
1610     xsltUnregisterAllExtModules();
1611     xsltUnregisterAllExtModuleFunction();
1612     xsltUnregisterAllExtModuleElement();
1613     xsltUnregisterAllExtModuleTopLevel();
1614 }
1615
1616 static void
1617 xsltDebugDumpExtensionsCallback(void* function ATTRIBUTE_UNUSED,
1618                                 FILE *output, const xmlChar* name,
1619                                 const xmlChar* URI,
1620                                 const xmlChar* not_used ATTRIBUTE_UNUSED) {
1621         if (!name||!URI)
1622                 return;
1623         fprintf(output,"{%s}%s\n",URI,name);
1624 }
1625
1626 /**
1627  * xsltDebugDumpExtensions:
1628  * @output:  the FILE * for the output, if NULL stdout is used
1629  *
1630  * Dumps a list of the registered XSLT extension functions and elements
1631  */
1632 void
1633 xsltDebugDumpExtensions(FILE * output)
1634 {
1635         if (output == NULL)
1636                 output = stdout;
1637     fprintf(output,"Registered XSLT Extensions\n--------------------------\n");
1638         if (!xsltFunctionsHash)
1639                 fprintf(output,"No registered extension functions\n");
1640         else {
1641                 fprintf(output,"Registered Extension Functions:\n");
1642                 xmlHashScanFull(xsltFunctionsHash,(xmlHashScannerFull)xsltDebugDumpExtensionsCallback,output);
1643         }
1644         if (!xsltElementsHash)
1645                 fprintf(output,"\nNo registered extension elements\n");
1646         else {
1647                 fprintf(output,"\nRegistered Extension Elements:\n");
1648                 xmlHashScanFull(xsltElementsHash,(xmlHashScannerFull)xsltDebugDumpExtensionsCallback,output);
1649         }
1650
1651 }
1652