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