fixed bug 119699 (missing error on shadowed variable) removed dependency
[platform/upstream/libxslt.git] / libxslt / variables.c
1 /*
2  * variables.c: Implementation of the variable storage and lookup
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/valid.h>
20 #include <libxml/hash.h>
21 #include <libxml/xmlerror.h>
22 #include <libxml/xpath.h>
23 #include <libxml/xpathInternals.h>
24 #include <libxml/parserInternals.h>
25 #include "xslt.h"
26 #include "xsltInternals.h"
27 #include "xsltutils.h"
28 #include "variables.h"
29 #include "transform.h"
30 #include "imports.h"
31 #include "preproc.h"
32
33 #ifdef WITH_XSLT_DEBUG
34 #define WITH_XSLT_DEBUG_VARIABLE
35 #endif
36
37 /************************************************************************
38  *                                                                      *
39  *                      Result Value Tree interfaces                    *
40  *                                                                      *
41  ************************************************************************/
42 /**
43  * xsltCreateRVT:
44  * @ctxt:  an XSLT transformation context
45  *
46  * Create a result value tree
47  *
48  * Returns the result value tree or NULL in case of error
49  */
50 xmlDocPtr
51 xsltCreateRVT(xsltTransformContextPtr ctxt)
52 {
53     xmlDocPtr container;
54
55     if (ctxt == NULL) return(NULL);
56
57     container = xmlNewDoc(NULL);
58     if (container == NULL)
59         return(NULL);
60
61     container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
62     container->doc = container;
63     container->parent = NULL;
64     return(container);
65 }
66
67 /**
68  * xsltRegisterTmpRVT:
69  * @ctxt:  an XSLT transformation context
70  * @RVT:  a result value tree
71  *
72  * Register the result value tree for destruction at the end of the context
73  *
74  * Returns 0 in case of success and -1 in case of error.
75  */
76 int
77 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
78 {
79     if ((ctxt == NULL) || (RVT == NULL)) return(-1);
80
81     RVT->next = (xmlNodePtr) ctxt->tmpRVT;
82     if (ctxt->tmpRVT != NULL)
83         ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
84     ctxt->tmpRVT = RVT;
85     return(0);
86 }
87
88 /**
89  * xsltRegisterPersistRVT:
90  * @ctxt:  an XSLT transformation context
91  * @RVT:  a result value tree
92  *
93  * Register the result value tree for destruction at the end of the processing
94  *
95  * Returns 0 in case of success and -1 in case of error.
96  */
97 int
98 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
99 {
100     if ((ctxt == NULL) || (RVT == NULL)) return(-1);
101
102     RVT->next = (xmlNodePtr) ctxt->persistRVT;
103     if (ctxt->persistRVT != NULL)
104         ctxt->persistRVT->prev = (xmlNodePtr) RVT;
105     ctxt->persistRVT = RVT;
106     return(0);
107 }
108
109 /**
110  * xsltFreeRVTs:
111  * @ctxt:  an XSLT transformation context
112  *
113  * Free all the registered result value tree of the transformation
114  */
115 void
116 xsltFreeRVTs(xsltTransformContextPtr ctxt)
117 {
118     xmlDocPtr cur, next;
119
120     if (ctxt == NULL) return;
121
122     cur = ctxt->tmpRVT;
123     while (cur != NULL) {
124         next = (xmlDocPtr) cur->next;
125         xmlFreeDoc(cur);
126         cur = next;
127     }
128     cur = ctxt->persistRVT;
129     while (cur != NULL) {
130         next = (xmlDocPtr) cur->next;
131         xmlFreeDoc(cur);
132         cur = next;
133     }
134 }
135
136 /************************************************************************
137  *                                                                      *
138  *                      Module interfaces                               *
139  *                                                                      *
140  ************************************************************************/
141
142 /**
143  * xsltNewStackElem:
144  *
145  * Create a new XSLT ParserContext
146  *
147  * Returns the newly allocated xsltParserStackElem or NULL in case of error
148  */
149 static xsltStackElemPtr
150 xsltNewStackElem(void) {
151     xsltStackElemPtr cur;
152
153     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
154     if (cur == NULL) {
155         xsltTransformError(NULL, NULL, NULL,
156                 "xsltNewStackElem : malloc failed\n");
157         return(NULL);
158     }
159     cur->computed = 0;
160     cur->name = NULL;
161     cur->nameURI = NULL;
162     cur->select = NULL;
163     cur->tree = NULL;
164     cur->value = NULL;
165     cur->comp = NULL;
166     return(cur);
167 }
168
169 /**
170  * xsltCopyStackElem:
171  * @elem:  an XSLT stack element
172  *
173  * Makes a copy of the stack element
174  *
175  * Returns the copy of NULL
176  */
177 static xsltStackElemPtr
178 xsltCopyStackElem(xsltStackElemPtr elem) {
179     xsltStackElemPtr cur;
180
181     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
182     if (cur == NULL) {
183         xsltTransformError(NULL, NULL, NULL,
184                 "xsltCopyStackElem : malloc failed\n");
185         return(NULL);
186     }
187     cur->name = xmlStrdup(elem->name);
188     cur->nameURI = xmlStrdup(elem->nameURI);
189     cur->select = xmlStrdup(elem->select);
190     cur->tree = elem->tree;
191     cur->comp = elem->comp;
192     cur->computed = 0;
193     cur->value = NULL;
194     return(cur);
195 }
196
197 /**
198  * xsltFreeStackElem:
199  * @elem:  an XSLT stack element
200  *
201  * Free up the memory allocated by @elem
202  */
203 static void
204 xsltFreeStackElem(xsltStackElemPtr elem) {
205     if (elem == NULL)
206         return;
207     if (elem->name != NULL)
208         xmlFree(elem->name);
209     if (elem->nameURI != NULL)
210         xmlFree(elem->nameURI);
211     if (elem->select != NULL)
212         xmlFree(elem->select);
213     if (elem->value != NULL)
214         xmlXPathFreeObject(elem->value);
215
216     xmlFree(elem);
217 }
218
219 /**
220  * xsltFreeStackElemList:
221  * @elem:  an XSLT stack element
222  *
223  * Free up the memory allocated by @elem
224  */
225 void
226 xsltFreeStackElemList(xsltStackElemPtr elem) {
227     xsltStackElemPtr next;
228
229     while(elem != NULL) {
230         next = elem->next;
231         xsltFreeStackElem(elem);
232         elem = next;
233     }
234 }
235
236 /**
237  * xsltStackLookup:
238  * @ctxt:  an XSLT transformation context
239  * @name:  the local part of the name
240  * @nameURI:  the URI part of the name
241  *
242  * Locate an element in the stack based on its name.
243  */
244 static xsltStackElemPtr
245 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
246                 const xmlChar *nameURI) {
247     xsltStackElemPtr ret = NULL;
248     int i;
249     xsltStackElemPtr cur;
250
251     if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
252         return(NULL);
253
254     /*
255      * Do the lookup from the top of the stack, but
256      * don't use params being computed in a call-param
257      */
258     ;
259
260     for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
261         cur = ctxt->varsTab[i-1];
262         while (cur != NULL) {
263             if (xmlStrEqual(cur->name, name)) {
264                 if (nameURI == NULL) {
265                     if (cur->nameURI == NULL) {
266                         return(cur);
267                     }
268                 } else {
269                     if ((cur->nameURI != NULL) &&
270                         (xmlStrEqual(cur->nameURI, nameURI))) {
271                         return(cur);
272                     }
273                 }
274
275             }
276             cur = cur->next;
277         }
278     }
279     return(ret);
280 }
281
282 /**
283  * xsltCheckStackElem:
284  * @ctxt:  xn XSLT transformation context
285  * @name:  the variable name
286  * @nameURI:  the variable namespace URI
287  *
288  * check wether the variable or param is already defined
289  *
290  * Returns 1 if variable is present, 2 if param is present, 3 if this
291  *         is an inherited param, 0 if not found, -1 in case of failure.
292  */
293 static int
294 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
295                    const xmlChar *nameURI) {
296     xsltStackElemPtr cur;
297
298     if ((ctxt == NULL) || (name == NULL))
299         return(-1);
300
301     cur = xsltStackLookup(ctxt, name, nameURI);
302     if (cur == NULL)
303         return(0);
304     if (cur->comp != NULL) {
305         if (cur->comp->type == XSLT_FUNC_WITHPARAM)
306             return(3);
307         else if (cur->comp->type == XSLT_FUNC_PARAM)
308             return(2);
309     }
310     
311     return(1);
312 }
313
314 /**
315  * xsltAddStackElem:
316  * @ctxt:  xn XSLT transformation context
317  * @elem:  a stack element
318  *
319  * add a new element at this level of the stack.
320  *
321  * Returns 0 in case of success, -1 in case of failure.
322  */
323 static int
324 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
325     if ((ctxt == NULL) || (elem == NULL))
326         return(-1);
327
328     elem->next = ctxt->varsTab[ctxt->varsNr - 1];
329     ctxt->varsTab[ctxt->varsNr - 1] = elem;
330     ctxt->vars = elem;
331     return(0);
332 }
333
334 /**
335  * xsltAddStackElemList:
336  * @ctxt:  xn XSLT transformation context
337  * @elems:  a stack element list
338  *
339  * add the new element list at this level of the stack.
340  *
341  * Returns 0 in case of success, -1 in case of failure.
342  */
343 int
344 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
345     xsltStackElemPtr cur;
346
347     if ((ctxt == NULL) || (elems == NULL))
348         return(-1);
349
350     /* TODO: check doublons */
351     if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
352         cur = ctxt->varsTab[ctxt->varsNr - 1];
353         while (cur->next != NULL)
354             cur = cur->next;
355         cur->next = elems;
356     } else {
357         elems->next = ctxt->varsTab[ctxt->varsNr - 1];
358         ctxt->varsTab[ctxt->varsNr - 1] = elems;
359         ctxt->vars = elems;
360     }
361     return(0);
362 }
363
364 /************************************************************************
365  *                                                                      *
366  *                      Module interfaces                               *
367  *                                                                      *
368  ************************************************************************/
369
370 /**
371  * xsltEvalVariable:
372  * @ctxt:  the XSLT transformation context
373  * @elem:  the variable or parameter.
374  * @precomp: pointer to precompiled data
375  *
376  * Evaluate a variable value.
377  *
378  * Returns the XPath Object value or NULL in case of error
379  */
380 static xmlXPathObjectPtr
381 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
382                  xsltStylePreCompPtr precomp) {
383     xmlXPathObjectPtr result = NULL;
384     int oldProximityPosition, oldContextSize;
385     xmlNodePtr oldInst, oldNode;
386     xsltDocumentPtr oldDoc;
387     int oldNsNr;
388     xmlNsPtr *oldNamespaces;
389
390     if ((ctxt == NULL) || (elem == NULL))
391         return(NULL);
392
393 #ifdef WITH_XSLT_DEBUG_VARIABLE
394     xsltGenericDebug(xsltGenericDebugContext,
395         "Evaluating variable %s\n", elem->name);
396 #endif
397     if (elem->select != NULL) {
398         xmlXPathCompExprPtr comp = NULL;
399
400         if ((precomp != NULL) && (precomp->comp != NULL)) {
401             comp = precomp->comp;
402         } else {
403             comp = xmlXPathCompile(elem->select);
404         }
405         if (comp == NULL)
406             return(NULL);
407         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
408         oldContextSize = ctxt->xpathCtxt->contextSize;
409         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
410         oldDoc = ctxt->document;
411         oldNode = ctxt->node;
412         oldInst = ctxt->inst;
413         oldNsNr = ctxt->xpathCtxt->nsNr;
414         oldNamespaces = ctxt->xpathCtxt->namespaces;
415         if (precomp != NULL) {
416             ctxt->inst = precomp->inst;
417             ctxt->xpathCtxt->namespaces = precomp->nsList;
418             ctxt->xpathCtxt->nsNr = precomp->nsNr;
419         } else {
420             ctxt->inst = NULL;
421             ctxt->xpathCtxt->namespaces = NULL;
422             ctxt->xpathCtxt->nsNr = 0;
423         }
424         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
425         ctxt->xpathCtxt->contextSize = oldContextSize;
426         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
427         ctxt->xpathCtxt->nsNr = oldNsNr;
428         ctxt->xpathCtxt->namespaces = oldNamespaces;
429         ctxt->inst = oldInst;
430         ctxt->node = oldNode;
431         ctxt->document = oldDoc;
432         if ((precomp == NULL) || (precomp->comp == NULL))
433             xmlXPathFreeCompExpr(comp);
434         if (result == NULL) {
435             xsltTransformError(ctxt, NULL, precomp->inst,
436                 "Evaluating variable %s failed\n", elem->name);
437             ctxt->state = XSLT_STATE_STOPPED;
438 #ifdef WITH_XSLT_DEBUG_VARIABLE
439 #ifdef LIBXML_DEBUG_ENABLED
440         } else {
441             if ((xsltGenericDebugContext == stdout) ||
442                 (xsltGenericDebugContext == stderr))
443                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
444                                         result, 0);
445 #endif
446 #endif
447         }
448     } else {
449         if (elem->tree == NULL) {
450             result = xmlXPathNewCString("");
451         } else {
452             /*
453              * This is a result tree fragment.
454              */
455             xmlDocPtr container;
456             xmlNodePtr oldInsert;
457             xmlDocPtr  oldoutput;
458
459             container = xsltCreateRVT(ctxt);
460             if (container == NULL)
461                 return(NULL);
462             /*
463              * Tag the subtree for removal once consumed
464              */
465             xsltRegisterTmpRVT(ctxt, container);
466             oldoutput = ctxt->output;
467             ctxt->output = container;
468             oldInsert = ctxt->insert;
469             ctxt->insert = (xmlNodePtr) container;
470             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
471             ctxt->insert = oldInsert;
472             ctxt->output = oldoutput;
473
474             result = xmlXPathNewValueTree((xmlNodePtr) container);
475             if (result == NULL) {
476                 result = xmlXPathNewCString("");
477             } else {
478                 result->boolval = 0; /* Freeing is not handled there anymore */
479             }
480 #ifdef WITH_XSLT_DEBUG_VARIABLE
481 #ifdef LIBXML_DEBUG_ENABLED
482             if ((xsltGenericDebugContext == stdout) ||
483                 (xsltGenericDebugContext == stderr))
484                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
485                                         result, 0);
486 #endif
487 #endif
488         }
489     }
490     return(result);
491 }
492
493 /**
494  * xsltEvalGlobalVariable:
495  * @elem:  the variable or parameter.
496  * @ctxt:  the XSLT transformation context
497  *
498  * Evaluate a global variable value.
499  *
500  * Returns the XPath Object value or NULL in case of error
501  */
502 static xmlXPathObjectPtr
503 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
504     xmlXPathObjectPtr result = NULL;
505     xsltStylePreCompPtr precomp;
506     int oldProximityPosition, oldContextSize;
507     xmlNodePtr oldInst;
508     int oldNsNr;
509     xmlNsPtr *oldNamespaces;
510     xmlChar *name;
511
512     if ((ctxt == NULL) || (elem == NULL))
513         return(NULL);
514     if (elem->computed)
515         return(elem->value);
516
517
518 #ifdef WITH_XSLT_DEBUG_VARIABLE
519     xsltGenericDebug(xsltGenericDebugContext,
520         "Evaluating global variable %s\n", elem->name);
521 #endif
522
523 #ifdef WITH_DEBUGGER
524     if ((xslDebugStatus != XSLT_DEBUG_NONE) &&
525         elem->comp && elem->comp->inst)
526         xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
527 #endif
528
529     name = elem->name;
530     elem->name = BAD_CAST "  being computed ... ";
531
532     precomp = elem->comp;
533     if (elem->select != NULL) {
534         xmlXPathCompExprPtr comp = NULL;
535
536         if ((precomp != NULL) && (precomp->comp != NULL)) {
537             comp = precomp->comp;
538         } else {
539             comp = xmlXPathCompile(elem->select);
540         }
541         if (comp == NULL) {
542             elem->name = name;
543             return(NULL);
544         }
545         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
546         oldContextSize = ctxt->xpathCtxt->contextSize;
547         oldInst = ctxt->inst;
548         oldNsNr = ctxt->xpathCtxt->nsNr;
549         oldNamespaces = ctxt->xpathCtxt->namespaces;
550         if (precomp != NULL) {
551             ctxt->inst = precomp->inst;
552             ctxt->xpathCtxt->namespaces = precomp->nsList;
553             ctxt->xpathCtxt->nsNr = precomp->nsNr;
554         } else {
555             ctxt->inst = NULL;
556             ctxt->xpathCtxt->namespaces = NULL;
557             ctxt->xpathCtxt->nsNr = 0;
558         }
559         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
560         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
561         ctxt->xpathCtxt->contextSize = oldContextSize;
562         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
563         ctxt->inst = oldInst;
564         ctxt->xpathCtxt->nsNr = oldNsNr;
565         ctxt->xpathCtxt->namespaces = oldNamespaces;
566         if ((precomp == NULL) || (precomp->comp == NULL))
567             xmlXPathFreeCompExpr(comp);
568         if (result == NULL) {
569             xsltTransformError(ctxt, NULL, precomp->inst,
570                 "Evaluating global variable %s failed\n", elem->name);
571             ctxt->state = XSLT_STATE_STOPPED;
572 #ifdef WITH_XSLT_DEBUG_VARIABLE
573 #ifdef LIBXML_DEBUG_ENABLED
574         } else {
575             if ((xsltGenericDebugContext == stdout) ||
576                 (xsltGenericDebugContext == stderr))
577                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
578                                         result, 0);
579 #endif
580 #endif
581         }
582     } else {
583         if (elem->tree == NULL) {
584             result = xmlXPathNewCString("");
585         } else {
586             /*
587              * This is a result tree fragment.
588              */
589             xmlDocPtr container;
590             xmlNodePtr oldInsert;
591             xmlDocPtr  oldoutput;
592
593             container = xsltCreateRVT(ctxt);
594             if (container == NULL)
595                 return(NULL);
596             /*
597              * Tag the subtree for removal once consumed
598              */
599             xsltRegisterTmpRVT(ctxt, container);
600             /*
601              * Save a pointer to the global variable for later cleanup
602              */
603             container->_private = elem;
604             oldoutput = ctxt->output;
605             ctxt->output = container;
606             oldInsert = ctxt->insert;
607             ctxt->insert = (xmlNodePtr) container;
608             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
609             ctxt->insert = oldInsert;
610             ctxt->output = oldoutput;
611
612             result = xmlXPathNewValueTree((xmlNodePtr) container);
613             if (result == NULL) {
614                 result = xmlXPathNewCString("");
615             } else {
616                 result->boolval = 0; /* Freeing is not handled there anymore */
617             }
618 #ifdef WITH_XSLT_DEBUG_VARIABLE
619 #ifdef LIBXML_DEBUG_ENABLED
620             if ((xsltGenericDebugContext == stdout) ||
621                 (xsltGenericDebugContext == stderr))
622                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
623                                         result, 0);
624 #endif
625 #endif
626         }
627     }
628     if (result != NULL) {
629         elem->value = result;
630         elem->computed = 1;
631     }
632     elem->name = name;
633     return(result);
634 }
635
636 /**
637  * xsltEvalGlobalVariables:
638  * @ctxt:  the XSLT transformation context
639  *
640  * Evaluate the global variables of a stylesheet. This need to be
641  * done on parsed stylesheets before starting to apply transformations
642  *
643  * Returns 0 in case of success, -1 in case of error
644  */
645 int
646 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
647     xsltStackElemPtr elem;
648     xsltStylesheetPtr style;
649
650     if ((ctxt == NULL) || (ctxt->document == NULL))
651         return(-1);
652  
653 #ifdef WITH_XSLT_DEBUG_VARIABLE
654     xsltGenericDebug(xsltGenericDebugContext,
655         "Registering global variables\n");
656 #endif
657
658     ctxt->node = (xmlNodePtr) ctxt->document->doc;
659     ctxt->xpathCtxt->contextSize = 1;
660     ctxt->xpathCtxt->proximityPosition = 1;
661
662     /*
663      * Walk the list from the stylesheets and populate the hash table
664      */
665     style = ctxt->style;
666     while (style != NULL) {
667         elem = style->variables;
668         
669 #ifdef WITH_XSLT_DEBUG_VARIABLE
670         if ((style->doc != NULL) && (style->doc->URL != NULL)) {
671             xsltGenericDebug(xsltGenericDebugContext,
672                              "Registering global variables from %s\n",
673                              style->doc->URL);
674         }
675 #endif
676
677         while (elem != NULL) {
678             xsltStackElemPtr def;
679
680             /*
681              * Global variables are stored in the variables pool.
682              */
683             def = (xsltStackElemPtr) 
684                     xmlHashLookup2(ctxt->globalVars,
685                                  elem->name, elem->nameURI);
686             if (def == NULL) {
687
688                 def = xsltCopyStackElem(elem);
689                 xmlHashAddEntry2(ctxt->globalVars,
690                                  elem->name, elem->nameURI, def);
691             } else if ((elem->comp != NULL) &&
692                        (elem->comp->type == XSLT_FUNC_VARIABLE)) {
693                 /*
694                  * Redefinition of variables from a different stylesheet
695                  * should not generate a message.
696                  */
697                 if ((elem->comp->inst != NULL) &&
698                     (def->comp != NULL) && (def->comp->inst != NULL) &&
699                     (elem->comp->inst->doc == def->comp->inst->doc)) {
700                     xsltTransformError(ctxt, style, elem->comp->inst,
701                         "Global variable %s already defined\n", elem->name);
702                     if (style != NULL) style->errors++;
703                 }
704             }
705             elem = elem->next;
706         }
707
708         style = xsltNextImport(style);
709     }
710
711     /*
712      * This part does the actual evaluation
713      */
714     ctxt->node = (xmlNodePtr) ctxt->document->doc;
715     ctxt->xpathCtxt->contextSize = 1;
716     ctxt->xpathCtxt->proximityPosition = 1;
717     xmlHashScan(ctxt->globalVars,
718                 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
719
720     return(0);
721 }
722
723 /**
724  * xsltRegisterGlobalVariable:
725  * @style:  the XSLT transformation context
726  * @name:  the variable name
727  * @ns_uri:  the variable namespace URI
728  * @select:  the expression which need to be evaluated to generate a value
729  * @tree:  the subtree if select is NULL
730  * @comp:  the precompiled value
731  * @value:  the string value if available
732  *
733  * Register a new variable value. If @value is NULL it unregisters
734  * the variable
735  *
736  * Returns 0 in case of success, -1 in case of error
737  */
738 static int
739 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
740                      const xmlChar *ns_uri, const xmlChar *select,
741                      xmlNodePtr tree, xsltStylePreCompPtr comp,
742                      const xmlChar *value) {
743     xsltStackElemPtr elem, tmp;
744     if (style == NULL)
745         return(-1);
746     if (name == NULL)
747         return(-1);
748     if (comp == NULL)
749         return(-1);
750
751 #ifdef WITH_XSLT_DEBUG_VARIABLE
752     if (comp->type == XSLT_FUNC_PARAM)
753         xsltGenericDebug(xsltGenericDebugContext,
754                          "Defining global param %s\n", name);
755     else
756         xsltGenericDebug(xsltGenericDebugContext,
757                          "Defining global variable %s\n", name);
758 #endif
759
760     elem = xsltNewStackElem();
761     if (elem == NULL)
762         return(-1);
763     elem->comp = comp;
764     elem->name = xmlStrdup(name);
765     elem->select = xmlStrdup(select);
766     if (ns_uri)
767         elem->nameURI = xmlStrdup(ns_uri);
768     elem->tree = tree;
769     tmp = style->variables;
770     if (tmp == NULL) {
771         elem->next = NULL;
772         style->variables = elem;
773     } else {
774         while (tmp != NULL) {
775             if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
776                 (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
777                 (xmlStrEqual(elem->name, tmp->name)) &&
778                 ((elem->nameURI == tmp->nameURI) ||
779                  (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
780                 xsltTransformError(NULL, style, comp->inst,
781                 "redefinition of global variable %s\n", elem->name);
782                 if (style != NULL) style->errors++;
783             }
784             if (tmp->next == NULL)
785                 break;
786             tmp = tmp->next;
787         }
788         elem->next = NULL;
789         tmp->next = elem;
790     }
791     if (value != NULL) {
792         elem->computed = 1;
793         elem->value = xmlXPathNewString(value);
794     }
795     return(0);
796 }
797
798 /**
799  * xsltProcessUserParamInternal
800  *
801  * @ctxt:  the XSLT transformation context
802  * @name:  a null terminated parameter name
803  * @value: a null terminated value (may be an XPath expression)
804  * @eval:  0 to treat the value literally, else evaluate as XPath expression
805  *
806  * If @eval is 0 then @value is treated literally and is stored in the global
807  * parameter/variable table without any change.
808  *
809  * Uf @eval is 1 then @value is treated as an XPath expression and is
810  * evaluated.  In this case, if you want to pass a string which will be
811  * interpreted literally then it must be enclosed in single or double quotes.
812  * If the string contains single quotes (double quotes) then it cannot be
813  * enclosed single quotes (double quotes).  If the string which you want to
814  * be treated literally contains both single and double quotes (e.g. Meet
815  * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
816  * quoting character.  You cannot use &apos; or &quot; inside the string
817  * because the replacement of character entities with their equivalents is
818  * done at a different stage of processing.  The solution is to call
819  * xsltQuoteUserParams or xsltQuoteOneUserParam.
820  *
821  * This needs to be done on parsed stylesheets before starting to apply
822  * transformations.  Normally this will be called (directly or indirectly)
823  * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
824  * or xsltQuoteOneUserParam.
825  *
826  * Returns 0 in case of success, -1 in case of error
827  */
828
829 static
830 int
831 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
832                              const xmlChar * name,
833                              const xmlChar * value,
834                              int eval) {
835
836     xsltStylesheetPtr style;
837     xmlChar *ncname;
838     xmlChar *prefix;
839     const xmlChar *href;
840     xmlXPathCompExprPtr comp;
841     xmlXPathObjectPtr result;
842     int oldProximityPosition;
843     int oldContextSize;
844     int oldNsNr;
845     xmlNsPtr *oldNamespaces;
846     xsltStackElemPtr elem;
847     int res;
848     void *res_ptr;
849
850     if (ctxt == NULL)
851         return(-1);
852     if (name == NULL)
853         return(0);
854     if (value == NULL)
855         return(0);
856
857     style = ctxt->style;
858
859 #ifdef WITH_XSLT_DEBUG_VARIABLE
860     xsltGenericDebug(xsltGenericDebugContext,
861             "Evaluating user parameter %s=%s\n", name, value);
862 #endif
863
864     /*
865      * Name lookup
866      */
867
868     ncname = xmlSplitQName2(name, &prefix);
869     href = NULL;
870     if (ncname != NULL) {
871         if (prefix != NULL) {
872             xmlNsPtr ns;
873
874             ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
875                              prefix);
876             if (ns == NULL) {
877                 xsltTransformError(ctxt, style, NULL,
878                 "user param : no namespace bound to prefix %s\n", prefix);
879                 href = NULL;
880             } else {
881                 href = ns->href;
882             }
883             xmlFree(prefix);
884             prefix = NULL;
885         } else {
886             href = NULL;
887         }
888         xmlFree(ncname);
889         ncname = NULL;
890     } else {
891         href = NULL;
892         ncname = xmlStrdup(name);
893     }
894
895     if (ncname == NULL)
896         return (-1);
897
898     res_ptr = xmlHashLookup2(ctxt->globalVars, ncname, href);
899     if (res_ptr != 0) {
900         xsltTransformError(ctxt, style, NULL,
901             "Global parameter %s already defined\n", ncname);
902     }
903
904     /*
905      * do not overwrite variables with parameters from the command line
906      */
907     while (style != NULL) {
908         elem = ctxt->style->variables;
909         while (elem != NULL) {
910             if ((elem->comp != NULL) &&
911                 (elem->comp->type == XSLT_FUNC_VARIABLE) &&
912                 (xmlStrEqual(elem->name, ncname)) &&
913                 (xmlStrEqual(elem->nameURI, href))) {
914                 xmlFree(ncname);
915                 return(0);
916             }
917             elem = elem->next;
918         }
919         style = xsltNextImport(style);
920     }
921     style = ctxt->style;
922     elem = NULL;
923
924     /*
925      * Do the evaluation if @eval is non-zero.
926      */
927
928     result = NULL;
929     if (eval != 0) {
930         comp = xmlXPathCompile(value);
931         if (comp != NULL) {
932             oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
933             oldContextSize = ctxt->xpathCtxt->contextSize;
934             ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
935
936             /* 
937              * There is really no in scope namespace for parameters on the
938              * command line.
939              */
940
941             oldNsNr = ctxt->xpathCtxt->nsNr;
942             oldNamespaces = ctxt->xpathCtxt->namespaces;
943             ctxt->xpathCtxt->namespaces = NULL;
944             ctxt->xpathCtxt->nsNr = 0;
945             result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
946             ctxt->xpathCtxt->contextSize = oldContextSize;
947             ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
948             ctxt->xpathCtxt->nsNr = oldNsNr;
949             ctxt->xpathCtxt->namespaces = oldNamespaces;
950             xmlXPathFreeCompExpr(comp);
951         }
952         if (result == NULL) {
953             xsltTransformError(ctxt, style, NULL,
954                 "Evaluating user parameter %s failed\n", name);
955             ctxt->state = XSLT_STATE_STOPPED;
956             xmlFree(ncname);
957             return(-1);
958         }
959     }
960
961     /* 
962      * If @eval is 0 then @value is to be taken literally and result is NULL
963      * 
964      * If @eval is not 0, then @value is an XPath expression and has been
965      * successfully evaluated and result contains the resulting value and
966      * is not NULL.
967      *
968      * Now create an xsltStackElemPtr for insertion into the context's
969      * global variable/parameter hash table.
970      */
971
972 #ifdef WITH_XSLT_DEBUG_VARIABLE
973 #ifdef LIBXML_DEBUG_ENABLED
974     if ((xsltGenericDebugContext == stdout) ||
975         (xsltGenericDebugContext == stderr))
976             xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
977                                     result, 0);
978 #endif
979 #endif
980
981     elem = xsltNewStackElem();
982     if (elem != NULL) {
983         elem->name = xmlStrdup(ncname);
984         if (value != NULL)
985             elem->select = xmlStrdup(value);
986         else
987             elem->select = NULL;
988         if (href)
989             elem->nameURI = xmlStrdup(href);
990         elem->tree = NULL;
991         elem->computed = 1;
992         if (eval == 0) {
993             elem->value = xmlXPathNewString(value);
994         } 
995         else {
996             elem->value = result;
997         }
998     }
999
1000     /*
1001      * Global parameters are stored in the XPath context variables pool.
1002      */
1003
1004     res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem);
1005     if (res != 0) {
1006         xsltFreeStackElem(elem);
1007         xsltTransformError(ctxt, style, NULL,
1008             "Global parameter %s already defined\n", ncname);
1009     }
1010     xmlFree(ncname);
1011     return(0);
1012 }
1013
1014 /**
1015  * xsltEvalUserParams:
1016  *
1017  * @ctxt:  the XSLT transformation context
1018  * @params:  a NULL terminated array of parameters name/value tuples
1019  *
1020  * Evaluate the global variables of a stylesheet. This needs to be
1021  * done on parsed stylesheets before starting to apply transformations.
1022  * Each of the parameters is evaluated as an XPath expression and stored
1023  * in the global variables/parameter hash table.  If you want your
1024  * parameter used literally, use xsltQuoteUserParams.
1025  *
1026  * Returns 0 in case of success, -1 in case of error
1027  */
1028  
1029 int
1030 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1031     int indx = 0;
1032     const xmlChar *name;
1033     const xmlChar *value;
1034
1035     if (params == NULL)
1036         return(0);
1037     while (params[indx] != NULL) {
1038         name = (const xmlChar *) params[indx++];
1039         value = (const xmlChar *) params[indx++];
1040         if (xsltEvalOneUserParam(ctxt, name, value) != 0) 
1041             return(-1);
1042     }
1043     return 0;
1044 }
1045
1046 /**
1047  * xsltQuoteUserParams:
1048  *
1049  * @ctxt:  the XSLT transformation context
1050  * @params:  a NULL terminated arry of parameters names/values tuples
1051  *
1052  * Similar to xsltEvalUserParams, but the values are treated literally and
1053  * are * *not* evaluated as XPath expressions. This should be done on parsed
1054  * stylesheets before starting to apply transformations.
1055  *
1056  * Returns 0 in case of success, -1 in case of error.
1057  */
1058  
1059 int
1060 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1061     int indx = 0;
1062     const xmlChar *name;
1063     const xmlChar *value;
1064
1065     if (params == NULL)
1066         return(0);
1067     while (params[indx] != NULL) {
1068         name = (const xmlChar *) params[indx++];
1069         value = (const xmlChar *) params[indx++];
1070         if (xsltQuoteOneUserParam(ctxt, name, value) != 0) 
1071             return(-1);
1072     }
1073     return 0;
1074 }
1075
1076 /**
1077  * xsltEvalOneUserParam:
1078  * @ctxt:  the XSLT transformation context
1079  * @name:  a null terminated string giving the name of the parameter
1080  * @value:  a null terminated string giving the XPath expression to be evaluated
1081  *
1082  * This is normally called from xsltEvalUserParams to process a single
1083  * parameter from a list of parameters.  The @value is evaluated as an
1084  * XPath expression and the result is stored in the context's global
1085  * variable/parameter hash table.
1086  *
1087  * To have a parameter treated literally (not as an XPath expression)
1088  * use xsltQuoteUserParams (or xsltQuoteOneUserParam).  For more
1089  * details see description of xsltProcessOneUserParamInternal.
1090  *
1091  * Returns 0 in case of success, -1 in case of error.
1092  */
1093
1094 int
1095 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1096                      const xmlChar * name,
1097                      const xmlChar * value) {
1098     return xsltProcessUserParamInternal(ctxt, name, value,
1099                                         1 /* xpath eval ? */);
1100 }
1101
1102 /**
1103  * xsltQuoteOneUserParam:
1104  * @ctxt:  the XSLT transformation context
1105  * @name:  a null terminated string giving the name of the parameter
1106  * @value:  a null terminated string giving the parameter value
1107  *
1108  * This is normally called from xsltQuoteUserParams to process a single
1109  * parameter from a list of parameters.  The @value is stored in the
1110  * context's global variable/parameter hash table.
1111  *
1112  * Returns 0 in case of success, -1 in case of error.
1113  */
1114
1115 int
1116 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1117                          const xmlChar * name,
1118                          const xmlChar * value) {
1119     return xsltProcessUserParamInternal(ctxt, name, value,
1120                                         0 /* xpath eval ? */);
1121 }
1122
1123 /**
1124  * xsltBuildVariable:
1125  * @ctxt:  the XSLT transformation context
1126  * @comp:  the precompiled form
1127  * @tree:  the tree if select is NULL
1128  *
1129  * Computes a new variable value.
1130  *
1131  * Returns the xsltStackElemPtr or NULL in case of error
1132  */
1133 static xsltStackElemPtr
1134 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1135                   xmlNodePtr tree) {
1136     xsltStackElemPtr elem;
1137
1138 #ifdef WITH_XSLT_DEBUG_VARIABLE
1139     xsltGenericDebug(xsltGenericDebugContext,
1140                      "Building variable %s", comp->name);
1141     if (comp->select != NULL)
1142         xsltGenericDebug(xsltGenericDebugContext,
1143                          " select %s", comp->select);
1144     xsltGenericDebug(xsltGenericDebugContext, "\n");
1145 #endif
1146
1147     elem = xsltNewStackElem();
1148     if (elem == NULL)
1149         return(NULL);
1150     elem->comp = comp;
1151     elem->name = xmlStrdup(comp->name);
1152     if (comp->select != NULL)
1153         elem->select = xmlStrdup(comp->select);
1154     else
1155         elem->select = NULL;
1156     if (comp->ns)
1157         elem->nameURI = xmlStrdup(comp->ns);
1158     elem->tree = tree;
1159     if (elem->computed == 0) {
1160         elem->value = xsltEvalVariable(ctxt, elem, comp);
1161         if (elem->value != NULL)
1162             elem->computed = 1;
1163     }
1164     return(elem);
1165 }
1166
1167 /**
1168  * xsltRegisterVariable:
1169  * @ctxt:  the XSLT transformation context
1170  * @comp:  pointer to precompiled data
1171  * @tree:  the tree if select is NULL
1172  * @param:  this is a parameter actually
1173  *
1174  * Computes and register a new variable value. 
1175  *
1176  * Returns 0 in case of success, -1 in case of error
1177  */
1178 static int
1179 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1180                      xmlNodePtr tree, int param) {
1181     xsltStackElemPtr elem;
1182     int present;
1183
1184     present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1185     if (param == 0) {
1186         if ((present != 0) && (present != 3)) {
1187             xsltTransformError(ctxt, NULL, comp->inst,
1188                 "xsl:variable : redefining %s\n", comp->name);
1189             return(0);
1190         }
1191     } else if (present != 0) {
1192         if ((present == 1) || (present == 2)) {
1193             xsltTransformError(ctxt, NULL, comp->inst,
1194                 "xsl:param : redefining %s\n", comp->name);
1195             return(0);
1196         }
1197 #ifdef WITH_XSLT_DEBUG_VARIABLE
1198         xsltGenericDebug(xsltGenericDebugContext,
1199                  "param %s defined by caller\n", comp->name);
1200 #endif
1201         return(0);
1202     }
1203     elem = xsltBuildVariable(ctxt, comp, tree);
1204     xsltAddStackElem(ctxt, elem);
1205     return(0);
1206 }
1207
1208 /**
1209  * xsltGlobalVariableLookup:
1210  * @ctxt:  the XSLT transformation context
1211  * @name:  the variable name
1212  * @ns_uri:  the variable namespace URI
1213  *
1214  * Search in the Variable array of the context for the given
1215  * variable value.
1216  *
1217  * Returns the value or NULL if not found
1218  */
1219 static xmlXPathObjectPtr
1220 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1221                          const xmlChar *ns_uri) {
1222     xsltStackElemPtr elem;
1223     xmlXPathObjectPtr ret = NULL;
1224
1225     /*
1226      * Lookup the global variables in XPath global variable hash table
1227      */
1228     if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1229         return(NULL);
1230     elem = (xsltStackElemPtr)
1231             xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1232     if (elem == NULL) {
1233 #ifdef WITH_XSLT_DEBUG_VARIABLE
1234         xsltGenericDebug(xsltGenericDebugContext,
1235                          "global variable not found %s\n", name);
1236 #endif
1237         return(NULL);
1238     }
1239     if (elem->computed == 0) {
1240         if (xmlStrEqual(elem->name, BAD_CAST "  being computed ... ")) {
1241             xsltTransformError(ctxt, NULL, elem->comp->inst,
1242                 "Recursive definition of %s\n", name);
1243             return(NULL);
1244         }
1245         ret = xsltEvalGlobalVariable(elem, ctxt);
1246     } else
1247         ret = elem->value;
1248     return(xmlXPathObjectCopy(ret));
1249 }
1250
1251 /**
1252  * xsltVariableLookup:
1253  * @ctxt:  the XSLT transformation context
1254  * @name:  the variable name
1255  * @ns_uri:  the variable namespace URI
1256  *
1257  * Search in the Variable array of the context for the given
1258  * variable value.
1259  *
1260  * Returns the value or NULL if not found
1261  */
1262 xmlXPathObjectPtr
1263 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1264                    const xmlChar *ns_uri) {
1265     xsltStackElemPtr elem;
1266
1267     if (ctxt == NULL)
1268         return(NULL);
1269
1270     elem = xsltStackLookup(ctxt, name, ns_uri);
1271     if (elem == NULL) {
1272         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1273     }
1274     if (elem->computed == 0) {
1275 #ifdef WITH_XSLT_DEBUG_VARIABLE
1276         xsltGenericDebug(xsltGenericDebugContext,
1277                          "uncomputed variable %s\n", name);
1278 #endif
1279         elem->value = xsltEvalVariable(ctxt, elem, NULL);
1280         elem->computed = 1;
1281     }
1282     if (elem->value != NULL)
1283         return(xmlXPathObjectCopy(elem->value));
1284 #ifdef WITH_XSLT_DEBUG_VARIABLE
1285     xsltGenericDebug(xsltGenericDebugContext,
1286                      "variable not found %s\n", name);
1287 #endif
1288     return(NULL);
1289 }
1290
1291 /**
1292  * xsltParseStylesheetCallerParam:
1293  * @ctxt:  the XSLT transformation context
1294  * @cur:  the "param" element
1295  *
1296  * parse an XSLT transformation param declaration, compute
1297  * its value but doesn't record it.
1298  *
1299  * Returns the new xsltStackElemPtr or NULL
1300  */
1301
1302 xsltStackElemPtr
1303 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1304     xmlNodePtr tree = NULL;
1305     xsltStackElemPtr elem = NULL;
1306     xsltStylePreCompPtr comp;
1307
1308     if ((cur == NULL) || (ctxt == NULL))
1309         return(NULL);
1310     comp = (xsltStylePreCompPtr) cur->_private;
1311     if (comp == NULL) {
1312         xsltTransformError(ctxt, NULL, cur,
1313             "xsl:param : compilation error\n");
1314         return(NULL);
1315     }
1316
1317     if (comp->name == NULL) {
1318         xsltTransformError(ctxt, NULL, cur,
1319             "xsl:param : missing name attribute\n");
1320         return(NULL);
1321     }
1322
1323 #ifdef WITH_XSLT_DEBUG_VARIABLE
1324     xsltGenericDebug(xsltGenericDebugContext,
1325             "Handling param %s\n", comp->name);
1326 #endif
1327
1328     if (comp->select == NULL) {
1329         tree = cur->children;
1330     } else {
1331 #ifdef WITH_XSLT_DEBUG_VARIABLE
1332         xsltGenericDebug(xsltGenericDebugContext,
1333             "        select %s\n", comp->select);
1334 #endif
1335         tree = cur;
1336     }
1337
1338     elem = xsltBuildVariable(ctxt, comp, tree);
1339
1340     return(elem);
1341 }
1342
1343 /**
1344  * xsltParseGlobalVariable:
1345  * @style:  the XSLT stylesheet
1346  * @cur:  the "variable" element
1347  *
1348  * parse an XSLT transformation variable declaration and record
1349  * its value.
1350  */
1351
1352 void
1353 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1354     xsltStylePreCompPtr comp;
1355
1356     if ((cur == NULL) || (style == NULL))
1357         return;
1358
1359     xsltStylePreCompute(style, cur);
1360     comp = (xsltStylePreCompPtr) cur->_private;
1361     if (comp == NULL) {
1362         xsltTransformError(NULL, style, cur,
1363              "xsl:variable : compilation failed\n");
1364         return;
1365     }
1366
1367     if (comp->name == NULL) {
1368         xsltTransformError(NULL, style, cur,
1369             "xsl:variable : missing name attribute\n");
1370         return;
1371     }
1372
1373 #ifdef WITH_XSLT_DEBUG_VARIABLE
1374     xsltGenericDebug(xsltGenericDebugContext,
1375         "Registering global variable %s\n", comp->name);
1376 #endif
1377
1378     xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1379                                cur->children, comp, NULL);
1380 }
1381
1382 /**
1383  * xsltParseGlobalParam:
1384  * @style:  the XSLT stylesheet
1385  * @cur:  the "param" element
1386  *
1387  * parse an XSLT transformation param declaration and record
1388  * its value.
1389  */
1390
1391 void
1392 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1393     xsltStylePreCompPtr comp;
1394
1395     if ((cur == NULL) || (style == NULL))
1396         return;
1397
1398     xsltStylePreCompute(style, cur);
1399     comp = (xsltStylePreCompPtr) cur->_private;
1400     if (comp == NULL) {
1401         xsltTransformError(NULL, style, cur,
1402              "xsl:param : compilation failed\n");
1403         return;
1404     }
1405
1406     if (comp->name == NULL) {
1407         xsltTransformError(NULL, style, cur,
1408             "xsl:param : missing name attribute\n");
1409         return;
1410     }
1411
1412 #ifdef WITH_XSLT_DEBUG_VARIABLE
1413     xsltGenericDebug(xsltGenericDebugContext,
1414         "Registering global param %s\n", comp->name);
1415 #endif
1416
1417     xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1418                                cur->children, comp, NULL);
1419 }
1420
1421 /**
1422  * xsltParseStylesheetVariable:
1423  * @ctxt:  the XSLT transformation context
1424  * @cur:  the "variable" element
1425  *
1426  * parse an XSLT transformation variable declaration and record
1427  * its value.
1428  */
1429
1430 void
1431 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1432     xsltStylePreCompPtr comp;
1433
1434     if ((cur == NULL) || (ctxt == NULL))
1435         return;
1436
1437     comp = (xsltStylePreCompPtr) cur->_private;
1438     if (comp == NULL) {
1439         xsltTransformError(ctxt, NULL, cur,
1440              "xsl:variable : compilation failed\n");
1441         return;
1442     }
1443
1444     if (comp->name == NULL) {
1445         xsltTransformError(ctxt, NULL, cur,
1446             "xsl:variable : missing name attribute\n");
1447         return;
1448     }
1449
1450 #ifdef WITH_XSLT_DEBUG_VARIABLE
1451     xsltGenericDebug(xsltGenericDebugContext,
1452         "Registering variable %s\n", comp->name);
1453 #endif
1454
1455     xsltRegisterVariable(ctxt, comp, cur->children, 0);
1456 }
1457
1458 /**
1459  * xsltParseStylesheetParam:
1460  * @ctxt:  the XSLT transformation context
1461  * @cur:  the "param" element
1462  *
1463  * parse an XSLT transformation param declaration and record
1464  * its value.
1465  */
1466
1467 void
1468 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1469     xsltStylePreCompPtr comp;
1470
1471     if ((cur == NULL) || (ctxt == NULL))
1472         return;
1473
1474     comp = (xsltStylePreCompPtr) cur->_private;
1475     if (comp == NULL) {
1476         xsltTransformError(ctxt, NULL, cur,
1477              "xsl:param : compilation failed\n");
1478         return;
1479     }
1480
1481     if (comp->name == NULL) {
1482         xsltTransformError(ctxt, NULL, cur,
1483             "xsl:param : missing name attribute\n");
1484         return;
1485     }
1486
1487 #ifdef WITH_XSLT_DEBUG_VARIABLE
1488     xsltGenericDebug(xsltGenericDebugContext,
1489         "Registering param %s\n", comp->name);
1490 #endif
1491
1492     xsltRegisterVariable(ctxt, comp, cur->children, 1);
1493 }
1494
1495 /**
1496  * xsltFreeGlobalVariables:
1497  * @ctxt:  the XSLT transformation context
1498  *
1499  * Free up the data associated to the global variables
1500  * its value.
1501  */
1502
1503 void
1504 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1505     xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1506 }
1507
1508 /**
1509  * xsltXPathVariableLookup:
1510  * @ctxt:  a void * but the the XSLT transformation context actually
1511  * @name:  the variable name
1512  * @ns_uri:  the variable namespace URI
1513  *
1514  * This is the entry point when a varibale is needed by the XPath
1515  * interpretor.
1516  *
1517  * Returns the value or NULL if not found
1518  */
1519 xmlXPathObjectPtr
1520 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1521                         const xmlChar *ns_uri) {
1522     xsltTransformContextPtr context;
1523     xmlXPathObjectPtr ret;
1524
1525     if ((ctxt == NULL) || (name == NULL))
1526         return(NULL);
1527
1528 #ifdef WITH_XSLT_DEBUG_VARIABLE
1529     xsltGenericDebug(xsltGenericDebugContext,
1530             "Lookup variable %s\n", name);
1531 #endif
1532     context = (xsltTransformContextPtr) ctxt;
1533     ret = xsltVariableLookup(context, name, ns_uri);
1534     if (ret == NULL) {
1535         xsltTransformError(ctxt, NULL, NULL,
1536             "unregistered variable %s\n", name);
1537     }
1538 #ifdef WITH_XSLT_DEBUG_VARIABLE
1539     if (ret != NULL)
1540         xsltGenericDebug(xsltGenericDebugContext,
1541             "found variable %s\n", name);
1542 #endif
1543     return(ret);
1544 }
1545
1546