Home | History | Annotate | Download | only in libxslt
      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 (at) 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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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