- libxslt/templates.c libxslt/transform.c libxslt/transform.h
[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                 "xsltCopyStackElem : 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) || (ctxt->varsNr == 0))
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     ;
241
242     for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
243         cur = ctxt->varsTab[i-1];
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  * @precomp: pointer to precompiled data
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     xmlNodePtr oldInst;
286     int oldNsNr;
287     xmlNsPtr *oldNamespaces;
288
289     if ((ctxt == NULL) || (elem == NULL))
290         return(NULL);
291
292 #ifdef WITH_XSLT_DEBUG_VARIABLE
293     xsltGenericDebug(xsltGenericDebugContext,
294         "Evaluating variable %s\n", elem->name);
295 #endif
296     if (elem->select != NULL) {
297         xmlXPathCompExprPtr comp = NULL;
298
299         if ((precomp != NULL) && (precomp->comp != NULL)) {
300             comp = precomp->comp;
301         } else {
302             comp = xmlXPathCompile(elem->select);
303         }
304         if (comp == NULL)
305             return(NULL);
306         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
307         oldContextSize = ctxt->xpathCtxt->contextSize;
308         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
309         oldInst = ctxt->inst;
310         oldNsNr = ctxt->xpathCtxt->nsNr;
311         oldNamespaces = ctxt->xpathCtxt->namespaces;
312         if (precomp != NULL) {
313             ctxt->inst = precomp->inst;
314             ctxt->xpathCtxt->namespaces = precomp->nsList;
315             ctxt->xpathCtxt->nsNr = precomp->nsNr;
316         } else {
317             ctxt->inst = NULL;
318             ctxt->xpathCtxt->namespaces = NULL;
319             ctxt->xpathCtxt->nsNr = 0;
320         }
321         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
322         ctxt->xpathCtxt->contextSize = oldContextSize;
323         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
324         ctxt->xpathCtxt->nsNr = oldNsNr;
325         ctxt->xpathCtxt->namespaces = oldNamespaces;
326         ctxt->inst = oldInst;
327         if ((precomp == NULL) || (precomp->comp == NULL))
328             xmlXPathFreeCompExpr(comp);
329         if (result == NULL) {
330             xsltGenericError(xsltGenericErrorContext,
331                 "Evaluating variable %s failed\n", elem->name);
332 #ifdef WITH_XSLT_DEBUG_VARIABLE
333 #ifdef LIBXML_DEBUG_ENABLED
334         } else {
335             if ((xsltGenericDebugContext == stdout) ||
336                 (xsltGenericDebugContext == stderr))
337                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
338                                         result, 0);
339 #endif
340 #endif
341         }
342     } else {
343         if (elem->tree == NULL) {
344             result = xmlXPathNewCString("");
345         } else {
346             /*
347              * This is a result tree fragment.
348              */
349             xmlNodePtr container;
350             xmlNodePtr oldInsert;
351
352             container = xmlNewDocNode(ctxt->output, NULL,
353                                       (const xmlChar *) "fake", NULL);
354             if (container == NULL)
355                 return(NULL);
356
357             oldInsert = ctxt->insert;
358             ctxt->insert = container;
359             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
360             ctxt->insert = oldInsert;
361
362             result = xmlXPathNewValueTree(container);
363             if (result == NULL) {
364                 result = xmlXPathNewCString("");
365             }
366 #ifdef WITH_XSLT_DEBUG_VARIABLE
367 #ifdef LIBXML_DEBUG_ENABLED
368             if ((xsltGenericDebugContext == stdout) ||
369                 (xsltGenericDebugContext == stderr))
370                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
371                                         result, 0);
372 #endif
373 #endif
374         }
375     }
376     return(result);
377 }
378
379 /**
380  * xsltEvalGlobalVariable:
381  * @elem:  the variable or parameter.
382  * @ctxt:  the XSLT transformation context
383  *
384  * Evaluate a global variable value.
385  *
386  * Returns the XPath Object value or NULL in case of error
387  */
388 static xmlXPathObjectPtr
389 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
390     xmlXPathObjectPtr result = NULL;
391     xsltStylePreCompPtr precomp;
392     int oldProximityPosition, oldContextSize;
393     xmlNodePtr oldInst;
394     int oldNsNr;
395     xmlNsPtr *oldNamespaces;
396
397     if ((ctxt == NULL) || (elem == NULL))
398         return(NULL);
399     if (elem->computed)
400         return(elem->value);
401
402
403 #ifdef WITH_XSLT_DEBUG_VARIABLE
404     xsltGenericDebug(xsltGenericDebugContext,
405         "Evaluating global variable %s\n", elem->name);
406 #endif
407
408     precomp = elem->comp;
409     if (elem->select != NULL) {
410         xmlXPathCompExprPtr comp = NULL;
411
412         if ((precomp != NULL) && (precomp->comp != NULL)) {
413             comp = precomp->comp;
414         } else {
415             comp = xmlXPathCompile(elem->select);
416         }
417         if (comp == NULL)
418             return(NULL);
419         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
420         oldContextSize = ctxt->xpathCtxt->contextSize;
421         oldInst = ctxt->inst;
422         oldNsNr = ctxt->xpathCtxt->nsNr;
423         oldNamespaces = ctxt->xpathCtxt->namespaces;
424         if (precomp != NULL) {
425             ctxt->inst = precomp->inst;
426             ctxt->xpathCtxt->namespaces = precomp->nsList;
427             ctxt->xpathCtxt->nsNr = precomp->nsNr;
428         } else {
429             ctxt->inst = NULL;
430             ctxt->xpathCtxt->namespaces = NULL;
431             ctxt->xpathCtxt->nsNr = 0;
432         }
433         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
434         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
435         ctxt->xpathCtxt->contextSize = oldContextSize;
436         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
437         ctxt->inst = oldInst;
438         ctxt->xpathCtxt->nsNr = oldNsNr;
439         ctxt->xpathCtxt->namespaces = oldNamespaces;
440         if ((precomp == NULL) || (precomp->comp == NULL))
441             xmlXPathFreeCompExpr(comp);
442         if (result == NULL) {
443             xsltGenericError(xsltGenericErrorContext,
444                 "Evaluating global variable %s failed\n", elem->name);
445 #ifdef WITH_XSLT_DEBUG_VARIABLE
446 #ifdef LIBXML_DEBUG_ENABLED
447         } else {
448             if ((xsltGenericDebugContext == stdout) ||
449                 (xsltGenericDebugContext == stderr))
450                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
451                                         result, 0);
452 #endif
453 #endif
454         }
455     } else {
456         if (elem->tree == NULL) {
457             result = xmlXPathNewCString("");
458         } else {
459             /*
460              * This is a result tree fragment.
461              */
462             xmlNodePtr container;
463             xmlNodePtr oldInsert;
464
465             container = xmlNewDocNode(ctxt->output, NULL,
466                                       (const xmlChar *) "fake", NULL);
467             if (container == NULL)
468                 return(NULL);
469
470             oldInsert = ctxt->insert;
471             ctxt->insert = container;
472             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
473             ctxt->insert = oldInsert;
474
475             result = xmlXPathNewValueTree(container);
476             if (result == NULL) {
477                 result = xmlXPathNewCString("");
478             }
479 #ifdef WITH_XSLT_DEBUG_VARIABLE
480 #ifdef LIBXML_DEBUG_ENABLED
481             if ((xsltGenericDebugContext == stdout) ||
482                 (xsltGenericDebugContext == stderr))
483                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
484                                         result, 0);
485 #endif
486 #endif
487         }
488     }
489     if (result != NULL) {
490         elem->value = result;
491         elem->computed = 1;
492     }
493     return(result);
494 }
495
496 /**
497  * xsltEvalGlobalVariables:
498  * @ctxt:  the XSLT transformation context
499  *
500  * Evaluate the global variables of a stylesheet. This need to be
501  * done on parsed stylesheets before starting to apply transformations
502  *
503  * Returns 0 in case of success, -1 in case of error
504  */
505 int
506 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
507     xsltStackElemPtr elem;
508     xsltStylesheetPtr style;
509
510     if (ctxt == NULL)
511         return(-1);
512  
513 #ifdef WITH_XSLT_DEBUG_VARIABLE
514     xsltGenericDebug(xsltGenericDebugContext,
515         "Registering global variables\n");
516 #endif
517     ctxt->node = (xmlNodePtr) ctxt->document->doc;
518     ctxt->xpathCtxt->contextSize = 1;
519     ctxt->xpathCtxt->proximityPosition = 1;
520
521     /*
522      * Walk the list from the stylesheets and populate the hash table
523      */
524     style = ctxt->style;
525     while (style != NULL) {
526         elem = style->variables;
527         
528 #ifdef WITH_XSLT_DEBUG_VARIABLE
529         if ((style->doc != NULL) && (style->doc->URL != NULL)) {
530             xsltGenericDebug(xsltGenericDebugContext,
531                              "Registering global variables from %s\n",
532                              style->doc->URL);
533         }
534 #endif
535
536         while (elem != NULL) {
537             xsltStackElemPtr def;
538
539             /*
540              * Global variables are stored in the variables pool.
541              */
542             def = (xsltStackElemPtr) 
543                     xmlHashLookup2(ctxt->globalVars,
544                                  elem->name, elem->nameURI);
545             if (def == NULL) {
546                 int res;
547
548                 def = xsltCopyStackElem(elem);
549                 res = xmlHashAddEntry2(ctxt->globalVars,
550                                  elem->name, elem->nameURI, def);
551             } else if ((elem->comp != NULL) &&
552                        (elem->comp->type == XSLT_FUNC_VARIABLE)) {
553                 xsltGenericError(xsltGenericErrorContext,
554                     "Global variable %s already defined\n", elem->name);
555             }
556             elem = elem->next;
557         }
558
559         style = xsltNextImport(style);
560     }
561
562     /*
563      * This part does the actual evaluation
564      */
565     ctxt->node = (xmlNodePtr) ctxt->document->doc;
566     ctxt->xpathCtxt->contextSize = 1;
567     ctxt->xpathCtxt->proximityPosition = 1;
568     xmlHashScan(ctxt->globalVars,
569                 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
570
571     return(0);
572 }
573
574 /**
575  * xsltRegisterGlobalVariable:
576  * @style:  the XSLT transformation context
577  * @name:  the variable name
578  * @ns_uri:  the variable namespace URI
579  * @select:  the expression which need to be evaluated to generate a value
580  * @tree:  the subtree if select is NULL
581  * @comp:  the precompiled value
582  * @value:  the string value if available
583  *
584  * Register a new variable value. If @value is NULL it unregisters
585  * the variable
586  *
587  * Returns 0 in case of success, -1 in case of error
588  */
589 static int
590 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
591                      const xmlChar *ns_uri, const xmlChar *select,
592                      xmlNodePtr tree, xsltStylePreCompPtr comp,
593                      const xmlChar *value) {
594     xsltStackElemPtr elem, tmp;
595     if (style == NULL)
596         return(-1);
597     if (name == NULL)
598         return(-1);
599     if (comp == NULL)
600         return(-1);
601
602 #ifdef WITH_XSLT_DEBUG_VARIABLE
603     if (comp->type == XSLT_FUNC_PARAM)
604         xsltGenericDebug(xsltGenericDebugContext,
605                          "Defining global param %s\n", name);
606     else
607         xsltGenericDebug(xsltGenericDebugContext,
608                          "Defining global variable %s\n", name);
609 #endif
610
611     elem = xsltNewStackElem();
612     if (elem == NULL)
613         return(-1);
614     elem->comp = comp;
615     elem->name = xmlStrdup(name);
616     elem->select = xmlStrdup(select);
617     if (ns_uri)
618         elem->nameURI = xmlStrdup(ns_uri);
619     elem->tree = tree;
620     tmp = style->variables;
621     if (tmp == NULL) {
622         elem->next = NULL;
623         style->variables = elem;
624     } else {
625         while (tmp->next != NULL)
626             tmp = tmp->next;
627         elem->next = NULL;
628         tmp->next = elem;
629     }
630     if (value != NULL) {
631         elem->computed = 1;
632         elem->value = xmlXPathNewString(value);
633     }
634     return(0);
635 }
636
637 /**
638  * xsltEvalUserParams:
639  * @ctxt:  the XSLT transformation context
640  * @params:  a NULL terminated arry of parameters names/values tuples
641  *
642  * Evaluate the global variables of a stylesheet. This needs to be
643  * done on parsed stylesheets before starting to apply transformations
644  *
645  * Returns 0 in case of success, -1 in case of error
646  */
647 int
648 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
649     xsltStylesheetPtr style;
650     int indx = 0;
651     const xmlChar *name;
652     const xmlChar *value;
653     xmlChar *ncname, *prefix;
654     const xmlChar *href;
655     xmlXPathCompExprPtr comp;
656     xmlXPathObjectPtr result;
657     int oldProximityPosition, oldContextSize;
658     int oldNsNr;
659     xmlNsPtr *oldNamespaces;
660
661     if (ctxt == NULL)
662         return(-1);
663     if (params == NULL)
664         return(0);
665  
666     style = ctxt->style;
667     while (params[indx] != NULL) {
668         name = (const xmlChar *)params[indx++];
669         value = (const xmlChar *)params[indx++];
670         if ((name == NULL) || (value == NULL))
671             break;
672
673 #ifdef WITH_XSLT_DEBUG_VARIABLE
674         xsltGenericDebug(xsltGenericDebugContext,
675             "Evaluating user parameter %s=%s\n", name, value);
676 #endif
677
678         /*
679          * Name lookup
680          */
681         ncname = xmlSplitQName2(name, &prefix);
682         href = NULL;
683         if (ncname != NULL) {
684             if (prefix != NULL) {
685                 xmlNsPtr ns;
686
687                 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
688                                  prefix);
689                 if (ns == NULL) {
690                     xsltGenericError(xsltGenericErrorContext,
691                     "user param : no namespace bound to prefix %s\n", prefix);
692                     href = NULL;
693                 } else {
694                     href = ns->href;
695                 }
696                 xmlFree(prefix);
697             } else {
698                 href = NULL;
699             }
700             xmlFree(ncname);
701         } else {
702             href = NULL;
703             ncname = xmlStrdup(name);
704         }
705
706         /*
707          * Do the evaluation
708          */
709         result = NULL;
710         comp = xmlXPathCompile(value);
711         if (comp != NULL) {
712             oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
713             oldContextSize = ctxt->xpathCtxt->contextSize;
714             ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
715
716             /* 
717              * There is really no in scope namespace for parameters on the
718              * command line.
719              */
720             oldNsNr = ctxt->xpathCtxt->nsNr;
721             oldNamespaces = ctxt->xpathCtxt->namespaces;
722             ctxt->xpathCtxt->namespaces = NULL;
723             ctxt->xpathCtxt->nsNr = 0;
724             result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
725             ctxt->xpathCtxt->contextSize = oldContextSize;
726             ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
727             ctxt->xpathCtxt->nsNr = oldNsNr;
728             ctxt->xpathCtxt->namespaces = oldNamespaces;
729             xmlXPathFreeCompExpr(comp);
730         }
731         if (result == NULL) {
732             xsltGenericError(xsltGenericErrorContext,
733                 "Evaluating user parameter %s failed\n", name);
734         } else {
735             xsltStackElemPtr elem;
736             int res;
737
738 #ifdef WITH_XSLT_DEBUG_VARIABLE
739 #ifdef LIBXML_DEBUG_ENABLED
740             if ((xsltGenericDebugContext == stdout) ||
741                 (xsltGenericDebugContext == stderr))
742                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
743                                         result, 0);
744 #endif
745 #endif
746
747             elem = xsltNewStackElem();
748             if (elem != NULL) {
749                 elem->name = xmlStrdup(ncname);
750                 if (value != NULL)
751                     elem->select = xmlStrdup(value);
752                 else
753                     elem->select = NULL;
754                 if (href)
755                     elem->nameURI = xmlStrdup(href);
756                 elem->tree = NULL;
757                 elem->computed = 1;
758                 elem->value = result;
759             }
760             /*
761              * Global parameters are stored in the XPath context
762              * variables pool.
763              */
764             res = xmlHashAddEntry2(ctxt->globalVars,
765                              ncname, href, elem);
766             if (res != 0) {
767                 xsltFreeStackElem(elem);
768                 xsltGenericError(xsltGenericErrorContext,
769                     "Global parameter %s already defined\n", ncname);
770             }
771         }
772         xmlFree(ncname);
773     }
774
775     return(0);
776 }
777
778 /**
779  * xsltBuildVariable:
780  * @ctxt:  the XSLT transformation context
781  * @comp:  the precompiled form
782  * @tree:  the tree if select is NULL
783  *
784  * Computes a new variable value.
785  *
786  * Returns the xsltStackElemPtr or NULL in case of error
787  */
788 static xsltStackElemPtr
789 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
790                   xmlNodePtr tree) {
791     xsltStackElemPtr elem;
792
793 #ifdef WITH_XSLT_DEBUG_VARIABLE
794     xsltGenericDebug(xsltGenericDebugContext,
795                      "Building variable %s", comp->name);
796     if (comp->select != NULL)
797         xsltGenericDebug(xsltGenericDebugContext,
798                          " select %s", comp->select);
799     xsltGenericDebug(xsltGenericDebugContext, "\n");
800 #endif
801
802     elem = xsltNewStackElem();
803     if (elem == NULL)
804         return(NULL);
805     elem->comp = comp;
806     elem->name = xmlStrdup(comp->name);
807     if (comp->select != NULL)
808         elem->select = xmlStrdup(comp->select);
809     else
810         elem->select = NULL;
811     if (comp->ns)
812         elem->nameURI = xmlStrdup(comp->ns);
813     elem->tree = tree;
814     if (elem->computed == 0) {
815         elem->value = xsltEvalVariable(ctxt, elem, comp);
816         if (elem->value != NULL)
817             elem->computed = 1;
818     }
819     return(elem);
820 }
821
822 /**
823  * xsltRegisterVariable:
824  * @ctxt:  the XSLT transformation context
825  * @comp:  pointer to precompiled data
826  * @tree:  the tree if select is NULL
827  * @param:  this is a parameter actually
828  *
829  * Computes and register a new variable value. 
830  *
831  * Returns 0 in case of success, -1 in case of error
832  */
833 static int
834 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
835                      xmlNodePtr tree, int param) {
836     xsltStackElemPtr elem;
837
838     if (xsltCheckStackElem(ctxt, comp->name, comp->ns) != 0) {
839         if (!param) {
840             xsltGenericError(xsltGenericErrorContext,
841             "xsl:variable : redefining %s\n", comp->name);
842         }
843 #ifdef WITH_XSLT_DEBUG_VARIABLE
844         else
845             xsltGenericDebug(xsltGenericDebugContext,
846                      "param %s defined by caller\n", comp->name);
847 #endif
848         return(0);
849     }
850     elem = xsltBuildVariable(ctxt, comp, tree);
851     xsltAddStackElem(ctxt, elem);
852     return(0);
853 }
854
855 /**
856  * xsltGlobalVariableLookup:
857  * @ctxt:  the XSLT transformation context
858  * @name:  the variable name
859  * @ns_uri:  the variable namespace URI
860  *
861  * Search in the Variable array of the context for the given
862  * variable value.
863  *
864  * Returns the value or NULL if not found
865  */
866 static xmlXPathObjectPtr
867 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
868                          const xmlChar *ns_uri) {
869     xsltStackElemPtr elem;
870     xmlXPathObjectPtr ret = NULL;
871
872     /*
873      * Lookup the global variables in XPath global variable hash table
874      */
875     if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
876         return(NULL);
877     elem = (xsltStackElemPtr)
878             xmlHashLookup2(ctxt->globalVars, name, ns_uri);
879     if (elem == NULL) {
880 #ifdef WITH_XSLT_DEBUG_VARIABLE
881         xsltGenericDebug(xsltGenericDebugContext,
882                          "global variable not found %s\n", name);
883 #endif
884         return(NULL);
885     }
886     if (elem->computed == 0)
887         ret = xsltEvalGlobalVariable(elem, ctxt);
888     else
889         ret = elem->value;
890     return(xmlXPathObjectCopy(ret));
891 }
892
893 /**
894  * xsltVariableLookup:
895  * @ctxt:  the XSLT transformation context
896  * @name:  the variable name
897  * @ns_uri:  the variable namespace URI
898  *
899  * Search in the Variable array of the context for the given
900  * variable value.
901  *
902  * Returns the value or NULL if not found
903  */
904 xmlXPathObjectPtr
905 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
906                    const xmlChar *ns_uri) {
907     xsltStackElemPtr elem;
908
909     if (ctxt == NULL)
910         return(NULL);
911
912     elem = xsltStackLookup(ctxt, name, ns_uri);
913     if (elem == NULL) {
914         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
915     }
916     if (elem->computed == 0) {
917 #ifdef WITH_XSLT_DEBUG_VARIABLE
918         xsltGenericDebug(xsltGenericDebugContext,
919                          "uncomputed variable %s\n", name);
920 #endif
921         elem->value = xsltEvalVariable(ctxt, elem, NULL);
922         elem->computed = 1;
923     }
924     if (elem->value != NULL)
925         return(xmlXPathObjectCopy(elem->value));
926 #ifdef WITH_XSLT_DEBUG_VARIABLE
927     xsltGenericDebug(xsltGenericDebugContext,
928                      "variable not found %s\n", name);
929 #endif
930     return(NULL);
931 }
932
933 /**
934  * xsltParseStylesheetCallerParam:
935  * @ctxt:  the XSLT transformation context
936  * @cur:  the "param" element
937  *
938  * parse an XSLT transformation param declaration, compute
939  * its value but doesn't record it.
940  *
941  * It returns the new xsltStackElemPtr or NULL
942  */
943
944 xsltStackElemPtr
945 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
946     xmlNodePtr tree = NULL;
947     xsltStackElemPtr elem = NULL;
948     xsltStylePreCompPtr comp;
949
950     if ((cur == NULL) || (ctxt == NULL))
951         return(NULL);
952     comp = (xsltStylePreCompPtr) cur->_private;
953     if (comp == NULL) {
954         xsltGenericError(xsltGenericErrorContext,
955             "xsl:param : compilation error\n");
956         return(NULL);
957     }
958
959     if (comp->name == NULL) {
960         xsltGenericError(xsltGenericErrorContext,
961             "xsl:param : missing name attribute\n");
962         return(NULL);
963     }
964
965 #ifdef WITH_XSLT_DEBUG_VARIABLE
966     xsltGenericDebug(xsltGenericDebugContext,
967             "Handling param %s\n", comp->name);
968 #endif
969
970     if (comp->select == NULL) {
971         tree = cur->children;
972     } else {
973 #ifdef WITH_XSLT_DEBUG_VARIABLE
974         xsltGenericDebug(xsltGenericDebugContext,
975             "        select %s\n", comp->select);
976 #endif
977         tree = cur;
978     }
979
980     elem = xsltBuildVariable(ctxt, comp, tree);
981
982     return(elem);
983 }
984
985 /**
986  * xsltParseGlobalVariable:
987  * @style:  the XSLT stylesheet
988  * @cur:  the "variable" element
989  *
990  * parse an XSLT transformation variable declaration and record
991  * its value.
992  */
993
994 void
995 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
996     xsltStylePreCompPtr comp;
997
998     if ((cur == NULL) || (style == NULL))
999         return;
1000
1001     xsltStylePreCompute(style, cur);
1002     comp = (xsltStylePreCompPtr) cur->_private;
1003     if (comp == NULL) {
1004         xsltGenericError(xsltGenericErrorContext,
1005              "xsl:variable : compilation failed\n");
1006         return;
1007     }
1008
1009     if (comp->name == NULL) {
1010         xsltGenericError(xsltGenericErrorContext,
1011             "xsl:variable : missing name attribute\n");
1012         return;
1013     }
1014
1015 #ifdef WITH_XSLT_DEBUG_VARIABLE
1016     xsltGenericDebug(xsltGenericDebugContext,
1017         "Registering global variable %s\n", comp->name);
1018 #endif
1019
1020     xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1021                                cur->children, comp, NULL);
1022 }
1023
1024 /**
1025  * xsltParseGlobalParam:
1026  * @style:  the XSLT stylesheet
1027  * @cur:  the "param" element
1028  *
1029  * parse an XSLT transformation param declaration and record
1030  * its value.
1031  */
1032
1033 void
1034 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1035     xsltStylePreCompPtr comp;
1036
1037     if ((cur == NULL) || (style == NULL))
1038         return;
1039
1040     xsltStylePreCompute(style, cur);
1041     comp = (xsltStylePreCompPtr) cur->_private;
1042     if (comp == NULL) {
1043         xsltGenericError(xsltGenericErrorContext,
1044              "xsl:param : compilation failed\n");
1045         return;
1046     }
1047
1048     if (comp->name == NULL) {
1049         xsltGenericError(xsltGenericErrorContext,
1050             "xsl:param : missing name attribute\n");
1051         return;
1052     }
1053
1054 #ifdef WITH_XSLT_DEBUG_VARIABLE
1055     xsltGenericDebug(xsltGenericDebugContext,
1056         "Registering global param %s\n", comp->name);
1057 #endif
1058
1059     xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1060                                cur->children, comp, NULL);
1061 }
1062
1063 /**
1064  * xsltParseStylesheetVariable:
1065  * @ctxt:  the XSLT transformation context
1066  * @cur:  the "variable" element
1067  *
1068  * parse an XSLT transformation variable declaration and record
1069  * its value.
1070  */
1071
1072 void
1073 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1074     xsltStylePreCompPtr comp;
1075
1076     if ((cur == NULL) || (ctxt == NULL))
1077         return;
1078
1079     comp = (xsltStylePreCompPtr) cur->_private;
1080     if (comp == NULL) {
1081         xsltGenericError(xsltGenericErrorContext,
1082              "xsl:variable : compilation failed\n");
1083         return;
1084     }
1085
1086     if (comp->name == NULL) {
1087         xsltGenericError(xsltGenericErrorContext,
1088             "xsl:variable : missing name attribute\n");
1089         return;
1090     }
1091
1092 #ifdef WITH_XSLT_DEBUG_VARIABLE
1093     xsltGenericDebug(xsltGenericDebugContext,
1094         "Registering variable %s\n", comp->name);
1095 #endif
1096
1097     xsltRegisterVariable(ctxt, comp, cur->children, 0);
1098 }
1099
1100 /**
1101  * xsltParseStylesheetParam:
1102  * @ctxt:  the XSLT transformation context
1103  * @cur:  the "param" element
1104  *
1105  * parse an XSLT transformation param declaration and record
1106  * its value.
1107  */
1108
1109 void
1110 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1111     xsltStylePreCompPtr comp;
1112
1113     if ((cur == NULL) || (ctxt == NULL))
1114         return;
1115
1116     comp = (xsltStylePreCompPtr) cur->_private;
1117     if (comp == NULL) {
1118         xsltGenericError(xsltGenericErrorContext,
1119              "xsl:param : compilation failed\n");
1120         return;
1121     }
1122
1123     if (comp->name == NULL) {
1124         xsltGenericError(xsltGenericErrorContext,
1125             "xsl:param : missing name attribute\n");
1126         return;
1127     }
1128
1129 #ifdef WITH_XSLT_DEBUG_VARIABLE
1130     xsltGenericDebug(xsltGenericDebugContext,
1131         "Registering param %s\n", comp->name);
1132 #endif
1133
1134     xsltRegisterVariable(ctxt, comp, cur->children, 1);
1135 }
1136
1137 /**
1138  * xsltFreeGlobalVariables:
1139  * @ctxt:  the XSLT transformation context
1140  *
1141  * Free up the data associated to the global variables
1142  * its value.
1143  */
1144
1145 void
1146 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1147     xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1148 }
1149
1150 /**
1151  * xsltXPathVariableLookup:
1152  * @ctxt:  a void * but the the XSLT transformation context actually
1153  * @name:  the variable name
1154  * @ns_uri:  the variable namespace URI
1155  *
1156  * This is the entry point when a varibale is needed by the XPath
1157  * interpretor.
1158  *
1159  * Returns the value or NULL if not found
1160  */
1161 xmlXPathObjectPtr
1162 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1163                         const xmlChar *ns_uri) {
1164     xsltTransformContextPtr context;
1165     xmlXPathObjectPtr ret;
1166
1167     if ((ctxt == NULL) || (name == NULL))
1168         return(NULL);
1169
1170 #ifdef WITH_XSLT_DEBUG_VARIABLE
1171     xsltGenericDebug(xsltGenericDebugContext,
1172             "Lookup variable %s\n", name);
1173 #endif
1174     context = (xsltTransformContextPtr) ctxt;
1175     ret = xsltVariableLookup(context, name, ns_uri);
1176     if (ret == NULL) {
1177         xsltGenericError(xsltGenericErrorContext,
1178             "unregistered variable %s\n", name);
1179     }
1180 #ifdef WITH_XSLT_DEBUG_VARIABLE
1181     if (ret != NULL)
1182         xsltGenericDebug(xsltGenericDebugContext,
1183             "found variable %s\n", name);
1184 #endif
1185     return(ret);
1186 }
1187
1188