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