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