1/*
2 * variables.c: Implementation of the variable storage and lookup
3 *
4 * Reference:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#include <string.h>
16
17#include <libxml/xmlmemory.h>
18#include <libxml/tree.h>
19#include <libxml/valid.h>
20#include <libxml/hash.h>
21#include <libxml/xmlerror.h>
22#include <libxml/xpath.h>
23#include <libxml/xpathInternals.h>
24#include <libxml/parserInternals.h>
25#include <libxml/dict.h>
26#include "xslt.h"
27#include "xsltInternals.h"
28#include "xsltutils.h"
29#include "variables.h"
30#include "transform.h"
31#include "imports.h"
32#include "preproc.h"
33#include "keys.h"
34
35#ifdef WITH_XSLT_DEBUG
36 #define WITH_XSLT_DEBUG_VARIABLE
37#endif
38
39#ifdef XSLT_REFACTORED
40const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
41#endif
42
43const xmlChar *xsltComputingGlobalVarMarker =
44 (const xmlChar *) " var/param being computed";
45
46#define XSLT_VAR_GLOBAL 1<<0
47#define XSLT_VAR_IN_SELECT 1<<1
48#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
49
50/************************************************************************
51 *									*
52 *  Result Value Tree (Result Tree Fragment) interfaces			*
53 *									*
54 ************************************************************************/
55/**
56 * xsltCreateRVT:
57 * @ctxt:  an XSLT transformation context
58 *
59 * Creates a Result Value Tree
60 * (the XSLT 1.0 term for this is "Result Tree Fragment")
61 *
62 * Returns the result value tree or NULL in case of API or internal errors.
63 */
64xmlDocPtr
65xsltCreateRVT(xsltTransformContextPtr ctxt)
66{
67    xmlDocPtr container;
68
69    /*
70    * Question: Why is this function public?
71    * Answer: It is called by the EXSLT module.
72    */
73    if (ctxt == NULL)
74	return(NULL);
75
76    /*
77    * Reuse a RTF from the cache if available.
78    */
79    if (ctxt->cache->RVT) {
80	container = ctxt->cache->RVT;
81	ctxt->cache->RVT = (xmlDocPtr) container->next;
82	/* clear the internal pointers */
83	container->next = NULL;
84	container->prev = NULL;
85	if (ctxt->cache->nbRVT > 0)
86	    ctxt->cache->nbRVT--;
87#ifdef XSLT_DEBUG_PROFILE_CACHE
88	ctxt->cache->dbgReusedRVTs++;
89#endif
90	return(container);
91    }
92
93    container = xmlNewDoc(NULL);
94    if (container == NULL)
95	return(NULL);
96    container->dict = ctxt->dict;
97    xmlDictReference(container->dict);
98    XSLT_MARK_RES_TREE_FRAG(container);
99    container->doc = container;
100    container->parent = NULL;
101    return(container);
102}
103
104/**
105 * xsltRegisterTmpRVT:
106 * @ctxt:  an XSLT transformation context
107 * @RVT:  a result value tree (Result Tree Fragment)
108 *
109 * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
110 * in the garbage collector.
111 * The fragment will be freed at the exit of the currently
112 * instantiated xsl:template.
113 * Obsolete; this function might produce massive memory overhead,
114 * since the fragment is only freed when the current xsl:template
115 * exits. Use xsltRegisterLocalRVT() instead.
116 *
117 * Returns 0 in case of success and -1 in case of API or internal errors.
118 */
119int
120xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
121{
122    if ((ctxt == NULL) || (RVT == NULL))
123	return(-1);
124
125    /*
126    * We'll restrict the lifetime of user-created fragments
127    * insinde an xsl:variable and xsl:param to the lifetime of the
128    * var/param itself.
129    */
130    if (ctxt->contextVariable != NULL) {
131	RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
132	XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
133	return(0);
134    }
135
136    RVT->next = (xmlNodePtr) ctxt->tmpRVT;
137    if (ctxt->tmpRVT != NULL)
138	ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
139    ctxt->tmpRVT = RVT;
140    return(0);
141}
142
143/**
144 * xsltRegisterLocalRVT:
145 * @ctxt:  an XSLT transformation context
146 * @RVT:  a result value tree (Result Tree Fragment; xmlDocPtr)
147 *
148 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
149 * in the RVT garbage collector.
150 * The fragment will be freed when the instruction which created the
151 * fragment exits.
152 *
153 * Returns 0 in case of success and -1 in case of API or internal errors.
154 */
155int
156xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
157		     xmlDocPtr RVT)
158{
159    if ((ctxt == NULL) || (RVT == NULL))
160	return(-1);
161
162    /*
163    * When evaluating "select" expressions of xsl:variable
164    * and xsl:param, we need to bind newly created tree fragments
165    * to the variable itself; otherwise the tragment will be
166    * freed before we leave the scope of a var.
167    */
168    if ((ctxt->contextVariable != NULL) &&
169	(XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
170    {
171	RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
172	XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
173	return(0);
174    }
175    /*
176    * Store the fragment in the scope of the current instruction.
177    * If not reference by a returning instruction (like EXSLT's function),
178    * then this fragment will be freed, when the instruction exits.
179    */
180    RVT->next = (xmlNodePtr) ctxt->localRVT;
181    if (ctxt->localRVT != NULL)
182	ctxt->localRVT->prev = (xmlNodePtr) RVT;
183    ctxt->localRVT = RVT;
184    /*
185    * We need to keep track of the first registered fragment
186    * for extension instructions which return fragments
187    * (e.g. EXSLT'S function), in order to let
188    * xsltExtensionInstructionResultFinalize() clear the
189    * preserving flag on the fragments.
190    */
191    if (ctxt->localRVTBase == NULL)
192	ctxt->localRVTBase = RVT;
193    return(0);
194}
195
196/**
197 * xsltExtensionInstructionResultFinalize:
198 * @ctxt:  an XSLT transformation context
199 *
200 * Finalizes the data (e.g. result tree fragments) created
201 * within a value-returning process (e.g. EXSLT's function).
202 * Tree fragments marked as being returned by a function are
203 * set to normal state, which means that the fragment garbage
204 * collector will free them after the function-calling process exits.
205 *
206 * Returns 0 in case of success and -1 in case of API or internal errors.
207 */
208int
209xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)
210{
211    xmlDocPtr cur;
212
213    if (ctxt == NULL)
214	return(-1);
215    if (ctxt->localRVTBase == NULL)
216	return(0);
217    /*
218    * Enable remaining local tree fragments to be freed
219    * by the fragment garbage collector.
220    */
221    cur = ctxt->localRVTBase;
222    do {
223	cur->psvi = NULL;
224	cur = (xmlDocPtr) cur->next;
225    } while (cur != NULL);
226    return(0);
227}
228
229/**
230 * xsltExtensionInstructionResultRegister:
231 * @ctxt: an XSLT transformation context
232 * @obj: an XPath object to be inspected for result tree fragments
233 *
234 * Marks the result of a value-returning extension instruction
235 * in order to avoid it being garbage collected before the
236 * extension instruction exits.
237 * Note that one still has to additionally register any newly created
238 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
239 *
240 * Returns 0 in case of success and -1 in case of error.
241 */
242int
243xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,
244				       xmlXPathObjectPtr obj)
245{
246    int i;
247    xmlNodePtr cur;
248    xmlDocPtr doc;
249
250    if ((ctxt == NULL) || (obj == NULL))
251	return(-1);
252
253    /*
254    * OPTIMIZE TODO: If no local variables/params and no local tree
255    * fragments were created, then we don't need to analyse the XPath
256    * objects for tree fragments.
257    */
258
259    if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
260	return(0);
261    if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
262	return(0);
263
264    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
265	cur = obj->nodesetval->nodeTab[i];
266	if (cur->type == XML_NAMESPACE_DECL) {
267	    /*
268	    * The XPath module sets the owner element of a ns-node on
269	    * the ns->next field.
270	    */
271	    if ((((xmlNsPtr) cur)->next != NULL) &&
272		(((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
273	    {
274		cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
275		doc = cur->doc;
276	    } else {
277		xsltTransformError(ctxt, NULL, ctxt->inst,
278		    "Internal error in "
279		    "xsltExtensionInstructionResultRegister(): "
280		    "Cannot retrieve the doc of a namespace node.\n");
281		goto error;
282	    }
283	} else {
284	    doc = cur->doc;
285	}
286	if (doc == NULL) {
287	    xsltTransformError(ctxt, NULL, ctxt->inst,
288		"Internal error in "
289		"xsltExtensionInstructionResultRegister(): "
290		"Cannot retrieve the doc of a node.\n");
291	    goto error;
292	}
293	if (doc->name && (doc->name[0] == ' ')) {
294	    /*
295	    * This is a result tree fragment.
296	    * We'll use the @psvi field for reference counting.
297	    * TODO: How do we know if this is a value of a
298	    *  global variable or a doc acquired via the
299	    *  document() function?
300	    */
301	    doc->psvi = (void *) ((long) 1);
302	}
303    }
304
305    return(0);
306error:
307    return(-1);
308}
309
310/**
311 * xsltReleaseRVT:
312 * @ctxt:  an XSLT transformation context
313 * @RVT:  a result value tree (Result Tree Fragment)
314 *
315 * Either frees the RVT (which is an xmlDoc) or stores
316 * it in the context's cache for later reuse.
317 */
318void
319xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
320{
321    if (RVT == NULL)
322	return;
323
324    if (ctxt && (ctxt->cache->nbRVT < 40)) {
325	/*
326	* Store the Result Tree Fragment.
327	* Free the document info.
328	*/
329	if (RVT->_private != NULL) {
330	    xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
331	    xmlFree(RVT->_private);
332	    RVT->_private = NULL;
333	}
334	/*
335	* Clear the document tree.
336	* REVISIT TODO: Do we expect ID/IDREF tables to be existent?
337	*/
338	if (RVT->children != NULL) {
339	    xmlFreeNodeList(RVT->children);
340	    RVT->children = NULL;
341	    RVT->last = NULL;
342	}
343	if (RVT->ids != NULL) {
344	    xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
345	    RVT->ids = NULL;
346	}
347	if (RVT->refs != NULL) {
348	    xmlFreeRefTable((xmlRefTablePtr) RVT->refs);
349	    RVT->refs = NULL;
350	}
351
352	/*
353	* Reset the reference counter.
354	*/
355	RVT->psvi = 0;
356
357	RVT->next = (xmlNodePtr) ctxt->cache->RVT;
358	ctxt->cache->RVT = RVT;
359
360	ctxt->cache->nbRVT++;
361
362#ifdef XSLT_DEBUG_PROFILE_CACHE
363	ctxt->cache->dbgCachedRVTs++;
364#endif
365	return;
366    }
367    /*
368    * Free it.
369    */
370    if (RVT->_private != NULL) {
371	xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
372	xmlFree(RVT->_private);
373    }
374    xmlFreeDoc(RVT);
375}
376
377/**
378 * xsltRegisterPersistRVT:
379 * @ctxt:  an XSLT transformation context
380 * @RVT:  a result value tree (Result Tree Fragment)
381 *
382 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
383 * in the fragment garbage collector.
384 * The fragment will be freed when the transformation context is
385 * freed.
386 *
387 * Returns 0 in case of success and -1 in case of error.
388 */
389int
390xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
391{
392    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
393
394    RVT->next = (xmlNodePtr) ctxt->persistRVT;
395    if (ctxt->persistRVT != NULL)
396	ctxt->persistRVT->prev = (xmlNodePtr) RVT;
397    ctxt->persistRVT = RVT;
398    return(0);
399}
400
401/**
402 * xsltFreeRVTs:
403 * @ctxt:  an XSLT transformation context
404 *
405 * Frees all registered result value trees (Result Tree Fragments)
406 * of the transformation. Internal function; should not be called
407 * by user-code.
408 */
409void
410xsltFreeRVTs(xsltTransformContextPtr ctxt)
411{
412    xmlDocPtr cur, next;
413
414    if (ctxt == NULL)
415	return;
416    /*
417    * Local fragments.
418    */
419    cur = ctxt->localRVT;
420    while (cur != NULL) {
421        next = (xmlDocPtr) cur->next;
422	if (cur->_private != NULL) {
423	    xsltFreeDocumentKeys(cur->_private);
424	    xmlFree(cur->_private);
425	}
426	xmlFreeDoc(cur);
427	cur = next;
428    }
429    ctxt->localRVT = NULL;
430    /*
431    * User-created per-template fragments.
432    */
433    cur = ctxt->tmpRVT;
434    while (cur != NULL) {
435        next = (xmlDocPtr) cur->next;
436	if (cur->_private != NULL) {
437	    xsltFreeDocumentKeys(cur->_private);
438	    xmlFree(cur->_private);
439	}
440	xmlFreeDoc(cur);
441	cur = next;
442    }
443    ctxt->tmpRVT = NULL;
444    /*
445    * Global fragments.
446    */
447    cur = ctxt->persistRVT;
448    while (cur != NULL) {
449        next = (xmlDocPtr) cur->next;
450	if (cur->_private != NULL) {
451	    xsltFreeDocumentKeys(cur->_private);
452	    xmlFree(cur->_private);
453	}
454	xmlFreeDoc(cur);
455	cur = next;
456    }
457    ctxt->persistRVT = NULL;
458}
459
460/************************************************************************
461 *									*
462 *			Module interfaces				*
463 *									*
464 ************************************************************************/
465
466/**
467 * xsltNewStackElem:
468 *
469 * Create a new XSLT ParserContext
470 *
471 * Returns the newly allocated xsltParserStackElem or NULL in case of error
472 */
473static xsltStackElemPtr
474xsltNewStackElem(xsltTransformContextPtr ctxt)
475{
476    xsltStackElemPtr ret;
477    /*
478    * Reuse a stack item from the cache if available.
479    */
480    if (ctxt && ctxt->cache->stackItems) {
481	ret = ctxt->cache->stackItems;
482	ctxt->cache->stackItems = ret->next;
483	ret->next = NULL;
484	ctxt->cache->nbStackItems--;
485#ifdef XSLT_DEBUG_PROFILE_CACHE
486	ctxt->cache->dbgReusedVars++;
487#endif
488	return(ret);
489    }
490    ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
491    if (ret == NULL) {
492	xsltTransformError(NULL, NULL, NULL,
493		"xsltNewStackElem : malloc failed\n");
494	return(NULL);
495    }
496    memset(ret, 0, sizeof(xsltStackElem));
497    ret->context = ctxt;
498    return(ret);
499}
500
501/**
502 * xsltCopyStackElem:
503 * @elem:  an XSLT stack element
504 *
505 * Makes a copy of the stack element
506 *
507 * Returns the copy of NULL
508 */
509static xsltStackElemPtr
510xsltCopyStackElem(xsltStackElemPtr elem) {
511    xsltStackElemPtr cur;
512
513    cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
514    if (cur == NULL) {
515	xsltTransformError(NULL, NULL, NULL,
516		"xsltCopyStackElem : malloc failed\n");
517	return(NULL);
518    }
519    memset(cur, 0, sizeof(xsltStackElem));
520    cur->context = elem->context;
521    cur->name = elem->name;
522    cur->nameURI = elem->nameURI;
523    cur->select = elem->select;
524    cur->tree = elem->tree;
525    cur->comp = elem->comp;
526    return(cur);
527}
528
529/**
530 * xsltFreeStackElem:
531 * @elem:  an XSLT stack element
532 *
533 * Free up the memory allocated by @elem
534 */
535static void
536xsltFreeStackElem(xsltStackElemPtr elem) {
537    if (elem == NULL)
538	return;
539    if (elem->value != NULL)
540	xmlXPathFreeObject(elem->value);
541    /*
542    * Release the list of temporary Result Tree Fragments.
543    */
544    if (elem->fragment) {
545	xmlDocPtr cur;
546
547	while (elem->fragment != NULL) {
548	    cur = elem->fragment;
549	    elem->fragment = (xmlDocPtr) cur->next;
550
551	    if (elem->context &&
552		(cur->psvi == (void *) ((long) 1)))
553	    {
554		/*
555		* This fragment is a result of an extension instruction
556		* (e.g. XSLT's function) and needs to be preserved until
557		* the instruction exits.
558		* Example: The fragment of the variable must not be freed
559		*  since it is returned by the EXSLT function:
560		*  <f:function name="foo">
561		*   <xsl:variable name="bar">
562		*     <bar/>
563		*   </xsl:variable>
564		*   <f:result select="$bar"/>
565		*  </f:function>
566		*
567		*/
568		xsltRegisterLocalRVT(elem->context, cur);
569	    } else {
570		xsltReleaseRVT((xsltTransformContextPtr) elem->context,
571		    cur);
572	    }
573	}
574    }
575    /*
576    * Cache or free the variable structure.
577    */
578    if (elem->context && (elem->context->cache->nbStackItems < 50)) {
579	/*
580	* Store the item in the cache.
581	*/
582	xsltTransformContextPtr ctxt = elem->context;
583	memset(elem, 0, sizeof(xsltStackElem));
584	elem->context = ctxt;
585	elem->next = ctxt->cache->stackItems;
586	ctxt->cache->stackItems = elem;
587	ctxt->cache->nbStackItems++;
588#ifdef XSLT_DEBUG_PROFILE_CACHE
589	ctxt->cache->dbgCachedVars++;
590#endif
591	return;
592    }
593    xmlFree(elem);
594}
595
596/**
597 * xsltFreeStackElemList:
598 * @elem:  an XSLT stack element
599 *
600 * Free up the memory allocated by @elem
601 */
602void
603xsltFreeStackElemList(xsltStackElemPtr elem) {
604    xsltStackElemPtr next;
605
606    while (elem != NULL) {
607	next = elem->next;
608	xsltFreeStackElem(elem);
609	elem = next;
610    }
611}
612
613/**
614 * xsltStackLookup:
615 * @ctxt:  an XSLT transformation context
616 * @name:  the local part of the name
617 * @nameURI:  the URI part of the name
618 *
619 * Locate an element in the stack based on its name.
620 */
621#if 0 /* TODO: Those seem to have been used for debugging. */
622static int stack_addr = 0;
623static int stack_cmp = 0;
624#endif
625
626static xsltStackElemPtr
627xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
628	        const xmlChar *nameURI) {
629    int i;
630    xsltStackElemPtr cur;
631
632    if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
633	return(NULL);
634
635    /*
636     * Do the lookup from the top of the stack, but
637     * don't use params being computed in a call-param
638     * First lookup expects the variable name and URI to
639     * come from the disctionnary and hence pointer comparison.
640     */
641    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
642	cur = ctxt->varsTab[i-1];
643	while (cur != NULL) {
644	    if ((cur->name == name) && (cur->nameURI == nameURI)) {
645#if 0
646		stack_addr++;
647#endif
648		return(cur);
649	    }
650	    cur = cur->next;
651	}
652    }
653
654    /*
655     * Redo the lookup with interned string compares
656     * to avoid string compares.
657     */
658    name = xmlDictLookup(ctxt->dict, name, -1);
659    if (nameURI != NULL)
660        nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
661
662    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
663	cur = ctxt->varsTab[i-1];
664	while (cur != NULL) {
665	    if ((cur->name == name) && (cur->nameURI == nameURI)) {
666#if 0
667		stack_cmp++;
668#endif
669		return(cur);
670	    }
671	    cur = cur->next;
672	}
673    }
674
675    return(NULL);
676}
677
678/**
679 * xsltCheckStackElem:
680 * @ctxt:  xn XSLT transformation context
681 * @name:  the variable name
682 * @nameURI:  the variable namespace URI
683 *
684 * Checks whether a variable or param is already defined.
685 *
686 * URGENT TODO: Checks for redefinition of vars/params should be
687 *  done only at compilation time.
688 *
689 * Returns 1 if variable is present, 2 if param is present, 3 if this
690 *         is an inherited param, 0 if not found, -1 in case of failure.
691 */
692static int
693xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
694	           const xmlChar *nameURI) {
695    xsltStackElemPtr cur;
696
697    if ((ctxt == NULL) || (name == NULL))
698	return(-1);
699
700    cur = xsltStackLookup(ctxt, name, nameURI);
701    if (cur == NULL)
702        return(0);
703    if (cur->comp != NULL) {
704        if (cur->comp->type == XSLT_FUNC_WITHPARAM)
705	    return(3);
706	else if (cur->comp->type == XSLT_FUNC_PARAM)
707	    return(2);
708    }
709
710    return(1);
711}
712
713/**
714 * xsltAddStackElem:
715 * @ctxt:  xn XSLT transformation context
716 * @elem:  a stack element
717 *
718 * Push an element (or list) onto the stack.
719 * In case of a list, each member will be pushed into
720 * a seperate slot; i.e. there's always 1 stack entry for
721 * 1 stack element.
722 *
723 * Returns 0 in case of success, -1 in case of failure.
724 */
725static int
726xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
727{
728    if ((ctxt == NULL) || (elem == NULL))
729	return(-1);
730
731    do {
732	if (ctxt->varsMax == 0) {
733	    ctxt->varsMax = 10;
734	    ctxt->varsTab =
735		(xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
736		sizeof(ctxt->varsTab[0]));
737	    if (ctxt->varsTab == NULL) {
738		xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
739		return (-1);
740	    }
741	}
742	if (ctxt->varsNr >= ctxt->varsMax) {
743	    ctxt->varsMax *= 2;
744	    ctxt->varsTab =
745		(xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
746		ctxt->varsMax *
747		sizeof(ctxt->varsTab[0]));
748	    if (ctxt->varsTab == NULL) {
749		xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
750		return (-1);
751	    }
752	}
753	ctxt->varsTab[ctxt->varsNr++] = elem;
754	ctxt->vars = elem;
755
756	elem = elem->next;
757    } while (elem != NULL);
758
759    return(0);
760}
761
762/**
763 * xsltAddStackElemList:
764 * @ctxt:  xn XSLT transformation context
765 * @elems:  a stack element list
766 *
767 * Push an element list onto the stack.
768 *
769 * Returns 0 in case of success, -1 in case of failure.
770 */
771int
772xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
773{
774    return(xsltAddStackElem(ctxt, elems));
775}
776
777/************************************************************************
778 *									*
779 *			Module interfaces				*
780 *									*
781 ************************************************************************/
782
783/**
784 * xsltEvalVariable:
785 * @ctxt:  the XSLT transformation context
786 * @variable:  the variable or parameter item
787 * @comp: the compiled XSLT instruction
788 *
789 * Evaluate a variable value.
790 *
791 * Returns the XPath Object value or NULL in case of error
792 */
793static xmlXPathObjectPtr
794xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
795	         xsltStylePreCompPtr castedComp)
796{
797#ifdef XSLT_REFACTORED
798    xsltStyleItemVariablePtr comp =
799	(xsltStyleItemVariablePtr) castedComp;
800#else
801    xsltStylePreCompPtr comp = castedComp;
802#endif
803    xmlXPathObjectPtr result = NULL;
804    xmlNodePtr oldInst;
805
806    if ((ctxt == NULL) || (variable == NULL))
807	return(NULL);
808
809    /*
810    * A variable or parameter are evaluated on demand; thus the
811    * context (of XSLT and XPath) need to be temporarily adjusted and
812    * restored on exit.
813    */
814    oldInst = ctxt->inst;
815
816#ifdef WITH_XSLT_DEBUG_VARIABLE
817    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
818	"Evaluating variable '%s'\n", variable->name));
819#endif
820    if (variable->select != NULL) {
821	xmlXPathCompExprPtr xpExpr = NULL;
822	xmlDocPtr oldXPDoc;
823	xmlNodePtr oldXPContextNode;
824	int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
825	xmlNsPtr *oldXPNamespaces;
826	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
827	xsltStackElemPtr oldVar = ctxt->contextVariable;
828
829	if ((comp != NULL) && (comp->comp != NULL)) {
830	    xpExpr = comp->comp;
831	} else {
832	    xpExpr = xmlXPathCompile(variable->select);
833	}
834	if (xpExpr == NULL)
835	    return(NULL);
836	/*
837	* Save context states.
838	*/
839	oldXPDoc = xpctxt->doc;
840	oldXPContextNode = xpctxt->node;
841	oldXPProximityPosition = xpctxt->proximityPosition;
842	oldXPContextSize = xpctxt->contextSize;
843	oldXPNamespaces = xpctxt->namespaces;
844	oldXPNsNr = xpctxt->nsNr;
845
846	xpctxt->node = ctxt->node;
847	/*
848	* OPTIMIZE TODO: Lame try to set the context doc.
849	*   Get rid of this somehow in xpath.c.
850	*/
851	if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
852	    ctxt->node->doc)
853	    xpctxt->doc = ctxt->node->doc;
854	/*
855	* BUG TODO: The proximity position and the context size will
856	*  potentially be wrong.
857	*  Example:
858	*  <xsl:template select="foo">
859	*    <xsl:variable name="pos" select="position()"/>
860	*    <xsl:for-each select="bar">
861	*      <xsl:value-of select="$pos"/>
862	*    </xsl:for-each>
863	*  </xsl:template>
864	*  Here the proximity position and context size are changed
865	*  to the context of <xsl:for-each select="bar">, but
866	*  the variable needs to be evaluated in the context of
867	*  <xsl:template select="foo">.
868	*/
869	if (comp != NULL) {
870
871#ifdef XSLT_REFACTORED
872	    if (comp->inScopeNs != NULL) {
873		xpctxt->namespaces = comp->inScopeNs->list;
874		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
875	    } else {
876		xpctxt->namespaces = NULL;
877		xpctxt->nsNr = 0;
878	    }
879#else
880	    xpctxt->namespaces = comp->nsList;
881	    xpctxt->nsNr = comp->nsNr;
882#endif
883	} else {
884	    xpctxt->namespaces = NULL;
885	    xpctxt->nsNr = 0;
886	}
887
888	/*
889	* We need to mark that we are "selecting" a var's value;
890	* if any tree fragments are created inside the expression,
891	* then those need to be stored inside the variable; otherwise
892	* we'll eventually free still referenced fragments, before
893	* we leave the scope of the variable.
894	*/
895	ctxt->contextVariable = variable;
896	variable->flags |= XSLT_VAR_IN_SELECT;
897
898	result = xmlXPathCompiledEval(xpExpr, xpctxt);
899
900	variable->flags ^= XSLT_VAR_IN_SELECT;
901	/*
902	* Restore Context states.
903	*/
904	ctxt->contextVariable = oldVar;
905
906	xpctxt->doc = oldXPDoc;
907	xpctxt->node = oldXPContextNode;
908	xpctxt->contextSize = oldXPContextSize;
909	xpctxt->proximityPosition = oldXPProximityPosition;
910	xpctxt->namespaces = oldXPNamespaces;
911	xpctxt->nsNr = oldXPNsNr;
912
913	if ((comp == NULL) || (comp->comp == NULL))
914	    xmlXPathFreeCompExpr(xpExpr);
915	if (result == NULL) {
916	    xsltTransformError(ctxt, NULL,
917		(comp != NULL) ? comp->inst : NULL,
918		"Failed to evaluate the expression of variable '%s'.\n",
919		variable->name);
920	    ctxt->state = XSLT_STATE_STOPPED;
921
922#ifdef WITH_XSLT_DEBUG_VARIABLE
923#ifdef LIBXML_DEBUG_ENABLED
924	} else {
925	    if ((xsltGenericDebugContext == stdout) ||
926		(xsltGenericDebugContext == stderr))
927		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
928					result, 0);
929#endif
930#endif
931	}
932    } else {
933	if (variable->tree == NULL) {
934	    result = xmlXPathNewCString("");
935	} else {
936	    if (variable->tree) {
937		xmlDocPtr container;
938		xmlNodePtr oldInsert;
939		xmlDocPtr  oldOutput;
940		xsltStackElemPtr oldVar = ctxt->contextVariable;
941
942		/*
943		* Generate a result tree fragment.
944		*/
945		container = xsltCreateRVT(ctxt);
946		if (container == NULL)
947		    goto error;
948		/*
949		* NOTE: Local Result Tree Fragments of params/variables
950		* are not registered globally anymore; the life-time
951		* is not directly dependant of the param/variable itself.
952		*
953		* OLD: xsltRegisterTmpRVT(ctxt, container);
954		*/
955		/*
956		* Attach the Result Tree Fragment to the variable;
957		* when the variable is freed, it will also free
958		* the Result Tree Fragment.
959		*/
960		variable->fragment = container;
961
962		oldOutput = ctxt->output;
963		oldInsert = ctxt->insert;
964
965		ctxt->output = container;
966		ctxt->insert = (xmlNodePtr) container;
967		ctxt->contextVariable = variable;
968		/*
969		* Process the sequence constructor (variable->tree).
970		* The resulting tree will be held by @container.
971		*/
972		xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
973		    NULL, NULL);
974
975		ctxt->contextVariable = oldVar;
976		ctxt->insert = oldInsert;
977		ctxt->output = oldOutput;
978
979		result = xmlXPathNewValueTree((xmlNodePtr) container);
980	    }
981	    if (result == NULL) {
982		result = xmlXPathNewCString("");
983	    } else {
984		/*
985		* Freeing is not handled there anymore.
986		* QUESTION TODO: What does the above comment mean?
987		*/
988	        result->boolval = 0;
989	    }
990#ifdef WITH_XSLT_DEBUG_VARIABLE
991#ifdef LIBXML_DEBUG_ENABLED
992
993	    if ((xsltGenericDebugContext == stdout) ||
994		(xsltGenericDebugContext == stderr))
995		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
996					result, 0);
997#endif
998#endif
999	}
1000    }
1001
1002error:
1003    ctxt->inst = oldInst;
1004    return(result);
1005}
1006
1007/**
1008 * xsltEvalGlobalVariable:
1009 * @elem:  the variable or parameter
1010 * @ctxt:  the XSLT transformation context
1011 *
1012 * Evaluates a the value of a global xsl:variable or
1013 * xsl:param declaration.
1014 *
1015 * Returns the XPath Object value or NULL in case of error
1016 */
1017static xmlXPathObjectPtr
1018xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
1019{
1020    xmlXPathObjectPtr result = NULL;
1021    xmlNodePtr oldInst;
1022    const xmlChar* oldVarName;
1023
1024#ifdef XSLT_REFACTORED
1025    xsltStyleBasicItemVariablePtr comp;
1026#else
1027    xsltStylePreCompPtr comp;
1028#endif
1029
1030    if ((ctxt == NULL) || (elem == NULL))
1031	return(NULL);
1032    if (elem->computed)
1033	return(elem->value);
1034
1035
1036#ifdef WITH_XSLT_DEBUG_VARIABLE
1037    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1038	"Evaluating global variable %s\n", elem->name));
1039#endif
1040
1041#ifdef WITH_DEBUGGER
1042    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
1043        elem->comp && elem->comp->inst)
1044        xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
1045#endif
1046
1047    oldInst = ctxt->inst;
1048    comp = elem->comp;
1049    oldVarName = elem->name;
1050    elem->name = xsltComputingGlobalVarMarker;
1051    /*
1052    * OPTIMIZE TODO: We should consider instantiating global vars/params
1053    *  on-demand. The vars/params don't need to be evaluated if never
1054    *  called; and in the case of global params, if values for such params
1055    *  are provided by the user.
1056    */
1057    if (elem->select != NULL) {
1058	xmlXPathCompExprPtr xpExpr = NULL;
1059	xmlDocPtr oldXPDoc;
1060	xmlNodePtr oldXPContextNode;
1061	int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1062	xmlNsPtr *oldXPNamespaces;
1063	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1064
1065	if ((comp != NULL) && (comp->comp != NULL)) {
1066	    xpExpr = comp->comp;
1067	} else {
1068	    xpExpr = xmlXPathCompile(elem->select);
1069	}
1070	if (xpExpr == NULL)
1071	    goto error;
1072
1073
1074	if (comp != NULL)
1075	    ctxt->inst = comp->inst;
1076	else
1077	    ctxt->inst = NULL;
1078	/*
1079	* SPEC XSLT 1.0:
1080	* "At top-level, the expression or template specifying the
1081	*  variable value is evaluated with the same context as that used
1082	*  to process the root node of the source document: the current
1083	*  node is the root node of the source document and the current
1084	*  node list is a list containing just the root node of the source
1085	*  document."
1086	*/
1087	/*
1088	* Save context states.
1089	*/
1090	oldXPDoc = xpctxt->doc;
1091	oldXPContextNode = xpctxt->node;
1092	oldXPProximityPosition = xpctxt->proximityPosition;
1093	oldXPContextSize = xpctxt->contextSize;
1094	oldXPNamespaces = xpctxt->namespaces;
1095	oldXPNsNr = xpctxt->nsNr;
1096
1097	xpctxt->node = ctxt->initialContextNode;
1098	xpctxt->doc = ctxt->initialContextDoc;
1099	xpctxt->contextSize = 1;
1100	xpctxt->proximityPosition = 1;
1101
1102	if (comp != NULL) {
1103
1104#ifdef XSLT_REFACTORED
1105	    if (comp->inScopeNs != NULL) {
1106		xpctxt->namespaces = comp->inScopeNs->list;
1107		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
1108	    } else {
1109		xpctxt->namespaces = NULL;
1110		xpctxt->nsNr = 0;
1111	    }
1112#else
1113	    xpctxt->namespaces = comp->nsList;
1114	    xpctxt->nsNr = comp->nsNr;
1115#endif
1116	} else {
1117	    xpctxt->namespaces = NULL;
1118	    xpctxt->nsNr = 0;
1119	}
1120
1121	result = xmlXPathCompiledEval(xpExpr, xpctxt);
1122
1123	/*
1124	* Restore Context states.
1125	*/
1126	xpctxt->doc = oldXPDoc;
1127	xpctxt->node = oldXPContextNode;
1128	xpctxt->contextSize = oldXPContextSize;
1129	xpctxt->proximityPosition = oldXPProximityPosition;
1130	xpctxt->namespaces = oldXPNamespaces;
1131	xpctxt->nsNr = oldXPNsNr;
1132
1133	if ((comp == NULL) || (comp->comp == NULL))
1134	    xmlXPathFreeCompExpr(xpExpr);
1135	if (result == NULL) {
1136	    if (comp == NULL)
1137		xsltTransformError(ctxt, NULL, NULL,
1138		    "Evaluating global variable %s failed\n", elem->name);
1139	    else
1140		xsltTransformError(ctxt, NULL, comp->inst,
1141		    "Evaluating global variable %s failed\n", elem->name);
1142	    ctxt->state = XSLT_STATE_STOPPED;
1143#ifdef WITH_XSLT_DEBUG_VARIABLE
1144#ifdef LIBXML_DEBUG_ENABLED
1145	} else {
1146	    if ((xsltGenericDebugContext == stdout) ||
1147		(xsltGenericDebugContext == stderr))
1148		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1149					result, 0);
1150#endif
1151#endif
1152	}
1153    } else {
1154	if (elem->tree == NULL) {
1155	    result = xmlXPathNewCString("");
1156	} else {
1157	    xmlDocPtr container;
1158	    xmlNodePtr oldInsert;
1159	    xmlDocPtr  oldOutput, oldXPDoc;
1160	    /*
1161	    * Generate a result tree fragment.
1162	    */
1163	    container = xsltCreateRVT(ctxt);
1164	    if (container == NULL)
1165		goto error;
1166	    /*
1167	    * Let the lifetime of the tree fragment be handled by
1168	    * the Libxslt's garbage collector.
1169	    */
1170	    xsltRegisterPersistRVT(ctxt, container);
1171
1172	    oldOutput = ctxt->output;
1173	    oldInsert = ctxt->insert;
1174
1175	    oldXPDoc = ctxt->xpathCtxt->doc;
1176
1177	    ctxt->output = container;
1178	    ctxt->insert = (xmlNodePtr) container;
1179
1180	    ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
1181	    /*
1182	    * Process the sequence constructor.
1183	    */
1184	    xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
1185
1186	    ctxt->xpathCtxt->doc = oldXPDoc;
1187
1188	    ctxt->insert = oldInsert;
1189	    ctxt->output = oldOutput;
1190
1191	    result = xmlXPathNewValueTree((xmlNodePtr) container);
1192	    if (result == NULL) {
1193		result = xmlXPathNewCString("");
1194	    } else {
1195	        result->boolval = 0; /* Freeing is not handled there anymore */
1196	    }
1197#ifdef WITH_XSLT_DEBUG_VARIABLE
1198#ifdef LIBXML_DEBUG_ENABLED
1199	    if ((xsltGenericDebugContext == stdout) ||
1200		(xsltGenericDebugContext == stderr))
1201		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1202					result, 0);
1203#endif
1204#endif
1205	}
1206    }
1207
1208error:
1209    elem->name = oldVarName;
1210    ctxt->inst = oldInst;
1211    if (result != NULL) {
1212	elem->value = result;
1213	elem->computed = 1;
1214    }
1215    return(result);
1216}
1217
1218/**
1219 * xsltEvalGlobalVariables:
1220 * @ctxt:  the XSLT transformation context
1221 *
1222 * Evaluates all global variables and parameters of a stylesheet.
1223 * For internal use only. This is called at start of a transformation.
1224 *
1225 * Returns 0 in case of success, -1 in case of error
1226 */
1227int
1228xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
1229    xsltStackElemPtr elem;
1230    xsltStylesheetPtr style;
1231
1232    if ((ctxt == NULL) || (ctxt->document == NULL))
1233	return(-1);
1234
1235#ifdef WITH_XSLT_DEBUG_VARIABLE
1236    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1237	"Registering global variables\n"));
1238#endif
1239    /*
1240     * Walk the list from the stylesheets and populate the hash table
1241     */
1242    style = ctxt->style;
1243    while (style != NULL) {
1244	elem = style->variables;
1245
1246#ifdef WITH_XSLT_DEBUG_VARIABLE
1247	if ((style->doc != NULL) && (style->doc->URL != NULL)) {
1248	    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1249			     "Registering global variables from %s\n",
1250		             style->doc->URL));
1251	}
1252#endif
1253
1254	while (elem != NULL) {
1255	    xsltStackElemPtr def;
1256
1257	    /*
1258	     * Global variables are stored in the variables pool.
1259	     */
1260	    def = (xsltStackElemPtr)
1261		    xmlHashLookup2(ctxt->globalVars,
1262		                 elem->name, elem->nameURI);
1263	    if (def == NULL) {
1264
1265		def = xsltCopyStackElem(elem);
1266		xmlHashAddEntry2(ctxt->globalVars,
1267				 elem->name, elem->nameURI, def);
1268	    } else if ((elem->comp != NULL) &&
1269		       (elem->comp->type == XSLT_FUNC_VARIABLE)) {
1270		/*
1271		 * Redefinition of variables from a different stylesheet
1272		 * should not generate a message.
1273		 */
1274		if ((elem->comp->inst != NULL) &&
1275		    (def->comp != NULL) && (def->comp->inst != NULL) &&
1276		    (elem->comp->inst->doc == def->comp->inst->doc))
1277		{
1278		    xsltTransformError(ctxt, style, elem->comp->inst,
1279			"Global variable %s already defined\n", elem->name);
1280		    if (style != NULL) style->errors++;
1281		}
1282	    }
1283	    elem = elem->next;
1284	}
1285
1286	style = xsltNextImport(style);
1287    }
1288
1289    /*
1290     * This part does the actual evaluation
1291     */
1292    xmlHashScan(ctxt->globalVars,
1293	        (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
1294
1295    return(0);
1296}
1297
1298/**
1299 * xsltRegisterGlobalVariable:
1300 * @style:  the XSLT transformation context
1301 * @name:  the variable name
1302 * @ns_uri:  the variable namespace URI
1303 * @sel:  the expression which need to be evaluated to generate a value
1304 * @tree:  the subtree if sel is NULL
1305 * @comp:  the precompiled value
1306 * @value:  the string value if available
1307 *
1308 * Register a new variable value. If @value is NULL it unregisters
1309 * the variable
1310 *
1311 * Returns 0 in case of success, -1 in case of error
1312 */
1313static int
1314xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
1315		     const xmlChar *ns_uri, const xmlChar *sel,
1316		     xmlNodePtr tree, xsltStylePreCompPtr comp,
1317		     const xmlChar *value) {
1318    xsltStackElemPtr elem, tmp;
1319    if (style == NULL)
1320	return(-1);
1321    if (name == NULL)
1322	return(-1);
1323    if (comp == NULL)
1324	return(-1);
1325
1326#ifdef WITH_XSLT_DEBUG_VARIABLE
1327    if (comp->type == XSLT_FUNC_PARAM)
1328	xsltGenericDebug(xsltGenericDebugContext,
1329			 "Defining global param %s\n", name);
1330    else
1331	xsltGenericDebug(xsltGenericDebugContext,
1332			 "Defining global variable %s\n", name);
1333#endif
1334
1335    elem = xsltNewStackElem(NULL);
1336    if (elem == NULL)
1337	return(-1);
1338    elem->comp = comp;
1339    elem->name = xmlDictLookup(style->dict, name, -1);
1340    elem->select = xmlDictLookup(style->dict, sel, -1);
1341    if (ns_uri)
1342	elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
1343    elem->tree = tree;
1344    tmp = style->variables;
1345    if (tmp == NULL) {
1346	elem->next = NULL;
1347	style->variables = elem;
1348    } else {
1349	while (tmp != NULL) {
1350	    if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
1351		(tmp->comp->type == XSLT_FUNC_VARIABLE) &&
1352		(xmlStrEqual(elem->name, tmp->name)) &&
1353		((elem->nameURI == tmp->nameURI) ||
1354		 (xmlStrEqual(elem->nameURI, tmp->nameURI))))
1355	    {
1356		xsltTransformError(NULL, style, comp->inst,
1357		"redefinition of global variable %s\n", elem->name);
1358		style->errors++;
1359	    }
1360	    if (tmp->next == NULL)
1361	        break;
1362	    tmp = tmp->next;
1363	}
1364	elem->next = NULL;
1365	tmp->next = elem;
1366    }
1367    if (value != NULL) {
1368	elem->computed = 1;
1369	elem->value = xmlXPathNewString(value);
1370    }
1371    return(0);
1372}
1373
1374/**
1375 * xsltProcessUserParamInternal
1376 *
1377 * @ctxt:  the XSLT transformation context
1378 * @name:  a null terminated parameter name
1379 * @value: a null terminated value (may be an XPath expression)
1380 * @eval:  0 to treat the value literally, else evaluate as XPath expression
1381 *
1382 * If @eval is 0 then @value is treated literally and is stored in the global
1383 * parameter/variable table without any change.
1384 *
1385 * Uf @eval is 1 then @value is treated as an XPath expression and is
1386 * evaluated.  In this case, if you want to pass a string which will be
1387 * interpreted literally then it must be enclosed in single or double quotes.
1388 * If the string contains single quotes (double quotes) then it cannot be
1389 * enclosed single quotes (double quotes).  If the string which you want to
1390 * be treated literally contains both single and double quotes (e.g. Meet
1391 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1392 * quoting character.  You cannot use &apos; or &quot; inside the string
1393 * because the replacement of character entities with their equivalents is
1394 * done at a different stage of processing.  The solution is to call
1395 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1396 *
1397 * This needs to be done on parsed stylesheets before starting to apply
1398 * transformations.  Normally this will be called (directly or indirectly)
1399 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1400 * or xsltQuoteOneUserParam.
1401 *
1402 * Returns 0 in case of success, -1 in case of error
1403 */
1404
1405static
1406int
1407xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
1408		             const xmlChar * name,
1409			     const xmlChar * value,
1410			     int eval) {
1411
1412    xsltStylesheetPtr style;
1413    const xmlChar *prefix;
1414    const xmlChar *href;
1415    xmlXPathCompExprPtr xpExpr;
1416    xmlXPathObjectPtr result;
1417
1418    xsltStackElemPtr elem;
1419    int res;
1420    void *res_ptr;
1421
1422    if (ctxt == NULL)
1423	return(-1);
1424    if (name == NULL)
1425	return(0);
1426    if (value == NULL)
1427	return(0);
1428
1429    style = ctxt->style;
1430
1431#ifdef WITH_XSLT_DEBUG_VARIABLE
1432    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1433	    "Evaluating user parameter %s=%s\n", name, value));
1434#endif
1435
1436    /*
1437     * Name lookup
1438     */
1439
1440    name = xsltSplitQName(ctxt->dict, name, &prefix);
1441    href = NULL;
1442    if (prefix != NULL) {
1443	xmlNsPtr ns;
1444
1445	ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
1446			 prefix);
1447	if (ns == NULL) {
1448	    xsltTransformError(ctxt, style, NULL,
1449	    "user param : no namespace bound to prefix %s\n", prefix);
1450	    href = NULL;
1451	} else {
1452	    href = ns->href;
1453	}
1454    }
1455
1456    if (name == NULL)
1457	return (-1);
1458
1459    res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
1460    if (res_ptr != 0) {
1461	xsltTransformError(ctxt, style, NULL,
1462	    "Global parameter %s already defined\n", name);
1463    }
1464    if (ctxt->globalVars == NULL)
1465	ctxt->globalVars = xmlHashCreate(20);
1466
1467    /*
1468     * do not overwrite variables with parameters from the command line
1469     */
1470    while (style != NULL) {
1471        elem = ctxt->style->variables;
1472	while (elem != NULL) {
1473	    if ((elem->comp != NULL) &&
1474	        (elem->comp->type == XSLT_FUNC_VARIABLE) &&
1475		(xmlStrEqual(elem->name, name)) &&
1476		(xmlStrEqual(elem->nameURI, href))) {
1477		return(0);
1478	    }
1479            elem = elem->next;
1480	}
1481        style = xsltNextImport(style);
1482    }
1483    style = ctxt->style;
1484    elem = NULL;
1485
1486    /*
1487     * Do the evaluation if @eval is non-zero.
1488     */
1489
1490    result = NULL;
1491    if (eval != 0) {
1492        xpExpr = xmlXPathCompile(value);
1493	if (xpExpr != NULL) {
1494	    xmlDocPtr oldXPDoc;
1495	    xmlNodePtr oldXPContextNode;
1496	    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1497	    xmlNsPtr *oldXPNamespaces;
1498	    xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1499
1500	    /*
1501	    * Save context states.
1502	    */
1503	    oldXPDoc = xpctxt->doc;
1504	    oldXPContextNode = xpctxt->node;
1505	    oldXPProximityPosition = xpctxt->proximityPosition;
1506	    oldXPContextSize = xpctxt->contextSize;
1507	    oldXPNamespaces = xpctxt->namespaces;
1508	    oldXPNsNr = xpctxt->nsNr;
1509
1510	    /*
1511	    * SPEC XSLT 1.0:
1512	    * "At top-level, the expression or template specifying the
1513	    *  variable value is evaluated with the same context as that used
1514	    *  to process the root node of the source document: the current
1515	    *  node is the root node of the source document and the current
1516	    *  node list is a list containing just the root node of the source
1517	    *  document."
1518	    */
1519	    xpctxt->doc = ctxt->initialContextDoc;
1520	    xpctxt->node = ctxt->initialContextNode;
1521	    xpctxt->contextSize = 1;
1522	    xpctxt->proximityPosition = 1;
1523	    /*
1524	    * There is really no in scope namespace for parameters on the
1525	    * command line.
1526	    */
1527	    xpctxt->namespaces = NULL;
1528	    xpctxt->nsNr = 0;
1529
1530	    result = xmlXPathCompiledEval(xpExpr, xpctxt);
1531
1532	    /*
1533	    * Restore Context states.
1534	    */
1535	    xpctxt->doc = oldXPDoc;
1536	    xpctxt->node = oldXPContextNode;
1537	    xpctxt->contextSize = oldXPContextSize;
1538	    xpctxt->proximityPosition = oldXPProximityPosition;
1539	    xpctxt->namespaces = oldXPNamespaces;
1540	    xpctxt->nsNr = oldXPNsNr;
1541
1542	    xmlXPathFreeCompExpr(xpExpr);
1543	}
1544	if (result == NULL) {
1545	    xsltTransformError(ctxt, style, NULL,
1546		"Evaluating user parameter %s failed\n", name);
1547	    ctxt->state = XSLT_STATE_STOPPED;
1548	    return(-1);
1549	}
1550    }
1551
1552    /*
1553     * If @eval is 0 then @value is to be taken literally and result is NULL
1554     *
1555     * If @eval is not 0, then @value is an XPath expression and has been
1556     * successfully evaluated and result contains the resulting value and
1557     * is not NULL.
1558     *
1559     * Now create an xsltStackElemPtr for insertion into the context's
1560     * global variable/parameter hash table.
1561     */
1562
1563#ifdef WITH_XSLT_DEBUG_VARIABLE
1564#ifdef LIBXML_DEBUG_ENABLED
1565    if ((xsltGenericDebugContext == stdout) ||
1566        (xsltGenericDebugContext == stderr))
1567	    xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1568				    result, 0);
1569#endif
1570#endif
1571
1572    elem = xsltNewStackElem(NULL);
1573    if (elem != NULL) {
1574	elem->name = name;
1575	elem->select = xmlDictLookup(ctxt->dict, value, -1);
1576	if (href != NULL)
1577	    elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1578	elem->tree = NULL;
1579	elem->computed = 1;
1580	if (eval == 0) {
1581	    elem->value = xmlXPathNewString(value);
1582	}
1583	else {
1584	    elem->value = result;
1585	}
1586    }
1587
1588    /*
1589     * Global parameters are stored in the XPath context variables pool.
1590     */
1591
1592    res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1593    if (res != 0) {
1594	xsltFreeStackElem(elem);
1595	xsltTransformError(ctxt, style, NULL,
1596	    "Global parameter %s already defined\n", name);
1597    }
1598    return(0);
1599}
1600
1601/**
1602 * xsltEvalUserParams:
1603 *
1604 * @ctxt:  the XSLT transformation context
1605 * @params:  a NULL terminated array of parameters name/value tuples
1606 *
1607 * Evaluate the global variables of a stylesheet. This needs to be
1608 * done on parsed stylesheets before starting to apply transformations.
1609 * Each of the parameters is evaluated as an XPath expression and stored
1610 * in the global variables/parameter hash table.  If you want your
1611 * parameter used literally, use xsltQuoteUserParams.
1612 *
1613 * Returns 0 in case of success, -1 in case of error
1614 */
1615
1616int
1617xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1618    int indx = 0;
1619    const xmlChar *name;
1620    const xmlChar *value;
1621
1622    if (params == NULL)
1623	return(0);
1624    while (params[indx] != NULL) {
1625	name = (const xmlChar *) params[indx++];
1626	value = (const xmlChar *) params[indx++];
1627    	if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1628	    return(-1);
1629    }
1630    return 0;
1631}
1632
1633/**
1634 * xsltQuoteUserParams:
1635 *
1636 * @ctxt:  the XSLT transformation context
1637 * @params:  a NULL terminated arry of parameters names/values tuples
1638 *
1639 * Similar to xsltEvalUserParams, but the values are treated literally and
1640 * are * *not* evaluated as XPath expressions. This should be done on parsed
1641 * stylesheets before starting to apply transformations.
1642 *
1643 * Returns 0 in case of success, -1 in case of error.
1644 */
1645
1646int
1647xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1648    int indx = 0;
1649    const xmlChar *name;
1650    const xmlChar *value;
1651
1652    if (params == NULL)
1653	return(0);
1654    while (params[indx] != NULL) {
1655	name = (const xmlChar *) params[indx++];
1656	value = (const xmlChar *) params[indx++];
1657    	if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1658	    return(-1);
1659    }
1660    return 0;
1661}
1662
1663/**
1664 * xsltEvalOneUserParam:
1665 * @ctxt:  the XSLT transformation context
1666 * @name:  a null terminated string giving the name of the parameter
1667 * @value:  a null terminated string giving the XPath expression to be evaluated
1668 *
1669 * This is normally called from xsltEvalUserParams to process a single
1670 * parameter from a list of parameters.  The @value is evaluated as an
1671 * XPath expression and the result is stored in the context's global
1672 * variable/parameter hash table.
1673 *
1674 * To have a parameter treated literally (not as an XPath expression)
1675 * use xsltQuoteUserParams (or xsltQuoteOneUserParam).  For more
1676 * details see description of xsltProcessOneUserParamInternal.
1677 *
1678 * Returns 0 in case of success, -1 in case of error.
1679 */
1680
1681int
1682xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1683    		     const xmlChar * name,
1684		     const xmlChar * value) {
1685    return xsltProcessUserParamInternal(ctxt, name, value,
1686		                        1 /* xpath eval ? */);
1687}
1688
1689/**
1690 * xsltQuoteOneUserParam:
1691 * @ctxt:  the XSLT transformation context
1692 * @name:  a null terminated string giving the name of the parameter
1693 * @value:  a null terminated string giving the parameter value
1694 *
1695 * This is normally called from xsltQuoteUserParams to process a single
1696 * parameter from a list of parameters.  The @value is stored in the
1697 * context's global variable/parameter hash table.
1698 *
1699 * Returns 0 in case of success, -1 in case of error.
1700 */
1701
1702int
1703xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1704			 const xmlChar * name,
1705			 const xmlChar * value) {
1706    return xsltProcessUserParamInternal(ctxt, name, value,
1707					0 /* xpath eval ? */);
1708}
1709
1710/**
1711 * xsltBuildVariable:
1712 * @ctxt:  the XSLT transformation context
1713 * @comp:  the precompiled form
1714 * @tree:  the tree if select is NULL
1715 *
1716 * Computes a new variable value.
1717 *
1718 * Returns the xsltStackElemPtr or NULL in case of error
1719 */
1720static xsltStackElemPtr
1721xsltBuildVariable(xsltTransformContextPtr ctxt,
1722		  xsltStylePreCompPtr castedComp,
1723		  xmlNodePtr tree)
1724{
1725#ifdef XSLT_REFACTORED
1726    xsltStyleBasicItemVariablePtr comp =
1727	(xsltStyleBasicItemVariablePtr) castedComp;
1728#else
1729    xsltStylePreCompPtr comp = castedComp;
1730#endif
1731    xsltStackElemPtr elem;
1732
1733#ifdef WITH_XSLT_DEBUG_VARIABLE
1734    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1735		     "Building variable %s", comp->name));
1736    if (comp->select != NULL)
1737	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1738			 " select %s", comp->select));
1739    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1740#endif
1741
1742    elem = xsltNewStackElem(ctxt);
1743    if (elem == NULL)
1744	return(NULL);
1745    elem->comp = (xsltStylePreCompPtr) comp;
1746    elem->name = comp->name;
1747    elem->select = comp->select;
1748    elem->nameURI = comp->ns;
1749    elem->tree = tree;
1750    elem->value = xsltEvalVariable(ctxt, elem,
1751	(xsltStylePreCompPtr) comp);
1752    if (elem->value != NULL)
1753	elem->computed = 1;
1754    return(elem);
1755}
1756
1757/**
1758 * xsltRegisterVariable:
1759 * @ctxt:  the XSLT transformation context
1760 * @comp: the compiled XSLT-variable (or param) instruction
1761 * @tree:  the tree if select is NULL
1762 * @isParam:  indicates if this is a parameter
1763 *
1764 * Computes and registers a new variable.
1765 *
1766 * Returns 0 in case of success, -1 in case of error
1767 */
1768static int
1769xsltRegisterVariable(xsltTransformContextPtr ctxt,
1770		     xsltStylePreCompPtr castedComp,
1771		     xmlNodePtr tree, int isParam)
1772{
1773#ifdef XSLT_REFACTORED
1774    xsltStyleBasicItemVariablePtr comp =
1775	(xsltStyleBasicItemVariablePtr) castedComp;
1776#else
1777    xsltStylePreCompPtr comp = castedComp;
1778    int present;
1779#endif
1780    xsltStackElemPtr variable;
1781
1782#ifdef XSLT_REFACTORED
1783    /*
1784    * REFACTORED NOTE: Redefinitions of vars/params are checked
1785    *  at compilation time in the refactored code.
1786    * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1787    */
1788#else
1789    present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1790    if (isParam == 0) {
1791	if ((present != 0) && (present != 3)) {
1792	    /* TODO: report QName. */
1793	    xsltTransformError(ctxt, NULL, comp->inst,
1794		"XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
1795	    return(0);
1796	}
1797    } else if (present != 0) {
1798	if ((present == 1) || (present == 2)) {
1799	    /* TODO: report QName. */
1800	    xsltTransformError(ctxt, NULL, comp->inst,
1801		"XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
1802	    return(0);
1803	}
1804#ifdef WITH_XSLT_DEBUG_VARIABLE
1805	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1806		 "param %s defined by caller\n", comp->name));
1807#endif
1808	return(0);
1809    }
1810#endif /* else of XSLT_REFACTORED */
1811
1812    variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1813    xsltAddStackElem(ctxt, variable);
1814    return(0);
1815}
1816
1817/**
1818 * xsltGlobalVariableLookup:
1819 * @ctxt:  the XSLT transformation context
1820 * @name:  the variable name
1821 * @ns_uri:  the variable namespace URI
1822 *
1823 * Search in the Variable array of the context for the given
1824 * variable value.
1825 *
1826 * Returns the value or NULL if not found
1827 */
1828static xmlXPathObjectPtr
1829xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1830		         const xmlChar *ns_uri) {
1831    xsltStackElemPtr elem;
1832    xmlXPathObjectPtr ret = NULL;
1833
1834    /*
1835     * Lookup the global variables in XPath global variable hash table
1836     */
1837    if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1838	return(NULL);
1839    elem = (xsltStackElemPtr)
1840	    xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1841    if (elem == NULL) {
1842#ifdef WITH_XSLT_DEBUG_VARIABLE
1843	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1844			 "global variable not found %s\n", name));
1845#endif
1846	return(NULL);
1847    }
1848    /*
1849    * URGENT TODO: Move the detection of recursive definitions
1850    * to compile-time.
1851    */
1852    if (elem->computed == 0) {
1853	if (elem->name == xsltComputingGlobalVarMarker) {
1854	    xsltTransformError(ctxt, NULL, elem->comp->inst,
1855		"Recursive definition of %s\n", name);
1856	    return(NULL);
1857	}
1858	ret = xsltEvalGlobalVariable(elem, ctxt);
1859    } else
1860	ret = elem->value;
1861    return(xmlXPathObjectCopy(ret));
1862}
1863
1864/**
1865 * xsltVariableLookup:
1866 * @ctxt:  the XSLT transformation context
1867 * @name:  the variable name
1868 * @ns_uri:  the variable namespace URI
1869 *
1870 * Search in the Variable array of the context for the given
1871 * variable value.
1872 *
1873 * Returns the value or NULL if not found
1874 */
1875xmlXPathObjectPtr
1876xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1877		   const xmlChar *ns_uri) {
1878    xsltStackElemPtr elem;
1879
1880    if (ctxt == NULL)
1881	return(NULL);
1882
1883    elem = xsltStackLookup(ctxt, name, ns_uri);
1884    if (elem == NULL) {
1885	return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1886    }
1887    if (elem->computed == 0) {
1888#ifdef WITH_XSLT_DEBUG_VARIABLE
1889	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1890		         "uncomputed variable %s\n", name));
1891#endif
1892        elem->value = xsltEvalVariable(ctxt, elem, NULL);
1893	elem->computed = 1;
1894    }
1895    if (elem->value != NULL)
1896	return(xmlXPathObjectCopy(elem->value));
1897#ifdef WITH_XSLT_DEBUG_VARIABLE
1898    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1899		     "variable not found %s\n", name));
1900#endif
1901    return(NULL);
1902}
1903
1904/**
1905 * xsltParseStylesheetCallerParam:
1906 * @ctxt:  the XSLT transformation context
1907 * @inst:  the xsl:with-param instruction element
1908 *
1909 * Processes an xsl:with-param instruction at transformation time.
1910 * The value is compute, but not recorded.
1911 * NOTE that this is also called with an *xsl:param* element
1912 * from exsltFuncFunctionFunction().
1913 *
1914 * Returns the new xsltStackElemPtr or NULL
1915 */
1916
1917xsltStackElemPtr
1918xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
1919{
1920#ifdef XSLT_REFACTORED
1921    xsltStyleBasicItemVariablePtr comp;
1922#else
1923    xsltStylePreCompPtr comp;
1924#endif
1925    xmlNodePtr tree = NULL; /* The first child node of the instruction or
1926                               the instruction itself. */
1927    xsltStackElemPtr param = NULL;
1928
1929    if ((ctxt == NULL) || (inst == NULL))
1930	return(NULL);
1931
1932#ifdef XSLT_REFACTORED
1933    comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
1934#else
1935    comp = (xsltStylePreCompPtr) inst->psvi;
1936#endif
1937
1938    if (comp == NULL) {
1939        xsltTransformError(ctxt, NULL, inst,
1940	    "Internal error in xsltParseStylesheetCallerParam(): "
1941	    "The XSLT 'with-param' instruction was not compiled.\n");
1942        return(NULL);
1943    }
1944    if (comp->name == NULL) {
1945	xsltTransformError(ctxt, NULL, inst,
1946	    "Internal error in xsltParseStylesheetCallerParam(): "
1947	    "XSLT 'with-param': The attribute 'name' was not compiled.\n");
1948	return(NULL);
1949    }
1950
1951#ifdef WITH_XSLT_DEBUG_VARIABLE
1952    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1953	    "Handling xsl:with-param %s\n", comp->name));
1954#endif
1955
1956    if (comp->select == NULL) {
1957	tree = inst->children;
1958    } else {
1959#ifdef WITH_XSLT_DEBUG_VARIABLE
1960	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1961	    "        select %s\n", comp->select));
1962#endif
1963	tree = inst;
1964    }
1965
1966    param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1967
1968    return(param);
1969}
1970
1971/**
1972 * xsltParseGlobalVariable:
1973 * @style:  the XSLT stylesheet
1974 * @cur:  the "variable" element
1975 *
1976 * Parses a global XSLT 'variable' declaration at compilation time
1977 * and registers it
1978 */
1979void
1980xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
1981{
1982#ifdef XSLT_REFACTORED
1983    xsltStyleItemVariablePtr comp;
1984#else
1985    xsltStylePreCompPtr comp;
1986#endif
1987
1988    if ((cur == NULL) || (style == NULL))
1989	return;
1990
1991#ifdef XSLT_REFACTORED
1992    /*
1993    * Note that xsltStylePreCompute() will be called from
1994    * xslt.c only.
1995    */
1996    comp = (xsltStyleItemVariablePtr) cur->psvi;
1997#else
1998    xsltStylePreCompute(style, cur);
1999    comp = (xsltStylePreCompPtr) cur->psvi;
2000#endif
2001    if (comp == NULL) {
2002	xsltTransformError(NULL, style, cur,
2003	     "xsl:variable : compilation failed\n");
2004	return;
2005    }
2006
2007    if (comp->name == NULL) {
2008	xsltTransformError(NULL, style, cur,
2009	    "xsl:variable : missing name attribute\n");
2010	return;
2011    }
2012
2013    /*
2014    * Parse the content (a sequence constructor) of xsl:variable.
2015    */
2016    if (cur->children != NULL) {
2017#ifdef XSLT_REFACTORED
2018        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2019#else
2020        xsltParseTemplateContent(style, cur);
2021#endif
2022    }
2023#ifdef WITH_XSLT_DEBUG_VARIABLE
2024    xsltGenericDebug(xsltGenericDebugContext,
2025	"Registering global variable %s\n", comp->name);
2026#endif
2027
2028    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2029	comp->select, cur->children, (xsltStylePreCompPtr) comp,
2030	NULL);
2031}
2032
2033/**
2034 * xsltParseGlobalParam:
2035 * @style:  the XSLT stylesheet
2036 * @cur:  the "param" element
2037 *
2038 * parse an XSLT transformation param declaration and record
2039 * its value.
2040 */
2041
2042void
2043xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
2044#ifdef XSLT_REFACTORED
2045    xsltStyleItemParamPtr comp;
2046#else
2047    xsltStylePreCompPtr comp;
2048#endif
2049
2050    if ((cur == NULL) || (style == NULL))
2051	return;
2052
2053#ifdef XSLT_REFACTORED
2054    /*
2055    * Note that xsltStylePreCompute() will be called from
2056    * xslt.c only.
2057    */
2058    comp = (xsltStyleItemParamPtr) cur->psvi;
2059#else
2060    xsltStylePreCompute(style, cur);
2061    comp = (xsltStylePreCompPtr) cur->psvi;
2062#endif
2063    if (comp == NULL) {
2064	xsltTransformError(NULL, style, cur,
2065	     "xsl:param : compilation failed\n");
2066	return;
2067    }
2068
2069    if (comp->name == NULL) {
2070	xsltTransformError(NULL, style, cur,
2071	    "xsl:param : missing name attribute\n");
2072	return;
2073    }
2074
2075    /*
2076    * Parse the content (a sequence constructor) of xsl:param.
2077    */
2078    if (cur->children != NULL) {
2079#ifdef XSLT_REFACTORED
2080        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2081#else
2082        xsltParseTemplateContent(style, cur);
2083#endif
2084    }
2085
2086#ifdef WITH_XSLT_DEBUG_VARIABLE
2087    xsltGenericDebug(xsltGenericDebugContext,
2088	"Registering global param %s\n", comp->name);
2089#endif
2090
2091    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2092	comp->select, cur->children, (xsltStylePreCompPtr) comp,
2093	NULL);
2094}
2095
2096/**
2097 * xsltParseStylesheetVariable:
2098 * @ctxt:  the XSLT transformation context
2099 * @inst:  the xsl:variable instruction element
2100 *
2101 * Registers a local XSLT 'variable' instruction at transformation time
2102 * and evaluates its value.
2103 */
2104void
2105xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
2106{
2107#ifdef XSLT_REFACTORED
2108    xsltStyleItemVariablePtr comp;
2109#else
2110    xsltStylePreCompPtr comp;
2111#endif
2112
2113    if ((inst == NULL) || (ctxt == NULL))
2114	return;
2115
2116    comp = inst->psvi;
2117    if (comp == NULL) {
2118        xsltTransformError(ctxt, NULL, inst,
2119	    "Internal error in xsltParseStylesheetVariable(): "
2120	    "The XSLT 'variable' instruction was not compiled.\n");
2121        return;
2122    }
2123    if (comp->name == NULL) {
2124	xsltTransformError(ctxt, NULL, inst,
2125	    "Internal error in xsltParseStylesheetVariable(): "
2126	    "The attribute 'name' was not compiled.\n");
2127	return;
2128    }
2129
2130#ifdef WITH_XSLT_DEBUG_VARIABLE
2131    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2132	"Registering variable '%s'\n", comp->name));
2133#endif
2134
2135    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
2136}
2137
2138/**
2139 * xsltParseStylesheetParam:
2140 * @ctxt:  the XSLT transformation context
2141 * @cur:  the XSLT 'param' element
2142 *
2143 * Registers a local XSLT 'param' declaration at transformation time and
2144 * evaluates its value.
2145 */
2146void
2147xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
2148{
2149#ifdef XSLT_REFACTORED
2150    xsltStyleItemParamPtr comp;
2151#else
2152    xsltStylePreCompPtr comp;
2153#endif
2154
2155    if ((cur == NULL) || (ctxt == NULL))
2156	return;
2157
2158    comp = cur->psvi;
2159    if ((comp == NULL) || (comp->name == NULL)) {
2160	xsltTransformError(ctxt, NULL, cur,
2161	    "Internal error in xsltParseStylesheetParam(): "
2162	    "The XSLT 'param' declaration was not compiled correctly.\n");
2163	return;
2164    }
2165
2166#ifdef WITH_XSLT_DEBUG_VARIABLE
2167    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2168	"Registering param %s\n", comp->name));
2169#endif
2170
2171    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
2172}
2173
2174/**
2175 * xsltFreeGlobalVariables:
2176 * @ctxt:  the XSLT transformation context
2177 *
2178 * Free up the data associated to the global variables
2179 * its value.
2180 */
2181
2182void
2183xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
2184    xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
2185}
2186
2187/**
2188 * xsltXPathVariableLookup:
2189 * @ctxt:  a void * but the the XSLT transformation context actually
2190 * @name:  the variable name
2191 * @ns_uri:  the variable namespace URI
2192 *
2193 * This is the entry point when a varibale is needed by the XPath
2194 * interpretor.
2195 *
2196 * Returns the value or NULL if not found
2197 */
2198xmlXPathObjectPtr
2199xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
2200	                const xmlChar *ns_uri) {
2201    xsltTransformContextPtr tctxt;
2202    xmlXPathObjectPtr valueObj = NULL;
2203
2204    if ((ctxt == NULL) || (name == NULL))
2205	return(NULL);
2206
2207#ifdef WITH_XSLT_DEBUG_VARIABLE
2208    XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2209	    "Lookup variable '%s'\n", name));
2210#endif
2211
2212    tctxt = (xsltTransformContextPtr) ctxt;
2213    /*
2214    * Local variables/params ---------------------------------------------
2215    *
2216    * Do the lookup from the top of the stack, but
2217    * don't use params being computed in a call-param
2218    * First lookup expects the variable name and URI to
2219    * come from the disctionnary and hence pointer comparison.
2220    */
2221    if (tctxt->varsNr != 0) {
2222	int i;
2223	xsltStackElemPtr variable = NULL, cur;
2224
2225	for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2226	    cur = tctxt->varsTab[i-1];
2227	    if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2228#if 0
2229		stack_addr++;
2230#endif
2231		variable = cur;
2232		goto local_variable_found;
2233	    }
2234	    cur = cur->next;
2235	}
2236	/*
2237	* Redo the lookup with interned strings to avoid string comparison.
2238	*
2239	* OPTIMIZE TODO: The problem here is, that if we request a
2240	*  global variable, then this will be also executed.
2241	*/
2242	{
2243	    const xmlChar *tmpName = name, *tmpNsName = ns_uri;
2244
2245	    name = xmlDictLookup(tctxt->dict, name, -1);
2246	    if (ns_uri)
2247		ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
2248	    if ((tmpName != name) || (tmpNsName != ns_uri)) {
2249		for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2250		    cur = tctxt->varsTab[i-1];
2251		    if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2252#if 0
2253			stack_cmp++;
2254#endif
2255			variable = cur;
2256			goto local_variable_found;
2257		    }
2258		}
2259	    }
2260	}
2261
2262local_variable_found:
2263
2264	if (variable) {
2265	    if (variable->computed == 0) {
2266
2267#ifdef WITH_XSLT_DEBUG_VARIABLE
2268		XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2269		    "uncomputed variable '%s'\n", name));
2270#endif
2271		variable->value = xsltEvalVariable(tctxt, variable, NULL);
2272		variable->computed = 1;
2273	    }
2274	    if (variable->value != NULL) {
2275		valueObj = xmlXPathObjectCopy(variable->value);
2276	    }
2277	    return(valueObj);
2278	}
2279    }
2280    /*
2281    * Global variables/params --------------------------------------------
2282    */
2283    if (tctxt->globalVars) {
2284	valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
2285    }
2286
2287    if (valueObj == NULL) {
2288
2289#ifdef WITH_XSLT_DEBUG_VARIABLE
2290    XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2291		     "variable not found '%s'\n", name));
2292#endif
2293
2294	if (ns_uri) {
2295	    xsltTransformError(tctxt, NULL, tctxt->inst,
2296		"Variable '{%s}%s' has not been declared.\n", ns_uri, name);
2297	} else {
2298	    xsltTransformError(tctxt, NULL, tctxt->inst,
2299		"Variable '%s' has not been declared.\n", name);
2300	}
2301    } else {
2302
2303#ifdef WITH_XSLT_DEBUG_VARIABLE
2304	XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2305	    "found variable '%s'\n", name));
2306#endif
2307    }
2308
2309    return(valueObj);
2310}
2311
2312
2313