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