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