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