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