- libxslt/variables.c: Mark Vakoc found a bug in variable eval
[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@imag.fr
10  */
11
12 #include "xsltconfig.h"
13
14 #include <string.h>
15
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/valid.h>
19 #include <libxml/hash.h>
20 #include <libxml/xmlerror.h>
21 #include <libxml/xpath.h>
22 #include <libxml/xpathInternals.h>
23 #include <libxml/parserInternals.h>
24 #include <libxml/xmlversion.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  *                      Module interfaces                               *
40  *                                                                      *
41  ************************************************************************/
42
43 /**
44  * xsltNewStackElem:
45  *
46  * Create a new XSLT ParserContext
47  *
48  * Returns the newly allocated xsltParserStackElem or NULL in case of error
49  */
50 static xsltStackElemPtr
51 xsltNewStackElem(void) {
52     xsltStackElemPtr cur;
53
54     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
55     if (cur == NULL) {
56         xsltGenericError(xsltGenericErrorContext,
57                 "xsltNewStackElem : malloc failed\n");
58         return(NULL);
59     }
60     cur->computed = 0;
61     cur->name = NULL;
62     cur->nameURI = NULL;
63     cur->select = NULL;
64     cur->tree = NULL;
65     cur->value = NULL;
66     cur->comp = NULL;
67     return(cur);
68 }
69
70 /**
71  * xsltCopyStackElem:
72  * @elem:  an XSLT stack element
73  *
74  * Makes a copy of the stack element
75  *
76  * Returns the copy of NULL
77  */
78 static xsltStackElemPtr
79 xsltCopyStackElem(xsltStackElemPtr elem) {
80     xsltStackElemPtr cur;
81
82     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
83     if (cur == NULL) {
84         xsltGenericError(xsltGenericErrorContext,
85                 "xsltNewStackElem : malloc failed\n");
86         return(NULL);
87     }
88     cur->name = xmlStrdup(elem->name);
89     cur->nameURI = xmlStrdup(elem->nameURI);
90     cur->select = xmlStrdup(elem->select);
91     cur->tree = elem->tree;
92     cur->comp = elem->comp;
93     cur->computed = 0;
94     cur->value = NULL;
95     return(cur);
96 }
97
98 /**
99  * xsltFreeStackElem:
100  * @elem:  an XSLT stack element
101  *
102  * Free up the memory allocated by @elem
103  */
104 static void
105 xsltFreeStackElem(xsltStackElemPtr elem) {
106     if (elem == NULL)
107         return;
108     if (elem->name != NULL)
109         xmlFree(elem->name);
110     if (elem->nameURI != NULL)
111         xmlFree(elem->nameURI);
112     if (elem->select != NULL)
113         xmlFree(elem->select);
114     if (elem->value != NULL)
115         xmlXPathFreeObject(elem->value);
116
117     xmlFree(elem);
118 }
119
120 /**
121  * xsltFreeStackElemList:
122  * @elem:  an XSLT stack element
123  *
124  * Free up the memory allocated by @elem
125  */
126 void
127 xsltFreeStackElemList(xsltStackElemPtr elem) {
128     xsltStackElemPtr next;
129
130     while(elem != NULL) {
131         next = elem->next;
132         xsltFreeStackElem(elem);
133         elem = next;
134     }
135 }
136
137 /**
138  * xsltCheckStackElem:
139  * @ctxt:  xn XSLT transformation context
140  * @name:  the variable name
141  * @nameURI:  the variable namespace URI
142  *
143  * check wether the variable or param is already defined
144  *
145  * Returns 1 if present, 0 if not, -1 in case of failure.
146  */
147 static int
148 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
149                    const xmlChar *nameURI) {
150     xsltStackElemPtr cur;
151
152     if ((ctxt == NULL) || (name == NULL))
153         return(-1);
154
155     cur = ctxt->vars;
156     while (cur != NULL) {
157         if (xmlStrEqual(name, cur->name)) {
158             if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
159                 ((nameURI != NULL) && (cur->nameURI != NULL) &&
160                  (xmlStrEqual(nameURI, cur->nameURI)))) {
161                 return(1);
162             }
163         }
164         cur = cur->next;
165     }
166     return(0);
167 }
168
169 /**
170  * xsltAddStackElem:
171  * @ctxt:  xn XSLT transformation context
172  * @elem:  a stack element
173  *
174  * add a new element at this level of the stack.
175  *
176  * Returns 0 in case of success, -1 in case of failure.
177  */
178 static int
179 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
180     if ((ctxt == NULL) || (elem == NULL))
181         return(-1);
182
183     elem->next = ctxt->varsTab[ctxt->varsNr - 1];
184     ctxt->varsTab[ctxt->varsNr - 1] = elem;
185     ctxt->vars = elem;
186     return(0);
187 }
188
189 /**
190  * xsltAddStackElemList:
191  * @ctxt:  xn XSLT transformation context
192  * @elems:  a stack element list
193  *
194  * add the new element list at this level of the stack.
195  *
196  * Returns 0 in case of success, -1 in case of failure.
197  */
198 int
199 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
200     xsltStackElemPtr cur;
201
202     if ((ctxt == NULL) || (elems == NULL))
203         return(-1);
204
205     /* TODO: check doublons */
206     if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
207         cur = ctxt->varsTab[ctxt->varsNr - 1];
208         while (cur->next != NULL)
209             cur = cur->next;
210         cur->next = elems;
211     } else {
212         elems->next = ctxt->varsTab[ctxt->varsNr - 1];
213         ctxt->varsTab[ctxt->varsNr - 1] = elems;
214         ctxt->vars = elems;
215     }
216     return(0);
217 }
218
219 /**
220  * xsltStackLookup:
221  * @ctxt:  an XSLT transformation context
222  * @name:  the local part of the name
223  * @nameURI:  the URI part of the name
224  *
225  * Locate an element in the stack based on its name.
226  */
227 static xsltStackElemPtr
228 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
229                 const xmlChar *nameURI) {
230     xsltStackElemPtr ret = NULL;
231     int i;
232     xsltStackElemPtr cur;
233
234     if ((ctxt == NULL) || (name == NULL))
235         return(NULL);
236
237     /*
238      * Do the lookup from the top of the stack, but
239      * don't use params being computed in a call-param
240      */
241     i = ctxt->varsNr - 1;
242
243     for (;i >= 0;i--) {
244         cur = ctxt->varsTab[i];
245         while (cur != NULL) {
246             if (xmlStrEqual(cur->name, name)) {
247                 if (nameURI == NULL) {
248                     if (cur->nameURI == NULL) {
249                         return(cur);
250                     }
251                 } else {
252                     if ((cur->nameURI != NULL) &&
253                         (xmlStrEqual(cur->nameURI, nameURI))) {
254                         return(cur);
255                     }
256                 }
257
258             }
259             cur = cur->next;
260         }
261     }
262     return(ret);
263 }
264
265 /************************************************************************
266  *                                                                      *
267  *                      Module interfaces                               *
268  *                                                                      *
269  ************************************************************************/
270
271 /**
272  * xsltEvalVariable:
273  * @ctxt:  the XSLT transformation context
274  * @elem:  the variable or parameter.
275  *
276  * Evaluate a variable value.
277  *
278  * Returns the XPath Object value or NULL in case of error
279  */
280 static xmlXPathObjectPtr
281 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
282                  xsltStylePreCompPtr precomp) {
283     xmlXPathObjectPtr result = NULL;
284     int oldProximityPosition, oldContextSize;
285     if ((ctxt == NULL) || (elem == NULL))
286         return(NULL);
287
288 #ifdef WITH_XSLT_DEBUG_VARIABLE
289     xsltGenericDebug(xsltGenericDebugContext,
290         "Evaluating variable %s\n", elem->name);
291 #endif
292     if (elem->select != NULL) {
293         xmlXPathCompExprPtr comp = NULL;
294
295         if ((precomp != NULL) && (precomp->comp != NULL)) {
296             comp = precomp->comp;
297         } else {
298             comp = xmlXPathCompile(elem->select);
299         }
300         if (comp == NULL)
301             return(NULL);
302         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
303         oldContextSize = ctxt->xpathCtxt->contextSize;
304         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
305         /* TODO: do we need to propagate the namespaces here ? */
306         ctxt->xpathCtxt->namespaces = NULL;
307         ctxt->xpathCtxt->nsNr = 0;
308         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
309         ctxt->xpathCtxt->contextSize = oldContextSize;
310         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
311         if ((precomp == NULL) || (precomp->comp == NULL))
312             xmlXPathFreeCompExpr(comp);
313         if (result == NULL) {
314             xsltGenericError(xsltGenericErrorContext,
315                 "Evaluating variable %s failed\n", elem->name);
316 #ifdef WITH_XSLT_DEBUG_VARIABLE
317 #ifdef LIBXML_DEBUG_ENABLED
318         } else {
319             if ((xsltGenericDebugContext == stdout) ||
320                 (xsltGenericDebugContext == stderr))
321                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
322                                         result, 0);
323 #endif
324 #endif
325         }
326     } else {
327         if (elem->tree == NULL) {
328             result = xmlXPathNewCString("");
329         } else {
330             /*
331              * This is a result tree fragment.
332              */
333             xmlNodePtr container;
334             xmlNodePtr oldInsert, oldNode;
335
336             container = xmlNewDocNode(ctxt->output, NULL,
337                                       (const xmlChar *) "fake", NULL);
338             if (container == NULL)
339                 return(NULL);
340
341             oldInsert = ctxt->insert;
342             oldNode = ctxt->node;
343             ctxt->insert = container;
344             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, 0);
345             ctxt->insert = oldInsert;
346             ctxt->node = oldNode;
347
348             result = xmlXPathNewValueTree(container);
349             if (result == NULL) {
350                 result = xmlXPathNewCString("");
351             }
352 #ifdef WITH_XSLT_DEBUG_VARIABLE
353 #ifdef LIBXML_DEBUG_ENABLED
354             if ((xsltGenericDebugContext == stdout) ||
355                 (xsltGenericDebugContext == stderr))
356                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
357                                         result, 0);
358 #endif
359 #endif
360         }
361     }
362     return(result);
363 }
364
365 /**
366  * xsltEvalGlobalVariable:
367  * @ctxt:  the XSLT transformation context
368  * @elem:  the variable or parameter.
369  *
370  * Evaluate a global variable value.
371  *
372  * Returns the XPath Object value or NULL in case of error
373  */
374 static xmlXPathObjectPtr
375 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
376     xmlXPathObjectPtr result = NULL;
377     xsltStylePreCompPtr precomp;
378     int oldProximityPosition, oldContextSize;
379     xmlNodePtr oldInst;
380
381     if ((ctxt == NULL) || (elem == NULL))
382         return(NULL);
383     if (elem->computed)
384         return(elem->value);
385
386
387 #ifdef WITH_XSLT_DEBUG_VARIABLE
388     xsltGenericDebug(xsltGenericDebugContext,
389         "Evaluating global variable %s\n", elem->name);
390 #endif
391
392     precomp = elem->comp;
393     if (elem->select != NULL) {
394         xmlXPathCompExprPtr comp = NULL;
395
396         if ((precomp != NULL) && (precomp->comp != NULL)) {
397             comp = precomp->comp;
398         } else {
399             comp = xmlXPathCompile(elem->select);
400         }
401         if (comp == NULL)
402             return(NULL);
403         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
404         oldContextSize = ctxt->xpathCtxt->contextSize;
405         oldInst = ctxt->inst;
406         if (precomp != NULL)
407             ctxt->inst = precomp->inst;
408         else
409             ctxt->inst = NULL;
410         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
411         /* TODO: do we need to propagate the namespaces here ? */
412         ctxt->xpathCtxt->namespaces = NULL;
413         ctxt->xpathCtxt->nsNr = 0;
414         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
415         ctxt->xpathCtxt->contextSize = oldContextSize;
416         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
417         ctxt->inst = oldInst;
418         if ((precomp == NULL) || (precomp->comp == NULL))
419             xmlXPathFreeCompExpr(comp);
420         if (result == NULL) {
421             xsltGenericError(xsltGenericErrorContext,
422                 "Evaluating global variable %s failed\n", elem->name);
423 #ifdef WITH_XSLT_DEBUG_VARIABLE
424 #ifdef LIBXML_DEBUG_ENABLED
425         } else {
426             if ((xsltGenericDebugContext == stdout) ||
427                 (xsltGenericDebugContext == stderr))
428                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
429                                         result, 0);
430 #endif
431 #endif
432         }
433     } else {
434         if (elem->tree == NULL) {
435             result = xmlXPathNewCString("");
436         } else {
437             /*
438              * This is a result tree fragment.
439              */
440             xmlNodePtr container;
441             xmlNodePtr oldInsert, oldNode;
442
443             container = xmlNewDocNode(ctxt->output, NULL,
444                                       (const xmlChar *) "fake", NULL);
445             if (container == NULL)
446                 return(NULL);
447
448             oldInsert = ctxt->insert;
449             oldNode = ctxt->node;
450             ctxt->insert = container;
451             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, 0);
452             ctxt->insert = oldInsert;
453             ctxt->node = oldNode;
454
455             result = xmlXPathNewValueTree(container);
456             if (result == NULL) {
457                 result = xmlXPathNewCString("");
458             }
459 #ifdef WITH_XSLT_DEBUG_VARIABLE
460 #ifdef LIBXML_DEBUG_ENABLED
461             if ((xsltGenericDebugContext == stdout) ||
462                 (xsltGenericDebugContext == stderr))
463                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
464                                         result, 0);
465 #endif
466 #endif
467         }
468     }
469     if (result != NULL) {
470         elem->value = result;
471         elem->computed = 1;
472     }
473     return(result);
474 }
475
476 /**
477  * xsltEvalGlobalVariables:
478  * @ctxt:  the XSLT transformation context
479  *
480  * Evaluate the global variables of a stylesheet. This need to be
481  * done on parsed stylesheets before starting to apply transformations
482  *
483  * Returns 0 in case of success, -1 in case of error
484  */
485 int
486 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
487     xsltStackElemPtr elem;
488     xsltStylesheetPtr style;
489
490     if (ctxt == NULL)
491         return(-1);
492  
493 #ifdef WITH_XSLT_DEBUG_VARIABLE
494     xsltGenericDebug(xsltGenericDebugContext,
495         "Registering global variables\n");
496 #endif
497     ctxt->node = (xmlNodePtr) ctxt->document->doc;
498     ctxt->xpathCtxt->contextSize = 1;
499     ctxt->xpathCtxt->proximityPosition = 1;
500
501     /*
502      * Walk the list from the stylesheets and populate the hash table
503      */
504     style = ctxt->style;
505     while (style != NULL) {
506         elem = style->variables;
507         
508 #ifdef WITH_XSLT_DEBUG_VARIABLE
509         if ((style->doc != NULL) && (style->doc->URL != NULL)) {
510
511             xsltGenericDebug(xsltGenericDebugContext,
512                 "Registering global variables from %s\n",
513                              style->doc->URL);
514         }
515 #endif
516         while (elem != NULL) {
517             xsltStackElemPtr def;
518
519             /*
520              * Global variables are stored in the variables pool.
521              */
522             def = (xsltStackElemPtr) 
523                     xmlHashLookup2(ctxt->globalVars,
524                                  elem->name, elem->nameURI);
525             if (def == NULL) {
526                 int res;
527
528                 def = xsltCopyStackElem(elem);
529                 res = xmlHashAddEntry2(ctxt->globalVars,
530                                  elem->name, elem->nameURI, def);
531             } else if ((elem->comp != NULL) &&
532                        (elem->comp->type == XSLT_FUNC_VARIABLE)) {
533                 xsltGenericError(xsltGenericErrorContext,
534                     "Global variable %s already defined\n", elem->name);
535             }
536             elem = elem->next;
537         }
538
539         style = xsltNextImport(style);
540     }
541
542     /*
543      * This part does the actual evaluation
544      */
545     ctxt->node = (xmlNodePtr) ctxt->document->doc;
546     ctxt->xpathCtxt->contextSize = 1;
547     ctxt->xpathCtxt->proximityPosition = 1;
548     xmlHashScan(ctxt->globalVars,
549                 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
550
551     return(0);
552 }
553
554 /**
555  * xsltRegisterGlobalVariable:
556  * @style:  the XSLT transformation context
557  * @name:  the variable name
558  * @ns_uri:  the variable namespace URI
559  * @select:  the expression which need to be evaluated to generate a value
560  * @tree:  the subtree if select is NULL
561  * @comp:  the precompiled value
562  * @value:  the string value if available
563  *
564  * Register a new variable value. If @value is NULL it unregisters
565  * the variable
566  *
567  * Returns 0 in case of success, -1 in case of error
568  */
569 static int
570 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
571                      const xmlChar *ns_uri, const xmlChar *select,
572                      xmlNodePtr tree, xsltStylePreCompPtr comp,
573                      const xmlChar *value) {
574     xsltStackElemPtr elem, tmp;
575     if (style == NULL)
576         return(-1);
577     if (name == NULL)
578         return(-1);
579     if (comp == NULL)
580         return(-1);
581
582 #ifdef WITH_XSLT_DEBUG_VARIABLE
583     if (comp->type == XSLT_FUNC_PARAM)
584         xsltGenericDebug(xsltGenericDebugContext,
585                          "Defining global param %s\n", name);
586     else
587         xsltGenericDebug(xsltGenericDebugContext,
588                          "Defining global variable %s\n", name);
589 #endif
590     elem = xsltNewStackElem();
591     if (elem == NULL)
592         return(-1);
593     elem->comp = comp;
594     elem->name = xmlStrdup(name);
595     elem->select = xmlStrdup(select);
596     if (ns_uri)
597         elem->nameURI = xmlStrdup(ns_uri);
598     elem->tree = tree;
599     tmp = style->variables;
600     if (tmp == NULL) {
601         elem->next = NULL;
602         style->variables = elem;
603     } else {
604         while (tmp->next != NULL)
605             tmp = tmp->next;
606         elem->next = NULL;
607         tmp->next = elem;
608     }
609     if (value != NULL) {
610         elem->computed = 1;
611         elem->value = xmlXPathNewString(value);
612     }
613     return(0);
614 }
615
616 /**
617  * xsltEvalUserParams:
618  * @ctxt:  the XSLT transformation context
619  * @params:  a NULL terminated arry of parameters names/values tuples
620  *
621  * Evaluate the global variables of a stylesheet. This need to be
622  * done on parsed stylesheets before starting to apply transformations
623  *
624  * Returns 0 in case of success, -1 in case of error
625  */
626 int
627 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
628     xsltStylesheetPtr style;
629     int indx = 0;
630     const xmlChar *name;
631     const xmlChar *value;
632     xmlChar *ncname, *prefix;
633     const xmlChar *href;
634     xmlXPathCompExprPtr comp;
635     xmlXPathObjectPtr result;
636     int oldProximityPosition, oldContextSize;
637
638     if (ctxt == NULL)
639         return(-1);
640     if (params == NULL)
641         return(0);
642  
643     style = ctxt->style;
644     while (params[indx] != NULL) {
645         name = (const xmlChar *)params[indx++];
646         value = (const xmlChar *)params[indx++];
647         if ((name == NULL) || (value == NULL))
648             break;
649
650 #ifdef WITH_XSLT_DEBUG_VARIABLE
651         xsltGenericDebug(xsltGenericDebugContext,
652             "Evaluating user parameter %s=%s\n", name, value);
653 #endif
654         /*
655          * Name lookup
656          */
657         ncname = xmlSplitQName2(name, &prefix);
658         href = NULL;
659         if (ncname != NULL) {
660             if (prefix != NULL) {
661                 xmlNsPtr ns;
662
663                 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
664                                  prefix);
665                 if (ns == NULL) {
666                     xsltGenericError(xsltGenericErrorContext,
667                         "user param : no namespace bound to prefix %s\n", prefix);
668                     href = NULL;
669                 } else {
670                     href = ns->href;
671                 }
672                 xmlFree(prefix);
673             } else {
674                 href = NULL;
675             }
676             xmlFree(ncname);
677         } else {
678             href = NULL;
679             ncname = xmlStrdup(name);
680         }
681
682         /*
683          * Do the evaluation
684          */
685         result = NULL;
686         comp = xmlXPathCompile(value);
687         if (comp != NULL) {
688             oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
689             oldContextSize = ctxt->xpathCtxt->contextSize;
690             ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
691             /* TODO: do we need to propagate the namespaces here ? */
692             ctxt->xpathCtxt->namespaces = NULL;
693             ctxt->xpathCtxt->nsNr = 0;
694             result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
695             ctxt->xpathCtxt->contextSize = oldContextSize;
696             ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
697             xmlXPathFreeCompExpr(comp);
698         }
699         if (result == NULL) {
700             xsltGenericError(xsltGenericErrorContext,
701                 "Evaluating user parameter %s failed\n", name);
702         } else {
703             xsltStackElemPtr elem;
704             int res;
705
706 #ifdef WITH_XSLT_DEBUG_VARIABLE
707 #ifdef LIBXML_DEBUG_ENABLED
708             if ((xsltGenericDebugContext == stdout) ||
709                 (xsltGenericDebugContext == stderr))
710                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
711                                         result, 0);
712 #endif
713 #endif
714             elem = xsltNewStackElem();
715             if (elem != NULL) {
716                 elem->name = xmlStrdup(ncname);
717                 if (value != NULL)
718                     elem->select = xmlStrdup(value);
719                 else
720                     elem->select = NULL;
721                 if (href)
722                     elem->nameURI = xmlStrdup(href);
723                 elem->tree = NULL;
724                 elem->computed = 1;
725                 elem->value = result;
726             }
727             /*
728              * Global parameters are stored in the XPath context
729              * variables pool.
730              */
731             res = xmlHashAddEntry2(ctxt->globalVars,
732                              ncname, href, elem);
733             if (res != 0) {
734                 xsltFreeStackElem(elem);
735                 xsltGenericError(xsltGenericErrorContext,
736                     "Global parameter %s already defined\n", ncname);
737             }
738         }
739         xmlFree(ncname);
740     }
741
742     return(0);
743 }
744
745 /**
746  * xsltBuildVariable:
747  * @ctxt:  the XSLT transformation context
748  * @comp:  the precompiled form
749  * @tree:  the tree if select is NULL
750  *
751  * Computes a new variable value.
752  *
753  * Returns the xsltStackElemPtr or NULL in case of error
754  */
755 static xsltStackElemPtr
756 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
757                   xmlNodePtr tree) {
758     xsltStackElemPtr elem;
759
760 #ifdef WITH_XSLT_DEBUG_VARIABLE
761     xsltGenericDebug(xsltGenericDebugContext,
762                      "Building variable %s", comp->name);
763     if (comp->select != NULL)
764         xsltGenericDebug(xsltGenericDebugContext,
765                          " select %s", comp->select);
766     xsltGenericDebug(xsltGenericDebugContext, "\n");
767 #endif
768     elem = xsltNewStackElem();
769     if (elem == NULL)
770         return(NULL);
771     elem->comp = comp;
772     elem->name = xmlStrdup(comp->name);
773     if (comp->select != NULL)
774         elem->select = xmlStrdup(comp->select);
775     else
776         elem->select = NULL;
777     if (comp->ns)
778         elem->nameURI = xmlStrdup(comp->ns);
779     elem->tree = tree;
780     if (elem->computed == 0) {
781         elem->value = xsltEvalVariable(ctxt, elem, comp);
782         if (elem->value != NULL)
783             elem->computed = 1;
784     }
785     return(elem);
786 }
787
788 /**
789  * xsltRegisterVariable:
790  * @ctxt:  the XSLT transformation context
791  * @name:  the variable name
792  * @ns_uri:  the variable namespace URI
793  * @select:  the expression which need to be evaluated to generate a value
794  * @tree:  the tree if select is NULL
795  * @param:  this is a parameter actually
796  *
797  * Computes and register a new variable value. 
798  *
799  * Returns 0 in case of success, -1 in case of error
800  */
801 static int
802 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
803                      xmlNodePtr tree, int param) {
804     xsltStackElemPtr elem;
805
806     if (xsltCheckStackElem(ctxt, comp->name, comp->ns) != 0) {
807         if (!param) {
808             xsltGenericError(xsltGenericErrorContext,
809             "xsl:variable : redefining %s\n", comp->name);
810         }
811 #ifdef WITH_XSLT_DEBUG_VARIABLE
812         else
813             xsltGenericDebug(xsltGenericDebugContext,
814                      "param %s defined by caller", comp->name);
815 #endif
816         return(0);
817     }
818     elem = xsltBuildVariable(ctxt, comp, tree);
819     xsltAddStackElem(ctxt, elem);
820     return(0);
821 }
822
823 /**
824  * xsltGlobalVariableLookup:
825  * @ctxt:  the XSLT transformation context
826  * @name:  the variable name
827  * @ns_uri:  the variable namespace URI
828  *
829  * Search in the Variable array of the context for the given
830  * variable value.
831  *
832  * Returns the value or NULL if not found
833  */
834 static xmlXPathObjectPtr
835 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
836                          const xmlChar *ns_uri) {
837     xsltStackElemPtr elem;
838     xmlXPathObjectPtr ret = NULL;
839
840     /*
841      * Lookup the global variables in XPath global variable hash table
842      */
843     if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
844         return(NULL);
845     elem = (xsltStackElemPtr)
846             xmlHashLookup2(ctxt->globalVars, name, ns_uri);
847     if (elem == NULL) {
848 #ifdef WITH_XSLT_DEBUG_VARIABLE
849         xsltGenericDebug(xsltGenericDebugContext,
850                          "global variable not found %s\n", name);
851 #endif
852         return(NULL);
853     }
854     if (elem->computed == 0)
855         ret = xsltEvalGlobalVariable(elem, ctxt);
856     else
857         ret = elem->value;
858     return(xmlXPathObjectCopy(ret));
859 }
860
861 /**
862  * xsltVariableLookup:
863  * @ctxt:  the XSLT transformation context
864  * @name:  the variable name
865  * @ns_uri:  the variable namespace URI
866  *
867  * Search in the Variable array of the context for the given
868  * variable value.
869  *
870  * Returns the value or NULL if not found
871  */
872 xmlXPathObjectPtr
873 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
874                    const xmlChar *ns_uri) {
875     xsltStackElemPtr elem;
876
877     if (ctxt == NULL)
878         return(NULL);
879
880     elem = xsltStackLookup(ctxt, name, ns_uri);
881     if (elem == NULL) {
882         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
883     }
884     if (elem->computed == 0) {
885 #ifdef WITH_XSLT_DEBUG_VARIABLE
886         xsltGenericDebug(xsltGenericDebugContext,
887                          "uncomputed variable %s\n", name);
888 #endif
889         elem->value = xsltEvalVariable(ctxt, elem, NULL);
890         elem->computed = 1;
891     }
892     if (elem->value != NULL)
893         return(xmlXPathObjectCopy(elem->value));
894 #ifdef WITH_XSLT_DEBUG_VARIABLE
895     xsltGenericDebug(xsltGenericDebugContext,
896                      "variable not found %s\n", name);
897 #endif
898     return(NULL);
899 }
900
901 /**
902  * xsltParseStylesheetCallerParam:
903  * @ctxt:  the XSLT transformation context
904  * @cur:  the "param" element
905  *
906  * parse an XSLT transformation param declaration, compute
907  * its value but doesn't record it.
908  *
909  * It returns the new xsltStackElemPtr or NULL
910  */
911
912 xsltStackElemPtr
913 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
914     xmlNodePtr tree = NULL;
915     xsltStackElemPtr elem = NULL;
916     xsltStylePreCompPtr comp;
917
918     if ((cur == NULL) || (ctxt == NULL))
919         return(NULL);
920     comp = (xsltStylePreCompPtr) cur->_private;
921     if (comp == NULL) {
922         xsltGenericError(xsltGenericErrorContext,
923             "xsl:param : compilation error\n");
924         return(NULL);
925     }
926
927     if (comp->name == NULL) {
928         xsltGenericError(xsltGenericErrorContext,
929             "xsl:param : missing name attribute\n");
930         return(NULL);
931     }
932 #ifdef WITH_XSLT_DEBUG_VARIABLE
933     xsltGenericDebug(xsltGenericDebugContext,
934             "Handling param %s\n", comp->name);
935 #endif
936
937
938     if (comp->select == NULL) {
939         tree = cur->children;
940     } else {
941 #ifdef WITH_XSLT_DEBUG_VARIABLE
942         xsltGenericDebug(xsltGenericDebugContext,
943             "        select %s\n", comp->select);
944 #endif
945         tree = cur;
946     }
947
948     elem = xsltBuildVariable(ctxt, comp, tree);
949
950     return(elem);
951 }
952
953 /**
954  * xsltParseGlobalVariable:
955  * @style:  the XSLT stylesheet
956  * @cur:  the "variable" element
957  *
958  * parse an XSLT transformation variable declaration and record
959  * its value.
960  */
961
962 void
963 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
964     xsltStylePreCompPtr comp;
965
966     if ((cur == NULL) || (style == NULL))
967         return;
968
969     xsltStylePreCompute(style, cur);
970     comp = (xsltStylePreCompPtr) cur->_private;
971     if (comp == NULL) {
972         xsltGenericError(xsltGenericErrorContext,
973              "xsl:variable : compilation had failed\n");
974         return;
975     }
976
977     if (comp->name == NULL) {
978         xsltGenericError(xsltGenericErrorContext,
979             "xsl:variable : missing name attribute\n");
980         return;
981     }
982
983 #ifdef WITH_XSLT_DEBUG_VARIABLE
984     xsltGenericDebug(xsltGenericDebugContext,
985         "Registering global variable %s\n", comp->name);
986 #endif
987
988     xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
989                                cur->children, comp, NULL);
990 }
991
992 /**
993  * xsltParseGlobalParam:
994  * @style:  the XSLT stylesheet
995  * @cur:  the "param" element
996  *
997  * parse an XSLT transformation param declaration and record
998  * its value.
999  */
1000
1001 void
1002 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1003     xsltStylePreCompPtr comp;
1004
1005     if ((cur == NULL) || (style == NULL))
1006         return;
1007
1008     xsltStylePreCompute(style, cur);
1009     comp = (xsltStylePreCompPtr) cur->_private;
1010     if (comp == NULL) {
1011         xsltGenericError(xsltGenericErrorContext,
1012              "xsl:param : compilation had failed\n");
1013         return;
1014     }
1015
1016     if (comp->name == NULL) {
1017         xsltGenericError(xsltGenericErrorContext,
1018             "xsl:param : missing name attribute\n");
1019         return;
1020     }
1021
1022 #ifdef WITH_XSLT_DEBUG_VARIABLE
1023     xsltGenericDebug(xsltGenericDebugContext,
1024         "Registering global param %s\n", comp->name);
1025 #endif
1026
1027     xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1028                                cur->children, comp, NULL);
1029 }
1030
1031 /**
1032  * xsltParseStylesheetVariable:
1033  * @ctxt:  the XSLT transformation context
1034  * @cur:  the "variable" element
1035  *
1036  * parse an XSLT transformation variable declaration and record
1037  * its value.
1038  */
1039
1040 void
1041 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1042     xsltStylePreCompPtr comp;
1043
1044     if ((cur == NULL) || (ctxt == NULL))
1045         return;
1046
1047     comp = (xsltStylePreCompPtr) cur->_private;
1048     if (comp == NULL) {
1049         xsltGenericError(xsltGenericErrorContext,
1050              "xsl:variable : compilation had failed\n");
1051         return;
1052     }
1053
1054     if (comp->name == NULL) {
1055         xsltGenericError(xsltGenericErrorContext,
1056             "xsl:variable : missing name attribute\n");
1057         return;
1058     }
1059
1060 #ifdef WITH_XSLT_DEBUG_VARIABLE
1061     xsltGenericDebug(xsltGenericDebugContext,
1062         "Registering variable %s\n", comp->name);
1063 #endif
1064
1065     xsltRegisterVariable(ctxt, comp, cur->children, 0);
1066 }
1067
1068 /**
1069  * xsltParseStylesheetParam:
1070  * @ctxt:  the XSLT transformation context
1071  * @cur:  the "param" element
1072  *
1073  * parse an XSLT transformation param declaration and record
1074  * its value.
1075  */
1076
1077 void
1078 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1079     xsltStylePreCompPtr comp;
1080
1081     if ((cur == NULL) || (ctxt == NULL))
1082         return;
1083
1084     comp = (xsltStylePreCompPtr) cur->_private;
1085     if (comp == NULL) {
1086         xsltGenericError(xsltGenericErrorContext,
1087              "xsl:param : compilation had failed\n");
1088         return;
1089     }
1090
1091     if (comp->name == NULL) {
1092         xsltGenericError(xsltGenericErrorContext,
1093             "xsl:param : missing name attribute\n");
1094         return;
1095     }
1096
1097 #ifdef WITH_XSLT_DEBUG_VARIABLE
1098     xsltGenericDebug(xsltGenericDebugContext,
1099         "Registering param %s\n", comp->name);
1100 #endif
1101
1102     xsltRegisterVariable(ctxt, comp, cur->children, 1);
1103 }
1104
1105 /**
1106  * xsltFreeGlobalVariables:
1107  * @ctxt:  the XSLT transformation context
1108  *
1109  * Free up the data associated to the global variables
1110  * its value.
1111  */
1112
1113 void
1114 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1115     xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1116 }
1117
1118 /**
1119  * xsltXPathVariableLookup:
1120  * @ctxt:  a void * but the the XSLT transformation context actually
1121  * @name:  the variable name
1122  * @ns_uri:  the variable namespace URI
1123  *
1124  * This is the entry point when a varibale is needed by the XPath
1125  * interpretor.
1126  *
1127  * Returns the value or NULL if not found
1128  */
1129 xmlXPathObjectPtr
1130 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1131                         const xmlChar *ns_uri) {
1132     xsltTransformContextPtr context;
1133     xmlXPathObjectPtr ret;
1134
1135     if ((ctxt == NULL) || (name == NULL))
1136         return(NULL);
1137
1138 #ifdef WITH_XSLT_DEBUG_VARIABLE
1139     xsltGenericDebug(xsltGenericDebugContext,
1140             "Lookup variable %s\n", name);
1141 #endif
1142     context = (xsltTransformContextPtr) ctxt;
1143     ret = xsltVariableLookup(context, name, ns_uri);
1144     if (ret == NULL) {
1145         xsltGenericError(xsltGenericErrorContext,
1146             "unregistered variable %s\n", name);
1147     }
1148 #ifdef WITH_XSLT_DEBUG_VARIABLE
1149     if (ret != NULL)
1150         xsltGenericDebug(xsltGenericDebugContext,
1151             "found variable %s\n", name);
1152 #endif
1153     return(ret);
1154 }
1155
1156