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