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