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