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