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