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#ifdef XSLT_REFACTORED
679#else
680
681/**
682 * xsltCheckStackElem:
683 * @ctxt:  xn XSLT transformation context
684 * @name:  the variable name
685 * @nameURI:  the variable namespace URI
686 *
687 * Checks whether a variable or param is already defined.
688 *
689 * URGENT TODO: Checks for redefinition of vars/params should be
690 *  done only at compilation time.
691 *
692 * Returns 1 if variable is present, 2 if param is present, 3 if this
693 *         is an inherited param, 0 if not found, -1 in case of failure.
694 */
695static int
696xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
697	           const xmlChar *nameURI) {
698    xsltStackElemPtr cur;
699
700    if ((ctxt == NULL) || (name == NULL))
701	return(-1);
702
703    cur = xsltStackLookup(ctxt, name, nameURI);
704    if (cur == NULL)
705        return(0);
706    if (cur->comp != NULL) {
707        if (cur->comp->type == XSLT_FUNC_WITHPARAM)
708	    return(3);
709	else if (cur->comp->type == XSLT_FUNC_PARAM)
710	    return(2);
711    }
712
713    return(1);
714}
715
716#endif /* XSLT_REFACTORED */
717
718/**
719 * xsltAddStackElem:
720 * @ctxt:  xn XSLT transformation context
721 * @elem:  a stack element
722 *
723 * Push an element (or list) onto the stack.
724 * In case of a list, each member will be pushed into
725 * a seperate slot; i.e. there's always 1 stack entry for
726 * 1 stack element.
727 *
728 * Returns 0 in case of success, -1 in case of failure.
729 */
730static int
731xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
732{
733    if ((ctxt == NULL) || (elem == NULL))
734	return(-1);
735
736    do {
737	if (ctxt->varsMax == 0) {
738	    ctxt->varsMax = 10;
739	    ctxt->varsTab =
740		(xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
741		sizeof(ctxt->varsTab[0]));
742	    if (ctxt->varsTab == NULL) {
743		xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
744		return (-1);
745	    }
746	}
747	if (ctxt->varsNr >= ctxt->varsMax) {
748	    ctxt->varsMax *= 2;
749	    ctxt->varsTab =
750		(xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
751		ctxt->varsMax *
752		sizeof(ctxt->varsTab[0]));
753	    if (ctxt->varsTab == NULL) {
754		xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
755		return (-1);
756	    }
757	}
758	ctxt->varsTab[ctxt->varsNr++] = elem;
759	ctxt->vars = elem;
760
761	elem = elem->next;
762    } while (elem != NULL);
763
764    return(0);
765}
766
767/**
768 * xsltAddStackElemList:
769 * @ctxt:  xn XSLT transformation context
770 * @elems:  a stack element list
771 *
772 * Push an element list onto the stack.
773 *
774 * Returns 0 in case of success, -1 in case of failure.
775 */
776int
777xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
778{
779    return(xsltAddStackElem(ctxt, elems));
780}
781
782/************************************************************************
783 *									*
784 *			Module interfaces				*
785 *									*
786 ************************************************************************/
787
788/**
789 * xsltEvalVariable:
790 * @ctxt:  the XSLT transformation context
791 * @variable:  the variable or parameter item
792 * @comp: the compiled XSLT instruction
793 *
794 * Evaluate a variable value.
795 *
796 * Returns the XPath Object value or NULL in case of error
797 */
798static xmlXPathObjectPtr
799xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
800	         xsltStylePreCompPtr castedComp)
801{
802#ifdef XSLT_REFACTORED
803    xsltStyleItemVariablePtr comp =
804	(xsltStyleItemVariablePtr) castedComp;
805#else
806    xsltStylePreCompPtr comp = castedComp;
807#endif
808    xmlXPathObjectPtr result = NULL;
809    xmlNodePtr oldInst;
810
811    if ((ctxt == NULL) || (variable == NULL))
812	return(NULL);
813
814    /*
815    * A variable or parameter are evaluated on demand; thus the
816    * context (of XSLT and XPath) need to be temporarily adjusted and
817    * restored on exit.
818    */
819    oldInst = ctxt->inst;
820
821#ifdef WITH_XSLT_DEBUG_VARIABLE
822    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
823	"Evaluating variable '%s'\n", variable->name));
824#endif
825    if (variable->select != NULL) {
826	xmlXPathCompExprPtr xpExpr = NULL;
827	xmlDocPtr oldXPDoc;
828	xmlNodePtr oldXPContextNode;
829	int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
830	xmlNsPtr *oldXPNamespaces;
831	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
832	xsltStackElemPtr oldVar = ctxt->contextVariable;
833
834	if ((comp != NULL) && (comp->comp != NULL)) {
835	    xpExpr = comp->comp;
836	} else {
837	    xpExpr = xmlXPathCompile(variable->select);
838	}
839	if (xpExpr == NULL)
840	    return(NULL);
841	/*
842	* Save context states.
843	*/
844	oldXPDoc = xpctxt->doc;
845	oldXPContextNode = xpctxt->node;
846	oldXPProximityPosition = xpctxt->proximityPosition;
847	oldXPContextSize = xpctxt->contextSize;
848	oldXPNamespaces = xpctxt->namespaces;
849	oldXPNsNr = xpctxt->nsNr;
850
851	xpctxt->node = ctxt->node;
852	/*
853	* OPTIMIZE TODO: Lame try to set the context doc.
854	*   Get rid of this somehow in xpath.c.
855	*/
856	if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
857	    ctxt->node->doc)
858	    xpctxt->doc = ctxt->node->doc;
859	/*
860	* BUG TODO: The proximity position and the context size will
861	*  potentially be wrong.
862	*  Example:
863	*  <xsl:template select="foo">
864	*    <xsl:variable name="pos" select="position()"/>
865	*    <xsl:for-each select="bar">
866	*      <xsl:value-of select="$pos"/>
867	*    </xsl:for-each>
868	*  </xsl:template>
869	*  Here the proximity position and context size are changed
870	*  to the context of <xsl:for-each select="bar">, but
871	*  the variable needs to be evaluated in the context of
872	*  <xsl:template select="foo">.
873	*/
874	if (comp != NULL) {
875
876#ifdef XSLT_REFACTORED
877	    if (comp->inScopeNs != NULL) {
878		xpctxt->namespaces = comp->inScopeNs->list;
879		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
880	    } else {
881		xpctxt->namespaces = NULL;
882		xpctxt->nsNr = 0;
883	    }
884#else
885	    xpctxt->namespaces = comp->nsList;
886	    xpctxt->nsNr = comp->nsNr;
887#endif
888	} else {
889	    xpctxt->namespaces = NULL;
890	    xpctxt->nsNr = 0;
891	}
892
893	/*
894	* We need to mark that we are "selecting" a var's value;
895	* if any tree fragments are created inside the expression,
896	* then those need to be stored inside the variable; otherwise
897	* we'll eventually free still referenced fragments, before
898	* we leave the scope of the variable.
899	*/
900	ctxt->contextVariable = variable;
901	variable->flags |= XSLT_VAR_IN_SELECT;
902
903	result = xmlXPathCompiledEval(xpExpr, xpctxt);
904
905	variable->flags ^= XSLT_VAR_IN_SELECT;
906	/*
907	* Restore Context states.
908	*/
909	ctxt->contextVariable = oldVar;
910
911	xpctxt->doc = oldXPDoc;
912	xpctxt->node = oldXPContextNode;
913	xpctxt->contextSize = oldXPContextSize;
914	xpctxt->proximityPosition = oldXPProximityPosition;
915	xpctxt->namespaces = oldXPNamespaces;
916	xpctxt->nsNr = oldXPNsNr;
917
918	if ((comp == NULL) || (comp->comp == NULL))
919	    xmlXPathFreeCompExpr(xpExpr);
920	if (result == NULL) {
921	    xsltTransformError(ctxt, NULL,
922		(comp != NULL) ? comp->inst : NULL,
923		"Failed to evaluate the expression of variable '%s'.\n",
924		variable->name);
925	    ctxt->state = XSLT_STATE_STOPPED;
926
927#ifdef WITH_XSLT_DEBUG_VARIABLE
928#ifdef LIBXML_DEBUG_ENABLED
929	} else {
930	    if ((xsltGenericDebugContext == stdout) ||
931		(xsltGenericDebugContext == stderr))
932		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
933					result, 0);
934#endif
935#endif
936	}
937    } else {
938	if (variable->tree == NULL) {
939	    result = xmlXPathNewCString("");
940	} else {
941	    if (variable->tree) {
942		xmlDocPtr container;
943		xmlNodePtr oldInsert;
944		xmlDocPtr  oldOutput;
945		xsltStackElemPtr oldVar = ctxt->contextVariable;
946
947		/*
948		* Generate a result tree fragment.
949		*/
950		container = xsltCreateRVT(ctxt);
951		if (container == NULL)
952		    goto error;
953		/*
954		* NOTE: Local Result Tree Fragments of params/variables
955		* are not registered globally anymore; the life-time
956		* is not directly dependant of the param/variable itself.
957		*
958		* OLD: xsltRegisterTmpRVT(ctxt, container);
959		*/
960		/*
961		* Attach the Result Tree Fragment to the variable;
962		* when the variable is freed, it will also free
963		* the Result Tree Fragment.
964		*/
965		variable->fragment = container;
966
967		oldOutput = ctxt->output;
968		oldInsert = ctxt->insert;
969
970		ctxt->output = container;
971		ctxt->insert = (xmlNodePtr) container;
972		ctxt->contextVariable = variable;
973		/*
974		* Process the sequence constructor (variable->tree).
975		* The resulting tree will be held by @container.
976		*/
977		xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
978		    NULL, NULL);
979
980		ctxt->contextVariable = oldVar;
981		ctxt->insert = oldInsert;
982		ctxt->output = oldOutput;
983
984		result = xmlXPathNewValueTree((xmlNodePtr) container);
985	    }
986	    if (result == NULL) {
987		result = xmlXPathNewCString("");
988	    } else {
989		/*
990		* Freeing is not handled there anymore.
991		* QUESTION TODO: What does the above comment mean?
992		*/
993	        result->boolval = 0;
994	    }
995#ifdef WITH_XSLT_DEBUG_VARIABLE
996#ifdef LIBXML_DEBUG_ENABLED
997
998	    if ((xsltGenericDebugContext == stdout) ||
999		(xsltGenericDebugContext == stderr))
1000		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1001					result, 0);
1002#endif
1003#endif
1004	}
1005    }
1006
1007error:
1008    ctxt->inst = oldInst;
1009    return(result);
1010}
1011
1012/**
1013 * xsltEvalGlobalVariable:
1014 * @elem:  the variable or parameter
1015 * @ctxt:  the XSLT transformation context
1016 *
1017 * Evaluates a the value of a global xsl:variable or
1018 * xsl:param declaration.
1019 *
1020 * Returns the XPath Object value or NULL in case of error
1021 */
1022static xmlXPathObjectPtr
1023xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
1024{
1025    xmlXPathObjectPtr result = NULL;
1026    xmlNodePtr oldInst;
1027    const xmlChar* oldVarName;
1028
1029#ifdef XSLT_REFACTORED
1030    xsltStyleBasicItemVariablePtr comp;
1031#else
1032    xsltStylePreCompPtr comp;
1033#endif
1034
1035    if ((ctxt == NULL) || (elem == NULL))
1036	return(NULL);
1037    if (elem->computed)
1038	return(elem->value);
1039
1040
1041#ifdef WITH_XSLT_DEBUG_VARIABLE
1042    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1043	"Evaluating global variable %s\n", elem->name));
1044#endif
1045
1046#ifdef WITH_DEBUGGER
1047    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
1048        elem->comp && elem->comp->inst)
1049        xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
1050#endif
1051
1052    oldInst = ctxt->inst;
1053#ifdef XSLT_REFACTORED
1054    comp = (xsltStyleBasicItemVariablePtr) elem->comp;
1055#else
1056    comp = elem->comp;
1057#endif
1058    oldVarName = elem->name;
1059    elem->name = xsltComputingGlobalVarMarker;
1060    /*
1061    * OPTIMIZE TODO: We should consider instantiating global vars/params
1062    *  on-demand. The vars/params don't need to be evaluated if never
1063    *  called; and in the case of global params, if values for such params
1064    *  are provided by the user.
1065    */
1066    if (elem->select != NULL) {
1067	xmlXPathCompExprPtr xpExpr = NULL;
1068	xmlDocPtr oldXPDoc;
1069	xmlNodePtr oldXPContextNode;
1070	int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1071	xmlNsPtr *oldXPNamespaces;
1072	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1073
1074	if ((comp != NULL) && (comp->comp != NULL)) {
1075	    xpExpr = comp->comp;
1076	} else {
1077	    xpExpr = xmlXPathCompile(elem->select);
1078	}
1079	if (xpExpr == NULL)
1080	    goto error;
1081
1082
1083	if (comp != NULL)
1084	    ctxt->inst = comp->inst;
1085	else
1086	    ctxt->inst = NULL;
1087	/*
1088	* SPEC XSLT 1.0:
1089	* "At top-level, the expression or template specifying the
1090	*  variable value is evaluated with the same context as that used
1091	*  to process the root node of the source document: the current
1092	*  node is the root node of the source document and the current
1093	*  node list is a list containing just the root node of the source
1094	*  document."
1095	*/
1096	/*
1097	* Save context states.
1098	*/
1099	oldXPDoc = xpctxt->doc;
1100	oldXPContextNode = xpctxt->node;
1101	oldXPProximityPosition = xpctxt->proximityPosition;
1102	oldXPContextSize = xpctxt->contextSize;
1103	oldXPNamespaces = xpctxt->namespaces;
1104	oldXPNsNr = xpctxt->nsNr;
1105
1106	xpctxt->node = ctxt->initialContextNode;
1107	xpctxt->doc = ctxt->initialContextDoc;
1108	xpctxt->contextSize = 1;
1109	xpctxt->proximityPosition = 1;
1110
1111	if (comp != NULL) {
1112
1113#ifdef XSLT_REFACTORED
1114	    if (comp->inScopeNs != NULL) {
1115		xpctxt->namespaces = comp->inScopeNs->list;
1116		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
1117	    } else {
1118		xpctxt->namespaces = NULL;
1119		xpctxt->nsNr = 0;
1120	    }
1121#else
1122	    xpctxt->namespaces = comp->nsList;
1123	    xpctxt->nsNr = comp->nsNr;
1124#endif
1125	} else {
1126	    xpctxt->namespaces = NULL;
1127	    xpctxt->nsNr = 0;
1128	}
1129
1130	result = xmlXPathCompiledEval(xpExpr, xpctxt);
1131
1132	/*
1133	* Restore Context states.
1134	*/
1135	xpctxt->doc = oldXPDoc;
1136	xpctxt->node = oldXPContextNode;
1137	xpctxt->contextSize = oldXPContextSize;
1138	xpctxt->proximityPosition = oldXPProximityPosition;
1139	xpctxt->namespaces = oldXPNamespaces;
1140	xpctxt->nsNr = oldXPNsNr;
1141
1142	if ((comp == NULL) || (comp->comp == NULL))
1143	    xmlXPathFreeCompExpr(xpExpr);
1144	if (result == NULL) {
1145	    if (comp == NULL)
1146		xsltTransformError(ctxt, NULL, NULL,
1147		    "Evaluating global variable %s failed\n", elem->name);
1148	    else
1149		xsltTransformError(ctxt, NULL, comp->inst,
1150		    "Evaluating global variable %s failed\n", elem->name);
1151	    ctxt->state = XSLT_STATE_STOPPED;
1152#ifdef WITH_XSLT_DEBUG_VARIABLE
1153#ifdef LIBXML_DEBUG_ENABLED
1154	} else {
1155	    if ((xsltGenericDebugContext == stdout) ||
1156		(xsltGenericDebugContext == stderr))
1157		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1158					result, 0);
1159#endif
1160#endif
1161	}
1162    } else {
1163	if (elem->tree == NULL) {
1164	    result = xmlXPathNewCString("");
1165	} else {
1166	    xmlDocPtr container;
1167	    xmlNodePtr oldInsert;
1168	    xmlDocPtr  oldOutput, oldXPDoc;
1169	    /*
1170	    * Generate a result tree fragment.
1171	    */
1172	    container = xsltCreateRVT(ctxt);
1173	    if (container == NULL)
1174		goto error;
1175	    /*
1176	    * Let the lifetime of the tree fragment be handled by
1177	    * the Libxslt's garbage collector.
1178	    */
1179	    xsltRegisterPersistRVT(ctxt, container);
1180
1181	    oldOutput = ctxt->output;
1182	    oldInsert = ctxt->insert;
1183
1184	    oldXPDoc = ctxt->xpathCtxt->doc;
1185
1186	    ctxt->output = container;
1187	    ctxt->insert = (xmlNodePtr) container;
1188
1189	    ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
1190	    /*
1191	    * Process the sequence constructor.
1192	    */
1193	    xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
1194
1195	    ctxt->xpathCtxt->doc = oldXPDoc;
1196
1197	    ctxt->insert = oldInsert;
1198	    ctxt->output = oldOutput;
1199
1200	    result = xmlXPathNewValueTree((xmlNodePtr) container);
1201	    if (result == NULL) {
1202		result = xmlXPathNewCString("");
1203	    } else {
1204	        result->boolval = 0; /* Freeing is not handled there anymore */
1205	    }
1206#ifdef WITH_XSLT_DEBUG_VARIABLE
1207#ifdef LIBXML_DEBUG_ENABLED
1208	    if ((xsltGenericDebugContext == stdout) ||
1209		(xsltGenericDebugContext == stderr))
1210		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1211					result, 0);
1212#endif
1213#endif
1214	}
1215    }
1216
1217error:
1218    elem->name = oldVarName;
1219    ctxt->inst = oldInst;
1220    if (result != NULL) {
1221	elem->value = result;
1222	elem->computed = 1;
1223    }
1224    return(result);
1225}
1226
1227/**
1228 * xsltEvalGlobalVariables:
1229 * @ctxt:  the XSLT transformation context
1230 *
1231 * Evaluates all global variables and parameters of a stylesheet.
1232 * For internal use only. This is called at start of a transformation.
1233 *
1234 * Returns 0 in case of success, -1 in case of error
1235 */
1236int
1237xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
1238    xsltStackElemPtr elem;
1239    xsltStylesheetPtr style;
1240
1241    if ((ctxt == NULL) || (ctxt->document == NULL))
1242	return(-1);
1243
1244#ifdef WITH_XSLT_DEBUG_VARIABLE
1245    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1246	"Registering global variables\n"));
1247#endif
1248    /*
1249     * Walk the list from the stylesheets and populate the hash table
1250     */
1251    style = ctxt->style;
1252    while (style != NULL) {
1253	elem = style->variables;
1254
1255#ifdef WITH_XSLT_DEBUG_VARIABLE
1256	if ((style->doc != NULL) && (style->doc->URL != NULL)) {
1257	    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1258			     "Registering global variables from %s\n",
1259		             style->doc->URL));
1260	}
1261#endif
1262
1263	while (elem != NULL) {
1264	    xsltStackElemPtr def;
1265
1266	    /*
1267	     * Global variables are stored in the variables pool.
1268	     */
1269	    def = (xsltStackElemPtr)
1270		    xmlHashLookup2(ctxt->globalVars,
1271		                 elem->name, elem->nameURI);
1272	    if (def == NULL) {
1273
1274		def = xsltCopyStackElem(elem);
1275		xmlHashAddEntry2(ctxt->globalVars,
1276				 elem->name, elem->nameURI, def);
1277	    } else if ((elem->comp != NULL) &&
1278		       (elem->comp->type == XSLT_FUNC_VARIABLE)) {
1279		/*
1280		 * Redefinition of variables from a different stylesheet
1281		 * should not generate a message.
1282		 */
1283		if ((elem->comp->inst != NULL) &&
1284		    (def->comp != NULL) && (def->comp->inst != NULL) &&
1285		    (elem->comp->inst->doc == def->comp->inst->doc))
1286		{
1287		    xsltTransformError(ctxt, style, elem->comp->inst,
1288			"Global variable %s already defined\n", elem->name);
1289		    if (style != NULL) style->errors++;
1290		}
1291	    }
1292	    elem = elem->next;
1293	}
1294
1295	style = xsltNextImport(style);
1296    }
1297
1298    /*
1299     * This part does the actual evaluation
1300     */
1301    xmlHashScan(ctxt->globalVars,
1302	        (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
1303
1304    return(0);
1305}
1306
1307/**
1308 * xsltRegisterGlobalVariable:
1309 * @style:  the XSLT transformation context
1310 * @name:  the variable name
1311 * @ns_uri:  the variable namespace URI
1312 * @sel:  the expression which need to be evaluated to generate a value
1313 * @tree:  the subtree if sel is NULL
1314 * @comp:  the precompiled value
1315 * @value:  the string value if available
1316 *
1317 * Register a new variable value. If @value is NULL it unregisters
1318 * the variable
1319 *
1320 * Returns 0 in case of success, -1 in case of error
1321 */
1322static int
1323xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
1324		     const xmlChar *ns_uri, const xmlChar *sel,
1325		     xmlNodePtr tree, xsltStylePreCompPtr comp,
1326		     const xmlChar *value) {
1327    xsltStackElemPtr elem, tmp;
1328    if (style == NULL)
1329	return(-1);
1330    if (name == NULL)
1331	return(-1);
1332    if (comp == NULL)
1333	return(-1);
1334
1335#ifdef WITH_XSLT_DEBUG_VARIABLE
1336    if (comp->type == XSLT_FUNC_PARAM)
1337	xsltGenericDebug(xsltGenericDebugContext,
1338			 "Defining global param %s\n", name);
1339    else
1340	xsltGenericDebug(xsltGenericDebugContext,
1341			 "Defining global variable %s\n", name);
1342#endif
1343
1344    elem = xsltNewStackElem(NULL);
1345    if (elem == NULL)
1346	return(-1);
1347    elem->comp = comp;
1348    elem->name = xmlDictLookup(style->dict, name, -1);
1349    elem->select = xmlDictLookup(style->dict, sel, -1);
1350    if (ns_uri)
1351	elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
1352    elem->tree = tree;
1353    tmp = style->variables;
1354    if (tmp == NULL) {
1355	elem->next = NULL;
1356	style->variables = elem;
1357    } else {
1358	while (tmp != NULL) {
1359	    if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
1360		(tmp->comp->type == XSLT_FUNC_VARIABLE) &&
1361		(xmlStrEqual(elem->name, tmp->name)) &&
1362		((elem->nameURI == tmp->nameURI) ||
1363		 (xmlStrEqual(elem->nameURI, tmp->nameURI))))
1364	    {
1365		xsltTransformError(NULL, style, comp->inst,
1366		"redefinition of global variable %s\n", elem->name);
1367		style->errors++;
1368	    }
1369	    if (tmp->next == NULL)
1370	        break;
1371	    tmp = tmp->next;
1372	}
1373	elem->next = NULL;
1374	tmp->next = elem;
1375    }
1376    if (value != NULL) {
1377	elem->computed = 1;
1378	elem->value = xmlXPathNewString(value);
1379    }
1380    return(0);
1381}
1382
1383/**
1384 * xsltProcessUserParamInternal
1385 *
1386 * @ctxt:  the XSLT transformation context
1387 * @name:  a null terminated parameter name
1388 * @value: a null terminated value (may be an XPath expression)
1389 * @eval:  0 to treat the value literally, else evaluate as XPath expression
1390 *
1391 * If @eval is 0 then @value is treated literally and is stored in the global
1392 * parameter/variable table without any change.
1393 *
1394 * Uf @eval is 1 then @value is treated as an XPath expression and is
1395 * evaluated.  In this case, if you want to pass a string which will be
1396 * interpreted literally then it must be enclosed in single or double quotes.
1397 * If the string contains single quotes (double quotes) then it cannot be
1398 * enclosed single quotes (double quotes).  If the string which you want to
1399 * be treated literally contains both single and double quotes (e.g. Meet
1400 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1401 * quoting character.  You cannot use &apos; or &quot; inside the string
1402 * because the replacement of character entities with their equivalents is
1403 * done at a different stage of processing.  The solution is to call
1404 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1405 *
1406 * This needs to be done on parsed stylesheets before starting to apply
1407 * transformations.  Normally this will be called (directly or indirectly)
1408 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1409 * or xsltQuoteOneUserParam.
1410 *
1411 * Returns 0 in case of success, -1 in case of error
1412 */
1413
1414static
1415int
1416xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
1417		             const xmlChar * name,
1418			     const xmlChar * value,
1419			     int eval) {
1420
1421    xsltStylesheetPtr style;
1422    const xmlChar *prefix;
1423    const xmlChar *href;
1424    xmlXPathCompExprPtr xpExpr;
1425    xmlXPathObjectPtr result;
1426
1427    xsltStackElemPtr elem;
1428    int res;
1429    void *res_ptr;
1430
1431    if (ctxt == NULL)
1432	return(-1);
1433    if (name == NULL)
1434	return(0);
1435    if (value == NULL)
1436	return(0);
1437
1438    style = ctxt->style;
1439
1440#ifdef WITH_XSLT_DEBUG_VARIABLE
1441    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1442	    "Evaluating user parameter %s=%s\n", name, value));
1443#endif
1444
1445    /*
1446     * Name lookup
1447     */
1448
1449    name = xsltSplitQName(ctxt->dict, name, &prefix);
1450    href = NULL;
1451    if (prefix != NULL) {
1452	xmlNsPtr ns;
1453
1454	ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
1455			 prefix);
1456	if (ns == NULL) {
1457	    xsltTransformError(ctxt, style, NULL,
1458	    "user param : no namespace bound to prefix %s\n", prefix);
1459	    href = NULL;
1460	} else {
1461	    href = ns->href;
1462	}
1463    }
1464
1465    if (name == NULL)
1466	return (-1);
1467
1468    res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
1469    if (res_ptr != 0) {
1470	xsltTransformError(ctxt, style, NULL,
1471	    "Global parameter %s already defined\n", name);
1472    }
1473    if (ctxt->globalVars == NULL)
1474	ctxt->globalVars = xmlHashCreate(20);
1475
1476    /*
1477     * do not overwrite variables with parameters from the command line
1478     */
1479    while (style != NULL) {
1480        elem = ctxt->style->variables;
1481	while (elem != NULL) {
1482	    if ((elem->comp != NULL) &&
1483	        (elem->comp->type == XSLT_FUNC_VARIABLE) &&
1484		(xmlStrEqual(elem->name, name)) &&
1485		(xmlStrEqual(elem->nameURI, href))) {
1486		return(0);
1487	    }
1488            elem = elem->next;
1489	}
1490        style = xsltNextImport(style);
1491    }
1492    style = ctxt->style;
1493    elem = NULL;
1494
1495    /*
1496     * Do the evaluation if @eval is non-zero.
1497     */
1498
1499    result = NULL;
1500    if (eval != 0) {
1501        xpExpr = xmlXPathCompile(value);
1502	if (xpExpr != NULL) {
1503	    xmlDocPtr oldXPDoc;
1504	    xmlNodePtr oldXPContextNode;
1505	    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1506	    xmlNsPtr *oldXPNamespaces;
1507	    xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1508
1509	    /*
1510	    * Save context states.
1511	    */
1512	    oldXPDoc = xpctxt->doc;
1513	    oldXPContextNode = xpctxt->node;
1514	    oldXPProximityPosition = xpctxt->proximityPosition;
1515	    oldXPContextSize = xpctxt->contextSize;
1516	    oldXPNamespaces = xpctxt->namespaces;
1517	    oldXPNsNr = xpctxt->nsNr;
1518
1519	    /*
1520	    * SPEC XSLT 1.0:
1521	    * "At top-level, the expression or template specifying the
1522	    *  variable value is evaluated with the same context as that used
1523	    *  to process the root node of the source document: the current
1524	    *  node is the root node of the source document and the current
1525	    *  node list is a list containing just the root node of the source
1526	    *  document."
1527	    */
1528	    xpctxt->doc = ctxt->initialContextDoc;
1529	    xpctxt->node = ctxt->initialContextNode;
1530	    xpctxt->contextSize = 1;
1531	    xpctxt->proximityPosition = 1;
1532	    /*
1533	    * There is really no in scope namespace for parameters on the
1534	    * command line.
1535	    */
1536	    xpctxt->namespaces = NULL;
1537	    xpctxt->nsNr = 0;
1538
1539	    result = xmlXPathCompiledEval(xpExpr, xpctxt);
1540
1541	    /*
1542	    * Restore Context states.
1543	    */
1544	    xpctxt->doc = oldXPDoc;
1545	    xpctxt->node = oldXPContextNode;
1546	    xpctxt->contextSize = oldXPContextSize;
1547	    xpctxt->proximityPosition = oldXPProximityPosition;
1548	    xpctxt->namespaces = oldXPNamespaces;
1549	    xpctxt->nsNr = oldXPNsNr;
1550
1551	    xmlXPathFreeCompExpr(xpExpr);
1552	}
1553	if (result == NULL) {
1554	    xsltTransformError(ctxt, style, NULL,
1555		"Evaluating user parameter %s failed\n", name);
1556	    ctxt->state = XSLT_STATE_STOPPED;
1557	    return(-1);
1558	}
1559    }
1560
1561    /*
1562     * If @eval is 0 then @value is to be taken literally and result is NULL
1563     *
1564     * If @eval is not 0, then @value is an XPath expression and has been
1565     * successfully evaluated and result contains the resulting value and
1566     * is not NULL.
1567     *
1568     * Now create an xsltStackElemPtr for insertion into the context's
1569     * global variable/parameter hash table.
1570     */
1571
1572#ifdef WITH_XSLT_DEBUG_VARIABLE
1573#ifdef LIBXML_DEBUG_ENABLED
1574    if ((xsltGenericDebugContext == stdout) ||
1575        (xsltGenericDebugContext == stderr))
1576	    xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1577				    result, 0);
1578#endif
1579#endif
1580
1581    elem = xsltNewStackElem(NULL);
1582    if (elem != NULL) {
1583	elem->name = name;
1584	elem->select = xmlDictLookup(ctxt->dict, value, -1);
1585	if (href != NULL)
1586	    elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1587	elem->tree = NULL;
1588	elem->computed = 1;
1589	if (eval == 0) {
1590	    elem->value = xmlXPathNewString(value);
1591	}
1592	else {
1593	    elem->value = result;
1594	}
1595    }
1596
1597    /*
1598     * Global parameters are stored in the XPath context variables pool.
1599     */
1600
1601    res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1602    if (res != 0) {
1603	xsltFreeStackElem(elem);
1604	xsltTransformError(ctxt, style, NULL,
1605	    "Global parameter %s already defined\n", name);
1606    }
1607    return(0);
1608}
1609
1610/**
1611 * xsltEvalUserParams:
1612 *
1613 * @ctxt:  the XSLT transformation context
1614 * @params:  a NULL terminated array of parameters name/value tuples
1615 *
1616 * Evaluate the global variables of a stylesheet. This needs to be
1617 * done on parsed stylesheets before starting to apply transformations.
1618 * Each of the parameters is evaluated as an XPath expression and stored
1619 * in the global variables/parameter hash table.  If you want your
1620 * parameter used literally, use xsltQuoteUserParams.
1621 *
1622 * Returns 0 in case of success, -1 in case of error
1623 */
1624
1625int
1626xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1627    int indx = 0;
1628    const xmlChar *name;
1629    const xmlChar *value;
1630
1631    if (params == NULL)
1632	return(0);
1633    while (params[indx] != NULL) {
1634	name = (const xmlChar *) params[indx++];
1635	value = (const xmlChar *) params[indx++];
1636	if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1637	    return(-1);
1638    }
1639    return 0;
1640}
1641
1642/**
1643 * xsltQuoteUserParams:
1644 *
1645 * @ctxt:  the XSLT transformation context
1646 * @params:  a NULL terminated arry of parameters names/values tuples
1647 *
1648 * Similar to xsltEvalUserParams, but the values are treated literally and
1649 * are * *not* evaluated as XPath expressions. This should be done on parsed
1650 * stylesheets before starting to apply transformations.
1651 *
1652 * Returns 0 in case of success, -1 in case of error.
1653 */
1654
1655int
1656xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1657    int indx = 0;
1658    const xmlChar *name;
1659    const xmlChar *value;
1660
1661    if (params == NULL)
1662	return(0);
1663    while (params[indx] != NULL) {
1664	name = (const xmlChar *) params[indx++];
1665	value = (const xmlChar *) params[indx++];
1666	if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1667	    return(-1);
1668    }
1669    return 0;
1670}
1671
1672/**
1673 * xsltEvalOneUserParam:
1674 * @ctxt:  the XSLT transformation context
1675 * @name:  a null terminated string giving the name of the parameter
1676 * @value:  a null terminated string giving the XPath expression to be evaluated
1677 *
1678 * This is normally called from xsltEvalUserParams to process a single
1679 * parameter from a list of parameters.  The @value is evaluated as an
1680 * XPath expression and the result is stored in the context's global
1681 * variable/parameter hash table.
1682 *
1683 * To have a parameter treated literally (not as an XPath expression)
1684 * use xsltQuoteUserParams (or xsltQuoteOneUserParam).  For more
1685 * details see description of xsltProcessOneUserParamInternal.
1686 *
1687 * Returns 0 in case of success, -1 in case of error.
1688 */
1689
1690int
1691xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1692		     const xmlChar * name,
1693		     const xmlChar * value) {
1694    return xsltProcessUserParamInternal(ctxt, name, value,
1695		                        1 /* xpath eval ? */);
1696}
1697
1698/**
1699 * xsltQuoteOneUserParam:
1700 * @ctxt:  the XSLT transformation context
1701 * @name:  a null terminated string giving the name of the parameter
1702 * @value:  a null terminated string giving the parameter value
1703 *
1704 * This is normally called from xsltQuoteUserParams to process a single
1705 * parameter from a list of parameters.  The @value is stored in the
1706 * context's global variable/parameter hash table.
1707 *
1708 * Returns 0 in case of success, -1 in case of error.
1709 */
1710
1711int
1712xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1713			 const xmlChar * name,
1714			 const xmlChar * value) {
1715    return xsltProcessUserParamInternal(ctxt, name, value,
1716					0 /* xpath eval ? */);
1717}
1718
1719/**
1720 * xsltBuildVariable:
1721 * @ctxt:  the XSLT transformation context
1722 * @comp:  the precompiled form
1723 * @tree:  the tree if select is NULL
1724 *
1725 * Computes a new variable value.
1726 *
1727 * Returns the xsltStackElemPtr or NULL in case of error
1728 */
1729static xsltStackElemPtr
1730xsltBuildVariable(xsltTransformContextPtr ctxt,
1731		  xsltStylePreCompPtr castedComp,
1732		  xmlNodePtr tree)
1733{
1734#ifdef XSLT_REFACTORED
1735    xsltStyleBasicItemVariablePtr comp =
1736	(xsltStyleBasicItemVariablePtr) castedComp;
1737#else
1738    xsltStylePreCompPtr comp = castedComp;
1739#endif
1740    xsltStackElemPtr elem;
1741
1742#ifdef WITH_XSLT_DEBUG_VARIABLE
1743    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1744		     "Building variable %s", comp->name));
1745    if (comp->select != NULL)
1746	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1747			 " select %s", comp->select));
1748    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1749#endif
1750
1751    elem = xsltNewStackElem(ctxt);
1752    if (elem == NULL)
1753	return(NULL);
1754    elem->comp = (xsltStylePreCompPtr) comp;
1755    elem->name = comp->name;
1756    elem->select = comp->select;
1757    elem->nameURI = comp->ns;
1758    elem->tree = tree;
1759    elem->value = xsltEvalVariable(ctxt, elem,
1760	(xsltStylePreCompPtr) comp);
1761    if (elem->value != NULL)
1762	elem->computed = 1;
1763    return(elem);
1764}
1765
1766/**
1767 * xsltRegisterVariable:
1768 * @ctxt:  the XSLT transformation context
1769 * @comp: the compiled XSLT-variable (or param) instruction
1770 * @tree:  the tree if select is NULL
1771 * @isParam:  indicates if this is a parameter
1772 *
1773 * Computes and registers a new variable.
1774 *
1775 * Returns 0 in case of success, -1 in case of error
1776 */
1777static int
1778xsltRegisterVariable(xsltTransformContextPtr ctxt,
1779		     xsltStylePreCompPtr castedComp,
1780		     xmlNodePtr tree, int isParam)
1781{
1782#ifdef XSLT_REFACTORED
1783    xsltStyleBasicItemVariablePtr comp =
1784	(xsltStyleBasicItemVariablePtr) castedComp;
1785#else
1786    xsltStylePreCompPtr comp = castedComp;
1787    int present;
1788#endif
1789    xsltStackElemPtr variable;
1790
1791#ifdef XSLT_REFACTORED
1792    /*
1793    * REFACTORED NOTE: Redefinitions of vars/params are checked
1794    *  at compilation time in the refactored code.
1795    * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1796    */
1797#else
1798    present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1799    if (isParam == 0) {
1800	if ((present != 0) && (present != 3)) {
1801	    /* TODO: report QName. */
1802	    xsltTransformError(ctxt, NULL, comp->inst,
1803		"XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
1804	    return(0);
1805	}
1806    } else if (present != 0) {
1807	if ((present == 1) || (present == 2)) {
1808	    /* TODO: report QName. */
1809	    xsltTransformError(ctxt, NULL, comp->inst,
1810		"XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
1811	    return(0);
1812	}
1813#ifdef WITH_XSLT_DEBUG_VARIABLE
1814	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1815		 "param %s defined by caller\n", comp->name));
1816#endif
1817	return(0);
1818    }
1819#endif /* else of XSLT_REFACTORED */
1820
1821    variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1822    xsltAddStackElem(ctxt, variable);
1823    return(0);
1824}
1825
1826/**
1827 * xsltGlobalVariableLookup:
1828 * @ctxt:  the XSLT transformation context
1829 * @name:  the variable name
1830 * @ns_uri:  the variable namespace URI
1831 *
1832 * Search in the Variable array of the context for the given
1833 * variable value.
1834 *
1835 * Returns the value or NULL if not found
1836 */
1837static xmlXPathObjectPtr
1838xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1839		         const xmlChar *ns_uri) {
1840    xsltStackElemPtr elem;
1841    xmlXPathObjectPtr ret = NULL;
1842
1843    /*
1844     * Lookup the global variables in XPath global variable hash table
1845     */
1846    if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1847	return(NULL);
1848    elem = (xsltStackElemPtr)
1849	    xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1850    if (elem == NULL) {
1851#ifdef WITH_XSLT_DEBUG_VARIABLE
1852	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1853			 "global variable not found %s\n", name));
1854#endif
1855	return(NULL);
1856    }
1857    /*
1858    * URGENT TODO: Move the detection of recursive definitions
1859    * to compile-time.
1860    */
1861    if (elem->computed == 0) {
1862	if (elem->name == xsltComputingGlobalVarMarker) {
1863	    xsltTransformError(ctxt, NULL, elem->comp->inst,
1864		"Recursive definition of %s\n", name);
1865	    return(NULL);
1866	}
1867	ret = xsltEvalGlobalVariable(elem, ctxt);
1868    } else
1869	ret = elem->value;
1870    return(xmlXPathObjectCopy(ret));
1871}
1872
1873/**
1874 * xsltVariableLookup:
1875 * @ctxt:  the XSLT transformation context
1876 * @name:  the variable name
1877 * @ns_uri:  the variable namespace URI
1878 *
1879 * Search in the Variable array of the context for the given
1880 * variable value.
1881 *
1882 * Returns the value or NULL if not found
1883 */
1884xmlXPathObjectPtr
1885xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1886		   const xmlChar *ns_uri) {
1887    xsltStackElemPtr elem;
1888
1889    if (ctxt == NULL)
1890	return(NULL);
1891
1892    elem = xsltStackLookup(ctxt, name, ns_uri);
1893    if (elem == NULL) {
1894	return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1895    }
1896    if (elem->computed == 0) {
1897#ifdef WITH_XSLT_DEBUG_VARIABLE
1898	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1899		         "uncomputed variable %s\n", name));
1900#endif
1901        elem->value = xsltEvalVariable(ctxt, elem, NULL);
1902	elem->computed = 1;
1903    }
1904    if (elem->value != NULL)
1905	return(xmlXPathObjectCopy(elem->value));
1906#ifdef WITH_XSLT_DEBUG_VARIABLE
1907    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1908		     "variable not found %s\n", name));
1909#endif
1910    return(NULL);
1911}
1912
1913/**
1914 * xsltParseStylesheetCallerParam:
1915 * @ctxt:  the XSLT transformation context
1916 * @inst:  the xsl:with-param instruction element
1917 *
1918 * Processes an xsl:with-param instruction at transformation time.
1919 * The value is compute, but not recorded.
1920 * NOTE that this is also called with an *xsl:param* element
1921 * from exsltFuncFunctionFunction().
1922 *
1923 * Returns the new xsltStackElemPtr or NULL
1924 */
1925
1926xsltStackElemPtr
1927xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
1928{
1929#ifdef XSLT_REFACTORED
1930    xsltStyleBasicItemVariablePtr comp;
1931#else
1932    xsltStylePreCompPtr comp;
1933#endif
1934    xmlNodePtr tree = NULL; /* The first child node of the instruction or
1935                               the instruction itself. */
1936    xsltStackElemPtr param = NULL;
1937
1938    if ((ctxt == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1939	return(NULL);
1940
1941#ifdef XSLT_REFACTORED
1942    comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
1943#else
1944    comp = (xsltStylePreCompPtr) inst->psvi;
1945#endif
1946
1947    if (comp == NULL) {
1948        xsltTransformError(ctxt, NULL, inst,
1949	    "Internal error in xsltParseStylesheetCallerParam(): "
1950	    "The XSLT 'with-param' instruction was not compiled.\n");
1951        return(NULL);
1952    }
1953    if (comp->name == NULL) {
1954	xsltTransformError(ctxt, NULL, inst,
1955	    "Internal error in xsltParseStylesheetCallerParam(): "
1956	    "XSLT 'with-param': The attribute 'name' was not compiled.\n");
1957	return(NULL);
1958    }
1959
1960#ifdef WITH_XSLT_DEBUG_VARIABLE
1961    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1962	    "Handling xsl:with-param %s\n", comp->name));
1963#endif
1964
1965    if (comp->select == NULL) {
1966	tree = inst->children;
1967    } else {
1968#ifdef WITH_XSLT_DEBUG_VARIABLE
1969	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1970	    "        select %s\n", comp->select));
1971#endif
1972	tree = inst;
1973    }
1974
1975    param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1976
1977    return(param);
1978}
1979
1980/**
1981 * xsltParseGlobalVariable:
1982 * @style:  the XSLT stylesheet
1983 * @cur:  the "variable" element
1984 *
1985 * Parses a global XSLT 'variable' declaration at compilation time
1986 * and registers it
1987 */
1988void
1989xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
1990{
1991#ifdef XSLT_REFACTORED
1992    xsltStyleItemVariablePtr comp;
1993#else
1994    xsltStylePreCompPtr comp;
1995#endif
1996
1997    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1998	return;
1999
2000#ifdef XSLT_REFACTORED
2001    /*
2002    * Note that xsltStylePreCompute() will be called from
2003    * xslt.c only.
2004    */
2005    comp = (xsltStyleItemVariablePtr) cur->psvi;
2006#else
2007    xsltStylePreCompute(style, cur);
2008    comp = (xsltStylePreCompPtr) cur->psvi;
2009#endif
2010    if (comp == NULL) {
2011	xsltTransformError(NULL, style, cur,
2012	     "xsl:variable : compilation failed\n");
2013	return;
2014    }
2015
2016    if (comp->name == NULL) {
2017	xsltTransformError(NULL, style, cur,
2018	    "xsl:variable : missing name attribute\n");
2019	return;
2020    }
2021
2022    /*
2023    * Parse the content (a sequence constructor) of xsl:variable.
2024    */
2025    if (cur->children != NULL) {
2026#ifdef XSLT_REFACTORED
2027        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2028#else
2029        xsltParseTemplateContent(style, cur);
2030#endif
2031    }
2032#ifdef WITH_XSLT_DEBUG_VARIABLE
2033    xsltGenericDebug(xsltGenericDebugContext,
2034	"Registering global variable %s\n", comp->name);
2035#endif
2036
2037    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2038	comp->select, cur->children, (xsltStylePreCompPtr) comp,
2039	NULL);
2040}
2041
2042/**
2043 * xsltParseGlobalParam:
2044 * @style:  the XSLT stylesheet
2045 * @cur:  the "param" element
2046 *
2047 * parse an XSLT transformation param declaration and record
2048 * its value.
2049 */
2050
2051void
2052xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
2053#ifdef XSLT_REFACTORED
2054    xsltStyleItemParamPtr comp;
2055#else
2056    xsltStylePreCompPtr comp;
2057#endif
2058
2059    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
2060	return;
2061
2062#ifdef XSLT_REFACTORED
2063    /*
2064    * Note that xsltStylePreCompute() will be called from
2065    * xslt.c only.
2066    */
2067    comp = (xsltStyleItemParamPtr) cur->psvi;
2068#else
2069    xsltStylePreCompute(style, cur);
2070    comp = (xsltStylePreCompPtr) cur->psvi;
2071#endif
2072    if (comp == NULL) {
2073	xsltTransformError(NULL, style, cur,
2074	     "xsl:param : compilation failed\n");
2075	return;
2076    }
2077
2078    if (comp->name == NULL) {
2079	xsltTransformError(NULL, style, cur,
2080	    "xsl:param : missing name attribute\n");
2081	return;
2082    }
2083
2084    /*
2085    * Parse the content (a sequence constructor) of xsl:param.
2086    */
2087    if (cur->children != NULL) {
2088#ifdef XSLT_REFACTORED
2089        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2090#else
2091        xsltParseTemplateContent(style, cur);
2092#endif
2093    }
2094
2095#ifdef WITH_XSLT_DEBUG_VARIABLE
2096    xsltGenericDebug(xsltGenericDebugContext,
2097	"Registering global param %s\n", comp->name);
2098#endif
2099
2100    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2101	comp->select, cur->children, (xsltStylePreCompPtr) comp,
2102	NULL);
2103}
2104
2105/**
2106 * xsltParseStylesheetVariable:
2107 * @ctxt:  the XSLT transformation context
2108 * @inst:  the xsl:variable instruction element
2109 *
2110 * Registers a local XSLT 'variable' instruction at transformation time
2111 * and evaluates its value.
2112 */
2113void
2114xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
2115{
2116#ifdef XSLT_REFACTORED
2117    xsltStyleItemVariablePtr comp;
2118#else
2119    xsltStylePreCompPtr comp;
2120#endif
2121
2122    if ((inst == NULL) || (ctxt == NULL) || (inst->type != XML_ELEMENT_NODE))
2123	return;
2124
2125    comp = inst->psvi;
2126    if (comp == NULL) {
2127        xsltTransformError(ctxt, NULL, inst,
2128	    "Internal error in xsltParseStylesheetVariable(): "
2129	    "The XSLT 'variable' instruction was not compiled.\n");
2130        return;
2131    }
2132    if (comp->name == NULL) {
2133	xsltTransformError(ctxt, NULL, inst,
2134	    "Internal error in xsltParseStylesheetVariable(): "
2135	    "The attribute 'name' was not compiled.\n");
2136	return;
2137    }
2138
2139#ifdef WITH_XSLT_DEBUG_VARIABLE
2140    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2141	"Registering variable '%s'\n", comp->name));
2142#endif
2143
2144    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
2145}
2146
2147/**
2148 * xsltParseStylesheetParam:
2149 * @ctxt:  the XSLT transformation context
2150 * @cur:  the XSLT 'param' element
2151 *
2152 * Registers a local XSLT 'param' declaration at transformation time and
2153 * evaluates its value.
2154 */
2155void
2156xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
2157{
2158#ifdef XSLT_REFACTORED
2159    xsltStyleItemParamPtr comp;
2160#else
2161    xsltStylePreCompPtr comp;
2162#endif
2163
2164    if ((cur == NULL) || (ctxt == NULL) || (cur->type != XML_ELEMENT_NODE))
2165	return;
2166
2167    comp = cur->psvi;
2168    if ((comp == NULL) || (comp->name == NULL)) {
2169	xsltTransformError(ctxt, NULL, cur,
2170	    "Internal error in xsltParseStylesheetParam(): "
2171	    "The XSLT 'param' declaration was not compiled correctly.\n");
2172	return;
2173    }
2174
2175#ifdef WITH_XSLT_DEBUG_VARIABLE
2176    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2177	"Registering param %s\n", comp->name));
2178#endif
2179
2180    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
2181}
2182
2183/**
2184 * xsltFreeGlobalVariables:
2185 * @ctxt:  the XSLT transformation context
2186 *
2187 * Free up the data associated to the global variables
2188 * its value.
2189 */
2190
2191void
2192xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
2193    xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
2194}
2195
2196/**
2197 * xsltXPathVariableLookup:
2198 * @ctxt:  a void * but the the XSLT transformation context actually
2199 * @name:  the variable name
2200 * @ns_uri:  the variable namespace URI
2201 *
2202 * This is the entry point when a varibale is needed by the XPath
2203 * interpretor.
2204 *
2205 * Returns the value or NULL if not found
2206 */
2207xmlXPathObjectPtr
2208xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
2209	                const xmlChar *ns_uri) {
2210    xsltTransformContextPtr tctxt;
2211    xmlXPathObjectPtr valueObj = NULL;
2212
2213    if ((ctxt == NULL) || (name == NULL))
2214	return(NULL);
2215
2216#ifdef WITH_XSLT_DEBUG_VARIABLE
2217    XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2218	    "Lookup variable '%s'\n", name));
2219#endif
2220
2221    tctxt = (xsltTransformContextPtr) ctxt;
2222    /*
2223    * Local variables/params ---------------------------------------------
2224    *
2225    * Do the lookup from the top of the stack, but
2226    * don't use params being computed in a call-param
2227    * First lookup expects the variable name and URI to
2228    * come from the disctionnary and hence pointer comparison.
2229    */
2230    if (tctxt->varsNr != 0) {
2231	int i;
2232	xsltStackElemPtr variable = NULL, cur;
2233
2234	for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2235	    cur = tctxt->varsTab[i-1];
2236	    if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2237#if 0
2238		stack_addr++;
2239#endif
2240		variable = cur;
2241		goto local_variable_found;
2242	    }
2243	    cur = cur->next;
2244	}
2245	/*
2246	* Redo the lookup with interned strings to avoid string comparison.
2247	*
2248	* OPTIMIZE TODO: The problem here is, that if we request a
2249	*  global variable, then this will be also executed.
2250	*/
2251	{
2252	    const xmlChar *tmpName = name, *tmpNsName = ns_uri;
2253
2254	    name = xmlDictLookup(tctxt->dict, name, -1);
2255	    if (ns_uri)
2256		ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
2257	    if ((tmpName != name) || (tmpNsName != ns_uri)) {
2258		for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2259		    cur = tctxt->varsTab[i-1];
2260		    if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2261#if 0
2262			stack_cmp++;
2263#endif
2264			variable = cur;
2265			goto local_variable_found;
2266		    }
2267		}
2268	    }
2269	}
2270
2271local_variable_found:
2272
2273	if (variable) {
2274	    if (variable->computed == 0) {
2275
2276#ifdef WITH_XSLT_DEBUG_VARIABLE
2277		XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2278		    "uncomputed variable '%s'\n", name));
2279#endif
2280		variable->value = xsltEvalVariable(tctxt, variable, NULL);
2281		variable->computed = 1;
2282	    }
2283	    if (variable->value != NULL) {
2284		valueObj = xmlXPathObjectCopy(variable->value);
2285	    }
2286	    return(valueObj);
2287	}
2288    }
2289    /*
2290    * Global variables/params --------------------------------------------
2291    */
2292    if (tctxt->globalVars) {
2293	valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
2294    }
2295
2296    if (valueObj == NULL) {
2297
2298#ifdef WITH_XSLT_DEBUG_VARIABLE
2299    XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2300		     "variable not found '%s'\n", name));
2301#endif
2302
2303	if (ns_uri) {
2304	    xsltTransformError(tctxt, NULL, tctxt->inst,
2305		"Variable '{%s}%s' has not been declared.\n", ns_uri, name);
2306	} else {
2307	    xsltTransformError(tctxt, NULL, tctxt->inst,
2308		"Variable '%s' has not been declared.\n", name);
2309	}
2310    } else {
2311
2312#ifdef WITH_XSLT_DEBUG_VARIABLE
2313	XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2314	    "found variable '%s'\n", name));
2315#endif
2316    }
2317
2318    return(valueObj);
2319}
2320
2321
2322