ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

variables.c
Go to the documentation of this file.
00001 /*
00002  * variables.c: Implementation of the variable storage and lookup
00003  *
00004  * Reference:
00005  *   http://www.w3.org/TR/1999/REC-xslt-19991116
00006  *
00007  * See Copyright for the status of this software.
00008  *
00009  * daniel@veillard.com
00010  */
00011 
00012 #define IN_LIBXSLT
00013 #include "libxslt.h"
00014 
00015 #include <string.h>
00016 
00017 #include <libxml/xmlmemory.h>
00018 #include <libxml/tree.h>
00019 #include <libxml/valid.h>
00020 #include <libxml/hash.h>
00021 #include <libxml/xmlerror.h>
00022 #include <libxml/xpath.h>
00023 #include <libxml/xpathInternals.h>
00024 #include <libxml/parserInternals.h>
00025 #include <libxml/dict.h>
00026 #include "xslt.h"
00027 #include "xsltInternals.h"
00028 #include "xsltutils.h"
00029 #include "variables.h"
00030 #include "transform.h"
00031 #include "imports.h"
00032 #include "preproc.h"
00033 #include "keys.h"
00034 
00035 #ifdef WITH_XSLT_DEBUG
00036  #define WITH_XSLT_DEBUG_VARIABLE
00037 #endif
00038 
00039 #ifdef XSLT_REFACTORED
00040 const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
00041 #endif
00042 
00043 const xmlChar *xsltComputingGlobalVarMarker =
00044  (const xmlChar *) " var/param being computed";
00045 
00046 #define XSLT_VAR_GLOBAL 1<<0
00047 #define XSLT_VAR_IN_SELECT 1<<1
00048 #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
00049 
00050 /************************************************************************
00051  *                                  *
00052  *  Result Value Tree (Result Tree Fragment) interfaces         *
00053  *                                  *
00054  ************************************************************************/
00064 xmlDocPtr
00065 xsltCreateRVT(xsltTransformContextPtr ctxt)
00066 {
00067     xmlDocPtr container;
00068 
00069     /*
00070     * Question: Why is this function public?
00071     * Answer: It is called by the EXSLT module.
00072     */    
00073     if (ctxt == NULL)
00074     return(NULL);
00075 
00076     /*
00077     * Reuse a RTF from the cache if available.
00078     */
00079     if (ctxt->cache->RVT) {
00080     container = ctxt->cache->RVT;
00081     ctxt->cache->RVT = (xmlDocPtr) container->next;
00082     /* clear the internal pointers */
00083     container->next = NULL;
00084     container->prev = NULL;
00085     if (ctxt->cache->nbRVT > 0)
00086         ctxt->cache->nbRVT--;
00087 #ifdef XSLT_DEBUG_PROFILE_CACHE
00088     ctxt->cache->dbgReusedRVTs++;
00089 #endif
00090     return(container);
00091     }
00092 
00093     container = xmlNewDoc(NULL);
00094     if (container == NULL)
00095     return(NULL);
00096     container->dict = ctxt->dict;
00097     xmlDictReference(container->dict);
00098     XSLT_MARK_RES_TREE_FRAG(container);
00099     container->doc = container;
00100     container->parent = NULL;
00101     return(container);
00102 }
00103 
00119 int
00120 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
00121 {
00122     if ((ctxt == NULL) || (RVT == NULL))
00123     return(-1);
00124 
00125     /*
00126     * We'll restrict the lifetime of user-created fragments
00127     * insinde an xsl:variable and xsl:param to the lifetime of the
00128     * var/param itself.
00129     */
00130     if (ctxt->contextVariable != NULL) {
00131     RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
00132     XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
00133     return(0);
00134     }
00135 
00136     RVT->next = (xmlNodePtr) ctxt->tmpRVT;
00137     if (ctxt->tmpRVT != NULL)
00138     ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
00139     ctxt->tmpRVT = RVT;
00140     return(0);
00141 }
00142 
00155 int
00156 xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
00157              xmlDocPtr RVT)
00158 {
00159     if ((ctxt == NULL) || (RVT == NULL))
00160     return(-1);
00161     
00162     /*
00163     * When evaluating "select" expressions of xsl:variable
00164     * and xsl:param, we need to bind newly created tree fragments
00165     * to the variable itself; otherwise the tragment will be
00166     * freed before we leave the scope of a var.
00167     */
00168     if ((ctxt->contextVariable != NULL) &&
00169     (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
00170     {
00171     RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
00172     XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
00173     return(0);
00174     }
00175     /*
00176     * Store the fragment in the scope of the current instruction.
00177     * If not reference by a returning instruction (like EXSLT's function),
00178     * then this fragment will be freed, when the instruction exits.
00179     */
00180     RVT->next = (xmlNodePtr) ctxt->localRVT;
00181     if (ctxt->localRVT != NULL)
00182     ctxt->localRVT->prev = (xmlNodePtr) RVT;
00183     ctxt->localRVT = RVT;
00184     /*
00185     * We need to keep track of the first registered fragment
00186     * for extension instructions which return fragments
00187     * (e.g. EXSLT'S function), in order to let
00188     * xsltExtensionInstructionResultFinalize() clear the
00189     * preserving flag on the fragments.
00190     */
00191     if (ctxt->localRVTBase == NULL)
00192     ctxt->localRVTBase = RVT;
00193     return(0);
00194 }
00195 
00208 int
00209 xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)
00210 {
00211     xmlDocPtr cur;
00212 
00213     if (ctxt == NULL)
00214     return(-1);
00215     if (ctxt->localRVTBase == NULL)
00216     return(0);
00217     /*
00218     * Enable remaining local tree fragments to be freed
00219     * by the fragment garbage collector.
00220     */
00221     cur = ctxt->localRVTBase;
00222     do {
00223     cur->psvi = NULL;
00224     cur = (xmlDocPtr) cur->next;
00225     } while (cur != NULL);
00226     return(0);
00227 }
00228 
00242 int
00243 xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,
00244                        xmlXPathObjectPtr obj)
00245 {
00246     int i;
00247     xmlNodePtr cur;
00248     xmlDocPtr doc;
00249 
00250     if ((ctxt == NULL) || (obj == NULL))
00251     return(-1);
00252 
00253     /*
00254     * OPTIMIZE TODO: If no local variables/params and no local tree
00255     * fragments were created, then we don't need to analyse the XPath
00256     * objects for tree fragments.
00257     */
00258 
00259     if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
00260     return(0);
00261     if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
00262     return(0);
00263 
00264     for (i = 0; i < obj->nodesetval->nodeNr; i++) {
00265     cur = obj->nodesetval->nodeTab[i];
00266     if (cur->type == XML_NAMESPACE_DECL) {
00267         /*
00268         * The XPath module sets the owner element of a ns-node on
00269         * the ns->next field.
00270         */
00271         if ((((xmlNsPtr) cur)->next != NULL) &&
00272         (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
00273         {
00274         cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
00275         doc = cur->doc; 
00276         } else {
00277         xsltTransformError(ctxt, NULL, ctxt->inst,
00278             "Internal error in "
00279             "xsltExtensionInstructionResultRegister(): "
00280             "Cannot retrieve the doc of a namespace node.\n");
00281         goto error;
00282         }
00283     } else {
00284         doc = cur->doc;
00285     }
00286     if (doc == NULL) {
00287         xsltTransformError(ctxt, NULL, ctxt->inst,
00288         "Internal error in "
00289         "xsltExtensionInstructionResultRegister(): "
00290         "Cannot retrieve the doc of a node.\n");
00291         goto error;
00292     }
00293     if (doc->name && (doc->name[0] == ' ')) {
00294         /*
00295         * This is a result tree fragment.
00296         * We'll use the @psvi field for reference counting.
00297         * TODO: How do we know if this is a value of a
00298         *  global variable or a doc acquired via the
00299         *  document() function?
00300         */
00301         doc->psvi = (void *) ((long) 1);
00302     }
00303     }
00304 
00305     return(0);
00306 error:
00307     return(-1);
00308 }
00309 
00318 void
00319 xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
00320 {
00321     if (RVT == NULL)
00322     return;
00323 
00324     if (ctxt && (ctxt->cache->nbRVT < 40)) {
00325     /*
00326     * Store the Result Tree Fragment.
00327     * Free the document info.
00328     */
00329     if (RVT->_private != NULL) {
00330         xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
00331         xmlFree(RVT->_private);
00332         RVT->_private = NULL;
00333     }
00334     /*
00335     * Clear the document tree.
00336     * REVISIT TODO: Do we expect ID/IDREF tables to be existent?    
00337     */
00338     if (RVT->children != NULL) {
00339         xmlFreeNodeList(RVT->children);
00340         RVT->children = NULL;
00341         RVT->last = NULL;
00342     }
00343     if (RVT->ids != NULL) {
00344         xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
00345         RVT->ids = NULL;
00346     }
00347     if (RVT->refs != NULL) {
00348         xmlFreeRefTable((xmlRefTablePtr) RVT->refs);
00349         RVT->refs = NULL;
00350     }
00351 
00352     /*
00353     * Reset the reference counter.
00354     */
00355     RVT->psvi = 0;
00356 
00357     RVT->next = (xmlNodePtr) ctxt->cache->RVT;
00358     ctxt->cache->RVT = RVT;
00359 
00360     ctxt->cache->nbRVT++;
00361 
00362 #ifdef XSLT_DEBUG_PROFILE_CACHE
00363     ctxt->cache->dbgCachedRVTs++;
00364 #endif
00365     return;
00366     }
00367     /*
00368     * Free it.
00369     */
00370     if (RVT->_private != NULL) {
00371     xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
00372     xmlFree(RVT->_private);
00373     }
00374     xmlFreeDoc(RVT);
00375 }
00376 
00389 int
00390 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
00391 {
00392     if ((ctxt == NULL) || (RVT == NULL)) return(-1);
00393 
00394     RVT->next = (xmlNodePtr) ctxt->persistRVT;
00395     if (ctxt->persistRVT != NULL)
00396     ctxt->persistRVT->prev = (xmlNodePtr) RVT;
00397     ctxt->persistRVT = RVT;
00398     return(0);
00399 }
00400 
00409 void
00410 xsltFreeRVTs(xsltTransformContextPtr ctxt)
00411 {
00412     xmlDocPtr cur, next;
00413 
00414     if (ctxt == NULL)
00415     return;
00416     /*
00417     * Local fragments.
00418     */
00419     cur = ctxt->localRVT;
00420     while (cur != NULL) {
00421         next = (xmlDocPtr) cur->next;
00422     if (cur->_private != NULL) {
00423         xsltFreeDocumentKeys(cur->_private);
00424         xmlFree(cur->_private);
00425     }
00426     xmlFreeDoc(cur);
00427     cur = next;
00428     }
00429     ctxt->localRVT = NULL;
00430     /*
00431     * User-created per-template fragments.
00432     */
00433     cur = ctxt->tmpRVT;
00434     while (cur != NULL) {
00435         next = (xmlDocPtr) cur->next;
00436     if (cur->_private != NULL) {
00437         xsltFreeDocumentKeys(cur->_private);
00438         xmlFree(cur->_private);
00439     }
00440     xmlFreeDoc(cur);
00441     cur = next;
00442     }
00443     ctxt->tmpRVT = NULL;
00444     /*
00445     * Global fragments.
00446     */
00447     cur = ctxt->persistRVT;
00448     while (cur != NULL) {
00449         next = (xmlDocPtr) cur->next;
00450     if (cur->_private != NULL) {
00451         xsltFreeDocumentKeys(cur->_private);
00452         xmlFree(cur->_private);
00453     }
00454     xmlFreeDoc(cur);
00455     cur = next;
00456     }
00457     ctxt->persistRVT = NULL;
00458 }
00459 
00460 /************************************************************************
00461  *                                  *
00462  *          Module interfaces               *
00463  *                                  *
00464  ************************************************************************/
00465 
00473 static xsltStackElemPtr
00474 xsltNewStackElem(xsltTransformContextPtr ctxt)
00475 {
00476     xsltStackElemPtr ret;
00477     /*
00478     * Reuse a stack item from the cache if available.
00479     */
00480     if (ctxt && ctxt->cache->stackItems) {
00481     ret = ctxt->cache->stackItems;
00482     ctxt->cache->stackItems = ret->next;
00483     ret->next = NULL;
00484     ctxt->cache->nbStackItems--;
00485 #ifdef XSLT_DEBUG_PROFILE_CACHE
00486     ctxt->cache->dbgReusedVars++;
00487 #endif
00488     return(ret);
00489     }
00490     ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
00491     if (ret == NULL) {
00492     xsltTransformError(NULL, NULL, NULL,
00493         "xsltNewStackElem : malloc failed\n");
00494     return(NULL);
00495     }
00496     memset(ret, 0, sizeof(xsltStackElem));
00497     ret->context = ctxt;
00498     return(ret);
00499 }
00500 
00509 static xsltStackElemPtr
00510 xsltCopyStackElem(xsltStackElemPtr elem) {
00511     xsltStackElemPtr cur;
00512 
00513     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
00514     if (cur == NULL) {
00515     xsltTransformError(NULL, NULL, NULL,
00516         "xsltCopyStackElem : malloc failed\n");
00517     return(NULL);
00518     }
00519     memset(cur, 0, sizeof(xsltStackElem));
00520     cur->context = elem->context;
00521     cur->name = elem->name;
00522     cur->nameURI = elem->nameURI;
00523     cur->select = elem->select;
00524     cur->tree = elem->tree;
00525     cur->comp = elem->comp;    
00526     return(cur);
00527 }
00528 
00535 static void
00536 xsltFreeStackElem(xsltStackElemPtr elem) {
00537     if (elem == NULL)
00538     return;
00539     if (elem->value != NULL)
00540     xmlXPathFreeObject(elem->value);
00541     /*
00542     * Release the list of temporary Result Tree Fragments.
00543     */
00544     if (elem->fragment) {
00545     xmlDocPtr cur;
00546 
00547     while (elem->fragment != NULL) {
00548         cur = elem->fragment;
00549         elem->fragment = (xmlDocPtr) cur->next;
00550 
00551         if (elem->context &&
00552         (cur->psvi == (void *) ((long) 1)))
00553         {
00554         /*
00555         * This fragment is a result of an extension instruction
00556         * (e.g. XSLT's function) and needs to be preserved until
00557         * the instruction exits.
00558         * Example: The fragment of the variable must not be freed
00559         *  since it is returned by the EXSLT function:
00560         *  <f:function name="foo">
00561         *   <xsl:variable name="bar">
00562         *     <bar/>
00563         *   </xsl:variable>
00564         *   <f:result select="$bar"/>
00565         *  </f:function>
00566         * 
00567         */
00568         xsltRegisterLocalRVT(elem->context, cur);
00569         } else {
00570         xsltReleaseRVT((xsltTransformContextPtr) elem->context,
00571             cur);
00572         }       
00573     }
00574     }
00575     /*
00576     * Cache or free the variable structure.
00577     */
00578     if (elem->context && (elem->context->cache->nbStackItems < 50)) {
00579     /*
00580     * Store the item in the cache.
00581     */
00582     xsltTransformContextPtr ctxt = elem->context;
00583     memset(elem, 0, sizeof(xsltStackElem));
00584     elem->context = ctxt;
00585     elem->next = ctxt->cache->stackItems;
00586     ctxt->cache->stackItems = elem; 
00587     ctxt->cache->nbStackItems++;
00588 #ifdef XSLT_DEBUG_PROFILE_CACHE
00589     ctxt->cache->dbgCachedVars++;
00590 #endif
00591     return;
00592     }
00593     xmlFree(elem);
00594 }
00595 
00602 void
00603 xsltFreeStackElemList(xsltStackElemPtr elem) {
00604     xsltStackElemPtr next;
00605     
00606     while (elem != NULL) {
00607     next = elem->next;
00608     xsltFreeStackElem(elem);
00609     elem = next;
00610     }
00611 }
00612 
00621 #if 0 /* TODO: Those seem to have been used for debugging. */
00622 static int stack_addr = 0;
00623 static int stack_cmp = 0;
00624 #endif
00625 
00626 static xsltStackElemPtr
00627 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
00628             const xmlChar *nameURI) {
00629     int i;
00630     xsltStackElemPtr cur;
00631 
00632     if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
00633     return(NULL);
00634 
00635     /*
00636      * Do the lookup from the top of the stack, but
00637      * don't use params being computed in a call-param
00638      * First lookup expects the variable name and URI to
00639      * come from the disctionnary and hence pointer comparison.
00640      */
00641     for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
00642     cur = ctxt->varsTab[i-1];
00643     while (cur != NULL) {
00644         if ((cur->name == name) && (cur->nameURI == nameURI)) {
00645 #if 0
00646         stack_addr++;
00647 #endif
00648         return(cur);
00649         }
00650         cur = cur->next;
00651     }
00652     }
00653 
00654     /*
00655      * Redo the lookup with interned string compares
00656      * to avoid string compares.
00657      */
00658     name = xmlDictLookup(ctxt->dict, name, -1);
00659     if (nameURI != NULL)
00660         nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
00661 
00662     for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
00663     cur = ctxt->varsTab[i-1];
00664     while (cur != NULL) {
00665         if ((cur->name == name) && (cur->nameURI == nameURI)) {
00666 #if 0
00667         stack_cmp++;
00668 #endif
00669         return(cur);
00670         }
00671         cur = cur->next;
00672     }
00673     }
00674 
00675     return(NULL);
00676 }
00677 
00692 static int
00693 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
00694                const xmlChar *nameURI) {
00695     xsltStackElemPtr cur;
00696 
00697     if ((ctxt == NULL) || (name == NULL))
00698     return(-1);
00699 
00700     cur = xsltStackLookup(ctxt, name, nameURI);
00701     if (cur == NULL)
00702         return(0);
00703     if (cur->comp != NULL) {
00704         if (cur->comp->type == XSLT_FUNC_WITHPARAM)
00705         return(3);
00706     else if (cur->comp->type == XSLT_FUNC_PARAM)
00707         return(2);
00708     }
00709     
00710     return(1);
00711 }
00712 
00725 static int
00726 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
00727 {
00728     if ((ctxt == NULL) || (elem == NULL))
00729     return(-1);
00730 
00731     do {
00732     if (ctxt->varsMax == 0) {
00733         ctxt->varsMax = 10;
00734         ctxt->varsTab =
00735         (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
00736         sizeof(ctxt->varsTab[0]));
00737         if (ctxt->varsTab == NULL) {
00738         xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
00739         return (-1);
00740         }
00741     }
00742     if (ctxt->varsNr >= ctxt->varsMax) {
00743         ctxt->varsMax *= 2;
00744         ctxt->varsTab =
00745         (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
00746         ctxt->varsMax *
00747         sizeof(ctxt->varsTab[0]));
00748         if (ctxt->varsTab == NULL) {
00749         xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
00750         return (-1);
00751         }
00752     }
00753     ctxt->varsTab[ctxt->varsNr++] = elem;
00754     ctxt->vars = elem;
00755     
00756     elem = elem->next;
00757     } while (elem != NULL);
00758     
00759     return(0);
00760 }
00761 
00771 int
00772 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
00773 {
00774     return(xsltAddStackElem(ctxt, elems));
00775 }
00776 
00777 /************************************************************************
00778  *                                  *
00779  *          Module interfaces               *
00780  *                                  *
00781  ************************************************************************/
00782 
00793 static xmlXPathObjectPtr
00794 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
00795              xsltStylePreCompPtr castedComp)
00796 {
00797 #ifdef XSLT_REFACTORED
00798     xsltStyleItemVariablePtr comp =
00799     (xsltStyleItemVariablePtr) castedComp;
00800 #else
00801     xsltStylePreCompPtr comp = castedComp;
00802 #endif   
00803     xmlXPathObjectPtr result = NULL;
00804     xmlNodePtr oldInst;
00805 
00806     if ((ctxt == NULL) || (variable == NULL))
00807     return(NULL);
00808 
00809     /*
00810     * A variable or parameter are evaluated on demand; thus the
00811     * context (of XSLT and XPath) need to be temporarily adjusted and
00812     * restored on exit.
00813     */
00814     oldInst = ctxt->inst;
00815 
00816 #ifdef WITH_XSLT_DEBUG_VARIABLE
00817     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
00818     "Evaluating variable '%s'\n", variable->name));
00819 #endif
00820     if (variable->select != NULL) {
00821     xmlXPathCompExprPtr xpExpr = NULL;
00822     xmlDocPtr oldXPDoc;
00823     xmlNodePtr oldXPContextNode;
00824     int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
00825     xmlNsPtr *oldXPNamespaces;
00826     xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
00827     xsltStackElemPtr oldVar = ctxt->contextVariable;
00828 
00829     if ((comp != NULL) && (comp->comp != NULL)) {
00830         xpExpr = comp->comp;
00831     } else {
00832         xpExpr = xmlXPathCompile(variable->select);
00833     }
00834     if (xpExpr == NULL)
00835         return(NULL);
00836     /*
00837     * Save context states.
00838     */
00839     oldXPDoc = xpctxt->doc;
00840     oldXPContextNode = xpctxt->node;
00841     oldXPProximityPosition = xpctxt->proximityPosition;
00842     oldXPContextSize = xpctxt->contextSize;
00843     oldXPNamespaces = xpctxt->namespaces;
00844     oldXPNsNr = xpctxt->nsNr;
00845         
00846     xpctxt->node = ctxt->node;
00847     /*
00848     * OPTIMIZE TODO: Lame try to set the context doc.
00849     *   Get rid of this somehow in xpath.c.
00850     */
00851     if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
00852         ctxt->node->doc)
00853         xpctxt->doc = ctxt->node->doc;
00854     /*
00855     * BUG TODO: The proximity position and the context size will
00856     *  potentially be wrong.
00857     *  Example: 
00858     *  <xsl:template select="foo">
00859     *    <xsl:variable name="pos" select="position()"/>
00860     *    <xsl:for-each select="bar">
00861     *      <xsl:value-of select="$pos"/>
00862     *    </xsl:for-each>
00863     *  </xsl:template>
00864     *  Here the proximity position and context size are changed
00865     *  to the context of <xsl:for-each select="bar">, but
00866     *  the variable needs to be evaluated in the context of
00867     *  <xsl:template select="foo">.
00868     */  
00869     if (comp != NULL) {
00870         
00871 #ifdef XSLT_REFACTORED
00872         if (comp->inScopeNs != NULL) {
00873         xpctxt->namespaces = comp->inScopeNs->list;
00874         xpctxt->nsNr = comp->inScopeNs->xpathNumber;
00875         } else {
00876         xpctxt->namespaces = NULL;
00877         xpctxt->nsNr = 0;
00878         }
00879 #else
00880         xpctxt->namespaces = comp->nsList;
00881         xpctxt->nsNr = comp->nsNr;
00882 #endif
00883     } else {
00884         xpctxt->namespaces = NULL;
00885         xpctxt->nsNr = 0;
00886     }
00887 
00888     /*
00889     * We need to mark that we are "selecting" a var's value;
00890     * if any tree fragments are created inside the expression,
00891     * then those need to be stored inside the variable; otherwise
00892     * we'll eventually free still referenced fragments, before
00893     * we leave the scope of the variable.
00894     */
00895     ctxt->contextVariable = variable;   
00896     variable->flags |= XSLT_VAR_IN_SELECT;  
00897     
00898     result = xmlXPathCompiledEval(xpExpr, xpctxt);
00899 
00900     variable->flags ^= XSLT_VAR_IN_SELECT;
00901     /*
00902     * Restore Context states.
00903     */
00904     ctxt->contextVariable = oldVar;
00905 
00906     xpctxt->doc = oldXPDoc;
00907     xpctxt->node = oldXPContextNode;
00908     xpctxt->contextSize = oldXPContextSize;
00909     xpctxt->proximityPosition = oldXPProximityPosition;
00910     xpctxt->namespaces = oldXPNamespaces;
00911     xpctxt->nsNr = oldXPNsNr;
00912 
00913     if ((comp == NULL) || (comp->comp == NULL))
00914         xmlXPathFreeCompExpr(xpExpr);
00915     if (result == NULL) {
00916         xsltTransformError(ctxt, NULL,
00917         (comp != NULL) ? comp->inst : NULL,
00918         "Failed to evaluate the expression of variable '%s'.\n",
00919         variable->name);
00920         ctxt->state = XSLT_STATE_STOPPED;
00921 
00922 #ifdef WITH_XSLT_DEBUG_VARIABLE
00923 #ifdef LIBXML_DEBUG_ENABLED
00924     } else {
00925         if ((xsltGenericDebugContext == stdout) ||
00926         (xsltGenericDebugContext == stderr))
00927         xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
00928                     result, 0);
00929 #endif
00930 #endif
00931     }
00932     } else {
00933     if (variable->tree == NULL) {
00934         result = xmlXPathNewCString("");
00935     } else {        
00936         if (variable->tree) {
00937         xmlDocPtr container;
00938         xmlNodePtr oldInsert;
00939         xmlDocPtr  oldOutput;
00940         xsltStackElemPtr oldVar = ctxt->contextVariable;
00941 
00942         /*
00943         * Generate a result tree fragment.
00944         */
00945         container = xsltCreateRVT(ctxt);
00946         if (container == NULL)
00947             goto error;
00948         /*
00949         * NOTE: Local Result Tree Fragments of params/variables
00950         * are not registered globally anymore; the life-time
00951         * is not directly dependant of the param/variable itself.
00952         *
00953         * OLD: xsltRegisterTmpRVT(ctxt, container);
00954         */
00955         /*
00956         * Attach the Result Tree Fragment to the variable;
00957         * when the variable is freed, it will also free 
00958         * the Result Tree Fragment.
00959         */
00960         variable->fragment = container;
00961         
00962         oldOutput = ctxt->output;
00963         oldInsert = ctxt->insert;       
00964         
00965         ctxt->output = container;
00966         ctxt->insert = (xmlNodePtr) container;
00967         ctxt->contextVariable = variable;
00968         /*
00969         * Process the sequence constructor (variable->tree).
00970         * The resulting tree will be held by @container.
00971         */
00972         xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
00973             NULL, NULL);
00974 
00975         ctxt->contextVariable = oldVar;     
00976         ctxt->insert = oldInsert;
00977         ctxt->output = oldOutput;
00978         
00979         result = xmlXPathNewValueTree((xmlNodePtr) container);
00980         }
00981         if (result == NULL) {
00982         result = xmlXPathNewCString("");
00983         } else {
00984         /*
00985         * Freeing is not handled there anymore.
00986         * QUESTION TODO: What does the above comment mean?
00987         */
00988             result->boolval = 0; 
00989         }
00990 #ifdef WITH_XSLT_DEBUG_VARIABLE
00991 #ifdef LIBXML_DEBUG_ENABLED
00992 
00993         if ((xsltGenericDebugContext == stdout) ||
00994         (xsltGenericDebugContext == stderr))
00995         xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
00996                     result, 0);
00997 #endif
00998 #endif
00999     }
01000     }
01001 
01002 error:
01003     ctxt->inst = oldInst;
01004     return(result);
01005 }
01006 
01017 static xmlXPathObjectPtr
01018 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
01019 {
01020     xmlXPathObjectPtr result = NULL;
01021     xmlNodePtr oldInst;
01022     const xmlChar* oldVarName;
01023 
01024 #ifdef XSLT_REFACTORED
01025     xsltStyleBasicItemVariablePtr comp;
01026 #else
01027     xsltStylePreCompPtr comp;
01028 #endif
01029 
01030     if ((ctxt == NULL) || (elem == NULL))
01031     return(NULL);
01032     if (elem->computed)
01033     return(elem->value);
01034 
01035 
01036 #ifdef WITH_XSLT_DEBUG_VARIABLE
01037     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01038     "Evaluating global variable %s\n", elem->name));
01039 #endif
01040 
01041 #ifdef WITH_DEBUGGER
01042     if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
01043         elem->comp && elem->comp->inst)
01044         xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
01045 #endif
01046 
01047     oldInst = ctxt->inst;
01048     comp = elem->comp;
01049     oldVarName = elem->name;
01050     elem->name = xsltComputingGlobalVarMarker;
01051     /*
01052     * OPTIMIZE TODO: We should consider instantiating global vars/params
01053     *  on-demand. The vars/params don't need to be evaluated if never
01054     *  called; and in the case of global params, if values for such params
01055     *  are provided by the user.
01056     */
01057     if (elem->select != NULL) {     
01058     xmlXPathCompExprPtr xpExpr = NULL;
01059     xmlDocPtr oldXPDoc;
01060     xmlNodePtr oldXPContextNode;
01061     int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
01062     xmlNsPtr *oldXPNamespaces;
01063     xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
01064 
01065     if ((comp != NULL) && (comp->comp != NULL)) {
01066         xpExpr = comp->comp;
01067     } else {
01068         xpExpr = xmlXPathCompile(elem->select);
01069     }
01070     if (xpExpr == NULL)
01071         goto error;
01072     
01073     
01074     if (comp != NULL)
01075         ctxt->inst = comp->inst;
01076     else
01077         ctxt->inst = NULL;
01078     /*
01079     * SPEC XSLT 1.0:
01080     * "At top-level, the expression or template specifying the
01081     *  variable value is evaluated with the same context as that used
01082     *  to process the root node of the source document: the current
01083     *  node is the root node of the source document and the current
01084     *  node list is a list containing just the root node of the source
01085     *  document."   
01086     */
01087     /*
01088     * Save context states.
01089     */
01090     oldXPDoc = xpctxt->doc;
01091     oldXPContextNode = xpctxt->node;
01092     oldXPProximityPosition = xpctxt->proximityPosition;
01093     oldXPContextSize = xpctxt->contextSize;
01094     oldXPNamespaces = xpctxt->namespaces;
01095     oldXPNsNr = xpctxt->nsNr;
01096         
01097     xpctxt->node = ctxt->initialContextNode;
01098     xpctxt->doc = ctxt->initialContextDoc;
01099     xpctxt->contextSize = 1;
01100     xpctxt->proximityPosition = 1;
01101         
01102     if (comp != NULL) {
01103         
01104 #ifdef XSLT_REFACTORED
01105         if (comp->inScopeNs != NULL) {
01106         xpctxt->namespaces = comp->inScopeNs->list;
01107         xpctxt->nsNr = comp->inScopeNs->xpathNumber;
01108         } else {
01109         xpctxt->namespaces = NULL;
01110         xpctxt->nsNr = 0;
01111         }
01112 #else
01113         xpctxt->namespaces = comp->nsList;
01114         xpctxt->nsNr = comp->nsNr;
01115 #endif
01116     } else {
01117         xpctxt->namespaces = NULL;
01118         xpctxt->nsNr = 0;
01119     }
01120     
01121     result = xmlXPathCompiledEval(xpExpr, xpctxt);
01122 
01123     /*
01124     * Restore Context states.
01125     */
01126     xpctxt->doc = oldXPDoc;
01127     xpctxt->node = oldXPContextNode;
01128     xpctxt->contextSize = oldXPContextSize;
01129     xpctxt->proximityPosition = oldXPProximityPosition;
01130     xpctxt->namespaces = oldXPNamespaces;
01131     xpctxt->nsNr = oldXPNsNr;
01132 
01133     if ((comp == NULL) || (comp->comp == NULL))
01134         xmlXPathFreeCompExpr(xpExpr);
01135     if (result == NULL) {
01136         if (comp == NULL)
01137         xsltTransformError(ctxt, NULL, NULL,
01138             "Evaluating global variable %s failed\n", elem->name);
01139         else
01140         xsltTransformError(ctxt, NULL, comp->inst,
01141             "Evaluating global variable %s failed\n", elem->name);
01142         ctxt->state = XSLT_STATE_STOPPED;
01143 #ifdef WITH_XSLT_DEBUG_VARIABLE
01144 #ifdef LIBXML_DEBUG_ENABLED
01145     } else {
01146         if ((xsltGenericDebugContext == stdout) ||
01147         (xsltGenericDebugContext == stderr))
01148         xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
01149                     result, 0);
01150 #endif
01151 #endif
01152     }
01153     } else {
01154     if (elem->tree == NULL) {
01155         result = xmlXPathNewCString("");
01156     } else {
01157         xmlDocPtr container;
01158         xmlNodePtr oldInsert;
01159         xmlDocPtr  oldOutput, oldXPDoc;     
01160         /*
01161         * Generate a result tree fragment.
01162         */
01163         container = xsltCreateRVT(ctxt);
01164         if (container == NULL)
01165         goto error;
01166         /*
01167         * Let the lifetime of the tree fragment be handled by
01168         * the Libxslt's garbage collector.
01169         */
01170         xsltRegisterPersistRVT(ctxt, container);        
01171 
01172         oldOutput = ctxt->output;
01173         oldInsert = ctxt->insert;
01174 
01175         oldXPDoc = ctxt->xpathCtxt->doc;
01176         
01177         ctxt->output = container;       
01178         ctxt->insert = (xmlNodePtr) container;
01179 
01180         ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
01181         /*
01182         * Process the sequence constructor.
01183         */
01184         xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
01185 
01186         ctxt->xpathCtxt->doc = oldXPDoc;
01187 
01188         ctxt->insert = oldInsert;
01189         ctxt->output = oldOutput;
01190         
01191         result = xmlXPathNewValueTree((xmlNodePtr) container);
01192         if (result == NULL) {
01193         result = xmlXPathNewCString("");
01194         } else {
01195             result->boolval = 0; /* Freeing is not handled there anymore */
01196         }
01197 #ifdef WITH_XSLT_DEBUG_VARIABLE
01198 #ifdef LIBXML_DEBUG_ENABLED
01199         if ((xsltGenericDebugContext == stdout) ||
01200         (xsltGenericDebugContext == stderr))
01201         xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
01202                     result, 0);
01203 #endif
01204 #endif
01205     }
01206     }
01207 
01208 error:
01209     elem->name = oldVarName;
01210     ctxt->inst = oldInst;
01211     if (result != NULL) {
01212     elem->value = result;
01213     elem->computed = 1;
01214     }
01215     return(result);
01216 }
01217 
01227 int
01228 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
01229     xsltStackElemPtr elem;
01230     xsltStylesheetPtr style;    
01231 
01232     if ((ctxt == NULL) || (ctxt->document == NULL))
01233     return(-1);
01234  
01235 #ifdef WITH_XSLT_DEBUG_VARIABLE
01236     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01237     "Registering global variables\n"));
01238 #endif
01239     /*
01240      * Walk the list from the stylesheets and populate the hash table
01241      */
01242     style = ctxt->style;
01243     while (style != NULL) {
01244     elem = style->variables;
01245     
01246 #ifdef WITH_XSLT_DEBUG_VARIABLE
01247     if ((style->doc != NULL) && (style->doc->URL != NULL)) {
01248         XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01249                  "Registering global variables from %s\n",
01250                      style->doc->URL));
01251     }
01252 #endif
01253 
01254     while (elem != NULL) {
01255         xsltStackElemPtr def;
01256 
01257         /*
01258          * Global variables are stored in the variables pool.
01259          */
01260         def = (xsltStackElemPtr) 
01261             xmlHashLookup2(ctxt->globalVars,
01262                          elem->name, elem->nameURI);
01263         if (def == NULL) {
01264 
01265         def = xsltCopyStackElem(elem);
01266         xmlHashAddEntry2(ctxt->globalVars,
01267                  elem->name, elem->nameURI, def);
01268         } else if ((elem->comp != NULL) &&
01269                (elem->comp->type == XSLT_FUNC_VARIABLE)) {
01270         /*
01271          * Redefinition of variables from a different stylesheet
01272          * should not generate a message.
01273          */
01274         if ((elem->comp->inst != NULL) &&
01275             (def->comp != NULL) && (def->comp->inst != NULL) &&
01276             (elem->comp->inst->doc == def->comp->inst->doc))
01277         {
01278             xsltTransformError(ctxt, style, elem->comp->inst,
01279             "Global variable %s already defined\n", elem->name);
01280             if (style != NULL) style->errors++;
01281         }
01282         }
01283         elem = elem->next;
01284     }
01285 
01286     style = xsltNextImport(style);
01287     }
01288 
01289     /*
01290      * This part does the actual evaluation
01291      */    
01292     xmlHashScan(ctxt->globalVars,
01293             (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
01294 
01295     return(0);
01296 }
01297 
01313 static int
01314 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
01315              const xmlChar *ns_uri, const xmlChar *sel,
01316              xmlNodePtr tree, xsltStylePreCompPtr comp,
01317              const xmlChar *value) {
01318     xsltStackElemPtr elem, tmp;
01319     if (style == NULL)
01320     return(-1);
01321     if (name == NULL)
01322     return(-1);
01323     if (comp == NULL)
01324     return(-1);
01325 
01326 #ifdef WITH_XSLT_DEBUG_VARIABLE
01327     if (comp->type == XSLT_FUNC_PARAM)
01328     xsltGenericDebug(xsltGenericDebugContext,
01329              "Defining global param %s\n", name);
01330     else
01331     xsltGenericDebug(xsltGenericDebugContext,
01332              "Defining global variable %s\n", name);
01333 #endif
01334 
01335     elem = xsltNewStackElem(NULL);
01336     if (elem == NULL)
01337     return(-1);
01338     elem->comp = comp;
01339     elem->name = xmlDictLookup(style->dict, name, -1);
01340     elem->select = xmlDictLookup(style->dict, sel, -1);
01341     if (ns_uri)
01342     elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
01343     elem->tree = tree;
01344     tmp = style->variables;
01345     if (tmp == NULL) {
01346     elem->next = NULL;
01347     style->variables = elem;
01348     } else {
01349     while (tmp != NULL) {
01350         if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
01351         (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
01352         (xmlStrEqual(elem->name, tmp->name)) &&
01353         ((elem->nameURI == tmp->nameURI) ||
01354          (xmlStrEqual(elem->nameURI, tmp->nameURI))))
01355         {
01356         xsltTransformError(NULL, style, comp->inst,
01357         "redefinition of global variable %s\n", elem->name);
01358         style->errors++;
01359         }
01360         if (tmp->next == NULL)
01361             break;
01362         tmp = tmp->next;
01363     }
01364     elem->next = NULL;
01365     tmp->next = elem;
01366     }
01367     if (value != NULL) {
01368     elem->computed = 1;
01369     elem->value = xmlXPathNewString(value);
01370     }
01371     return(0);
01372 }
01373 
01405 static
01406 int
01407 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
01408                      const xmlChar * name,
01409                  const xmlChar * value,
01410                  int eval) {
01411 
01412     xsltStylesheetPtr style;
01413     const xmlChar *prefix;
01414     const xmlChar *href;
01415     xmlXPathCompExprPtr xpExpr;
01416     xmlXPathObjectPtr result;
01417     
01418     xsltStackElemPtr elem;
01419     int res;
01420     void *res_ptr;
01421 
01422     if (ctxt == NULL)
01423     return(-1);
01424     if (name == NULL)
01425     return(0);
01426     if (value == NULL)
01427     return(0);
01428 
01429     style = ctxt->style;
01430 
01431 #ifdef WITH_XSLT_DEBUG_VARIABLE
01432     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01433         "Evaluating user parameter %s=%s\n", name, value));
01434 #endif
01435 
01436     /*
01437      * Name lookup
01438      */
01439 
01440     name = xsltSplitQName(ctxt->dict, name, &prefix);
01441     href = NULL;
01442     if (prefix != NULL) {
01443     xmlNsPtr ns;
01444 
01445     ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
01446              prefix);
01447     if (ns == NULL) {
01448         xsltTransformError(ctxt, style, NULL,
01449         "user param : no namespace bound to prefix %s\n", prefix);
01450         href = NULL;
01451     } else {
01452         href = ns->href;
01453     }
01454     }
01455 
01456     if (name == NULL)
01457     return (-1);
01458 
01459     res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
01460     if (res_ptr != 0) {
01461     xsltTransformError(ctxt, style, NULL,
01462         "Global parameter %s already defined\n", name);
01463     }
01464     if (ctxt->globalVars == NULL)
01465     ctxt->globalVars = xmlHashCreate(20);
01466 
01467     /*
01468      * do not overwrite variables with parameters from the command line
01469      */
01470     while (style != NULL) {
01471         elem = ctxt->style->variables;
01472     while (elem != NULL) {
01473         if ((elem->comp != NULL) &&
01474             (elem->comp->type == XSLT_FUNC_VARIABLE) &&
01475         (xmlStrEqual(elem->name, name)) &&
01476         (xmlStrEqual(elem->nameURI, href))) {
01477         return(0);
01478         }
01479             elem = elem->next;
01480     }
01481         style = xsltNextImport(style);
01482     }
01483     style = ctxt->style;
01484     elem = NULL;
01485 
01486     /*
01487      * Do the evaluation if @eval is non-zero.
01488      */
01489 
01490     result = NULL;
01491     if (eval != 0) {
01492         xpExpr = xmlXPathCompile(value);
01493     if (xpExpr != NULL) {
01494         xmlDocPtr oldXPDoc;
01495         xmlNodePtr oldXPContextNode;
01496         int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
01497         xmlNsPtr *oldXPNamespaces;
01498         xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
01499        
01500         /*
01501         * Save context states.
01502         */
01503         oldXPDoc = xpctxt->doc;
01504         oldXPContextNode = xpctxt->node;
01505         oldXPProximityPosition = xpctxt->proximityPosition;
01506         oldXPContextSize = xpctxt->contextSize;
01507         oldXPNamespaces = xpctxt->namespaces;
01508         oldXPNsNr = xpctxt->nsNr;
01509 
01510         /*
01511         * SPEC XSLT 1.0:
01512         * "At top-level, the expression or template specifying the
01513         *  variable value is evaluated with the same context as that used
01514         *  to process the root node of the source document: the current
01515         *  node is the root node of the source document and the current
01516         *  node list is a list containing just the root node of the source
01517         *  document."
01518         */
01519         xpctxt->doc = ctxt->initialContextDoc;      
01520         xpctxt->node = ctxt->initialContextNode;        
01521         xpctxt->contextSize = 1;
01522         xpctxt->proximityPosition = 1;
01523         /* 
01524         * There is really no in scope namespace for parameters on the
01525         * command line.
01526         */
01527         xpctxt->namespaces = NULL;
01528         xpctxt->nsNr = 0;      
01529         
01530         result = xmlXPathCompiledEval(xpExpr, xpctxt);
01531         
01532         /*
01533         * Restore Context states.
01534         */
01535         xpctxt->doc = oldXPDoc;
01536         xpctxt->node = oldXPContextNode;
01537         xpctxt->contextSize = oldXPContextSize;
01538         xpctxt->proximityPosition = oldXPProximityPosition;
01539         xpctxt->namespaces = oldXPNamespaces;
01540         xpctxt->nsNr = oldXPNsNr;
01541         
01542         xmlXPathFreeCompExpr(xpExpr);
01543     }
01544     if (result == NULL) {
01545         xsltTransformError(ctxt, style, NULL,
01546         "Evaluating user parameter %s failed\n", name);
01547         ctxt->state = XSLT_STATE_STOPPED;
01548         return(-1);
01549     }
01550     }
01551 
01552     /* 
01553      * If @eval is 0 then @value is to be taken literally and result is NULL
01554      * 
01555      * If @eval is not 0, then @value is an XPath expression and has been
01556      * successfully evaluated and result contains the resulting value and
01557      * is not NULL.
01558      *
01559      * Now create an xsltStackElemPtr for insertion into the context's
01560      * global variable/parameter hash table.
01561      */
01562 
01563 #ifdef WITH_XSLT_DEBUG_VARIABLE
01564 #ifdef LIBXML_DEBUG_ENABLED
01565     if ((xsltGenericDebugContext == stdout) ||
01566         (xsltGenericDebugContext == stderr))
01567         xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
01568                     result, 0);
01569 #endif
01570 #endif
01571 
01572     elem = xsltNewStackElem(NULL);
01573     if (elem != NULL) {
01574     elem->name = name;
01575     elem->select = xmlDictLookup(ctxt->dict, value, -1);
01576     if (href != NULL)
01577         elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
01578     elem->tree = NULL;
01579     elem->computed = 1;
01580     if (eval == 0) {
01581         elem->value = xmlXPathNewString(value);
01582     } 
01583     else {
01584         elem->value = result;
01585     }
01586     }
01587 
01588     /*
01589      * Global parameters are stored in the XPath context variables pool.
01590      */
01591 
01592     res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
01593     if (res != 0) {
01594     xsltFreeStackElem(elem);
01595     xsltTransformError(ctxt, style, NULL,
01596         "Global parameter %s already defined\n", name);
01597     }
01598     return(0);
01599 }
01600 
01616 int
01617 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
01618     int indx = 0;
01619     const xmlChar *name;
01620     const xmlChar *value;
01621 
01622     if (params == NULL)
01623     return(0);
01624     while (params[indx] != NULL) {
01625     name = (const xmlChar *) params[indx++];
01626     value = (const xmlChar *) params[indx++];
01627         if (xsltEvalOneUserParam(ctxt, name, value) != 0) 
01628         return(-1);
01629     }
01630     return 0;
01631 }
01632 
01646 int
01647 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
01648     int indx = 0;
01649     const xmlChar *name;
01650     const xmlChar *value;
01651 
01652     if (params == NULL)
01653     return(0);
01654     while (params[indx] != NULL) {
01655     name = (const xmlChar *) params[indx++];
01656     value = (const xmlChar *) params[indx++];
01657         if (xsltQuoteOneUserParam(ctxt, name, value) != 0) 
01658         return(-1);
01659     }
01660     return 0;
01661 }
01662 
01681 int
01682 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
01683                  const xmlChar * name,
01684              const xmlChar * value) {
01685     return xsltProcessUserParamInternal(ctxt, name, value,
01686                                 1 /* xpath eval ? */);
01687 }
01688 
01702 int
01703 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
01704              const xmlChar * name,
01705              const xmlChar * value) {
01706     return xsltProcessUserParamInternal(ctxt, name, value,
01707                     0 /* xpath eval ? */);
01708 }
01709 
01720 static xsltStackElemPtr
01721 xsltBuildVariable(xsltTransformContextPtr ctxt,
01722           xsltStylePreCompPtr castedComp,
01723           xmlNodePtr tree)
01724 {
01725 #ifdef XSLT_REFACTORED
01726     xsltStyleBasicItemVariablePtr comp =
01727     (xsltStyleBasicItemVariablePtr) castedComp;
01728 #else
01729     xsltStylePreCompPtr comp = castedComp;
01730 #endif 
01731     xsltStackElemPtr elem;
01732 
01733 #ifdef WITH_XSLT_DEBUG_VARIABLE
01734     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01735              "Building variable %s", comp->name));
01736     if (comp->select != NULL)
01737     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01738              " select %s", comp->select));
01739     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
01740 #endif
01741 
01742     elem = xsltNewStackElem(ctxt);
01743     if (elem == NULL)
01744     return(NULL);
01745     elem->comp = (xsltStylePreCompPtr) comp;
01746     elem->name = comp->name;
01747     elem->select = comp->select;
01748     elem->nameURI = comp->ns;
01749     elem->tree = tree;
01750     elem->value = xsltEvalVariable(ctxt, elem,
01751     (xsltStylePreCompPtr) comp);
01752     if (elem->value != NULL)
01753     elem->computed = 1;
01754     return(elem);
01755 }
01756 
01768 static int
01769 xsltRegisterVariable(xsltTransformContextPtr ctxt,
01770              xsltStylePreCompPtr castedComp,
01771              xmlNodePtr tree, int isParam)
01772 {
01773 #ifdef XSLT_REFACTORED
01774     xsltStyleBasicItemVariablePtr comp =
01775     (xsltStyleBasicItemVariablePtr) castedComp;
01776 #else
01777     xsltStylePreCompPtr comp = castedComp;
01778     int present;
01779 #endif
01780     xsltStackElemPtr variable;    
01781     
01782 #ifdef XSLT_REFACTORED
01783     /*
01784     * REFACTORED NOTE: Redefinitions of vars/params are checked
01785     *  at compilation time in the refactored code.
01786     * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
01787     */
01788 #else
01789     present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
01790     if (isParam == 0) { 
01791     if ((present != 0) && (present != 3)) {
01792         /* TODO: report QName. */
01793         xsltTransformError(ctxt, NULL, comp->inst,
01794         "XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
01795         return(0);
01796     }
01797     } else if (present != 0) {
01798     if ((present == 1) || (present == 2)) {
01799         /* TODO: report QName. */
01800         xsltTransformError(ctxt, NULL, comp->inst,
01801         "XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
01802         return(0);
01803     }
01804 #ifdef WITH_XSLT_DEBUG_VARIABLE
01805     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01806          "param %s defined by caller\n", comp->name));
01807 #endif
01808     return(0);
01809     }
01810 #endif /* else of XSLT_REFACTORED */
01811 
01812     variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
01813     xsltAddStackElem(ctxt, variable);
01814     return(0);
01815 }
01816 
01828 static xmlXPathObjectPtr
01829 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
01830                  const xmlChar *ns_uri) {
01831     xsltStackElemPtr elem;
01832     xmlXPathObjectPtr ret = NULL;
01833 
01834     /*
01835      * Lookup the global variables in XPath global variable hash table
01836      */
01837     if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
01838     return(NULL);
01839     elem = (xsltStackElemPtr)
01840         xmlHashLookup2(ctxt->globalVars, name, ns_uri);
01841     if (elem == NULL) {
01842 #ifdef WITH_XSLT_DEBUG_VARIABLE
01843     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01844              "global variable not found %s\n", name));
01845 #endif
01846     return(NULL);
01847     }
01848     /*
01849     * URGENT TODO: Move the detection of recursive definitions
01850     * to compile-time.
01851     */
01852     if (elem->computed == 0) {
01853     if (elem->name == xsltComputingGlobalVarMarker) {
01854         xsltTransformError(ctxt, NULL, elem->comp->inst,
01855         "Recursive definition of %s\n", name);
01856         return(NULL);
01857     }
01858     ret = xsltEvalGlobalVariable(elem, ctxt);
01859     } else
01860     ret = elem->value;
01861     return(xmlXPathObjectCopy(ret));
01862 }
01863 
01875 xmlXPathObjectPtr
01876 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
01877            const xmlChar *ns_uri) {
01878     xsltStackElemPtr elem;
01879 
01880     if (ctxt == NULL)
01881     return(NULL);
01882 
01883     elem = xsltStackLookup(ctxt, name, ns_uri);
01884     if (elem == NULL) {
01885     return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
01886     }
01887     if (elem->computed == 0) {
01888 #ifdef WITH_XSLT_DEBUG_VARIABLE
01889     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01890                  "uncomputed variable %s\n", name));
01891 #endif
01892         elem->value = xsltEvalVariable(ctxt, elem, NULL);
01893     elem->computed = 1;
01894     }
01895     if (elem->value != NULL)
01896     return(xmlXPathObjectCopy(elem->value));
01897 #ifdef WITH_XSLT_DEBUG_VARIABLE
01898     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01899              "variable not found %s\n", name));
01900 #endif
01901     return(NULL);
01902 }
01903 
01917 xsltStackElemPtr
01918 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
01919 {
01920 #ifdef XSLT_REFACTORED
01921     xsltStyleBasicItemVariablePtr comp;
01922 #else
01923     xsltStylePreCompPtr comp;
01924 #endif
01925     xmlNodePtr tree = NULL; /* The first child node of the instruction or
01926                                the instruction itself. */
01927     xsltStackElemPtr param = NULL;
01928     
01929     if ((ctxt == NULL) || (inst == NULL))
01930     return(NULL);
01931 
01932 #ifdef XSLT_REFACTORED
01933     comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
01934 #else
01935     comp = (xsltStylePreCompPtr) inst->psvi;
01936 #endif
01937     
01938     if (comp == NULL) {
01939         xsltTransformError(ctxt, NULL, inst,
01940         "Internal error in xsltParseStylesheetCallerParam(): "
01941         "The XSLT 'with-param' instruction was not compiled.\n");
01942         return(NULL);
01943     }
01944     if (comp->name == NULL) {
01945     xsltTransformError(ctxt, NULL, inst,
01946         "Internal error in xsltParseStylesheetCallerParam(): "
01947         "XSLT 'with-param': The attribute 'name' was not compiled.\n");
01948     return(NULL);
01949     }
01950 
01951 #ifdef WITH_XSLT_DEBUG_VARIABLE
01952     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01953         "Handling xsl:with-param %s\n", comp->name));
01954 #endif
01955 
01956     if (comp->select == NULL) {
01957     tree = inst->children;
01958     } else {
01959 #ifdef WITH_XSLT_DEBUG_VARIABLE
01960     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
01961         "        select %s\n", comp->select));
01962 #endif
01963     tree = inst;
01964     }
01965 
01966     param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
01967 
01968     return(param);
01969 }
01970 
01979 void
01980 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
01981 {
01982 #ifdef XSLT_REFACTORED
01983     xsltStyleItemVariablePtr comp;
01984 #else
01985     xsltStylePreCompPtr comp;
01986 #endif
01987 
01988     if ((cur == NULL) || (style == NULL))
01989     return;
01990     
01991 #ifdef XSLT_REFACTORED
01992     /*
01993     * Note that xsltStylePreCompute() will be called from
01994     * xslt.c only.
01995     */
01996     comp = (xsltStyleItemVariablePtr) cur->psvi;
01997 #else
01998     xsltStylePreCompute(style, cur);
01999     comp = (xsltStylePreCompPtr) cur->psvi;
02000 #endif
02001     if (comp == NULL) {
02002     xsltTransformError(NULL, style, cur,
02003          "xsl:variable : compilation failed\n");
02004     return;
02005     }
02006 
02007     if (comp->name == NULL) {
02008     xsltTransformError(NULL, style, cur,
02009         "xsl:variable : missing name attribute\n");
02010     return;
02011     }
02012 
02013     /*
02014     * Parse the content (a sequence constructor) of xsl:variable.
02015     */
02016     if (cur->children != NULL) {
02017 #ifdef XSLT_REFACTORED  
02018         xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
02019 #else
02020         xsltParseTemplateContent(style, cur);
02021 #endif
02022     }
02023 #ifdef WITH_XSLT_DEBUG_VARIABLE
02024     xsltGenericDebug(xsltGenericDebugContext,
02025     "Registering global variable %s\n", comp->name);
02026 #endif
02027 
02028     xsltRegisterGlobalVariable(style, comp->name, comp->ns,
02029     comp->select, cur->children, (xsltStylePreCompPtr) comp,
02030     NULL);
02031 }
02032 
02042 void
02043 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
02044 #ifdef XSLT_REFACTORED
02045     xsltStyleItemParamPtr comp;
02046 #else
02047     xsltStylePreCompPtr comp;
02048 #endif
02049 
02050     if ((cur == NULL) || (style == NULL))
02051     return;
02052     
02053 #ifdef XSLT_REFACTORED
02054     /*
02055     * Note that xsltStylePreCompute() will be called from
02056     * xslt.c only.
02057     */
02058     comp = (xsltStyleItemParamPtr) cur->psvi;
02059 #else
02060     xsltStylePreCompute(style, cur);
02061     comp = (xsltStylePreCompPtr) cur->psvi;
02062 #endif    
02063     if (comp == NULL) {
02064     xsltTransformError(NULL, style, cur,
02065          "xsl:param : compilation failed\n");
02066     return;
02067     }
02068 
02069     if (comp->name == NULL) {
02070     xsltTransformError(NULL, style, cur,
02071         "xsl:param : missing name attribute\n");
02072     return;
02073     }
02074 
02075     /*
02076     * Parse the content (a sequence constructor) of xsl:param.
02077     */
02078     if (cur->children != NULL) {
02079 #ifdef XSLT_REFACTORED  
02080         xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
02081 #else
02082         xsltParseTemplateContent(style, cur);
02083 #endif
02084     }
02085 
02086 #ifdef WITH_XSLT_DEBUG_VARIABLE
02087     xsltGenericDebug(xsltGenericDebugContext,
02088     "Registering global param %s\n", comp->name);
02089 #endif
02090 
02091     xsltRegisterGlobalVariable(style, comp->name, comp->ns,
02092     comp->select, cur->children, (xsltStylePreCompPtr) comp,
02093     NULL);
02094 }
02095 
02104 void
02105 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
02106 {
02107 #ifdef XSLT_REFACTORED
02108     xsltStyleItemVariablePtr comp;
02109 #else
02110     xsltStylePreCompPtr comp;
02111 #endif
02112 
02113     if ((inst == NULL) || (ctxt == NULL))
02114     return;
02115 
02116     comp = inst->psvi;
02117     if (comp == NULL) {
02118         xsltTransformError(ctxt, NULL, inst,
02119         "Internal error in xsltParseStylesheetVariable(): "
02120         "The XSLT 'variable' instruction was not compiled.\n");
02121         return;
02122     }
02123     if (comp->name == NULL) {
02124     xsltTransformError(ctxt, NULL, inst,
02125         "Internal error in xsltParseStylesheetVariable(): "
02126         "The attribute 'name' was not compiled.\n");
02127     return;
02128     }
02129 
02130 #ifdef WITH_XSLT_DEBUG_VARIABLE
02131     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
02132     "Registering variable '%s'\n", comp->name));
02133 #endif
02134 
02135     xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
02136 }
02137 
02146 void
02147 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
02148 {
02149 #ifdef XSLT_REFACTORED
02150     xsltStyleItemParamPtr comp;
02151 #else
02152     xsltStylePreCompPtr comp;
02153 #endif
02154 
02155     if ((cur == NULL) || (ctxt == NULL))
02156     return;
02157 
02158     comp = cur->psvi;
02159     if ((comp == NULL) || (comp->name == NULL)) {
02160     xsltTransformError(ctxt, NULL, cur,
02161         "Internal error in xsltParseStylesheetParam(): "
02162         "The XSLT 'param' declaration was not compiled correctly.\n");
02163     return;
02164     }
02165 
02166 #ifdef WITH_XSLT_DEBUG_VARIABLE
02167     XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
02168     "Registering param %s\n", comp->name));
02169 #endif
02170 
02171     xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
02172 }
02173 
02182 void
02183 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
02184     xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
02185 }
02186 
02198 xmlXPathObjectPtr
02199 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
02200                     const xmlChar *ns_uri) {
02201     xsltTransformContextPtr tctxt;
02202     xmlXPathObjectPtr valueObj = NULL;
02203 
02204     if ((ctxt == NULL) || (name == NULL))
02205     return(NULL);
02206 
02207 #ifdef WITH_XSLT_DEBUG_VARIABLE
02208     XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
02209         "Lookup variable '%s'\n", name));
02210 #endif
02211     
02212     tctxt = (xsltTransformContextPtr) ctxt;
02213     /*
02214     * Local variables/params ---------------------------------------------
02215     *
02216     * Do the lookup from the top of the stack, but
02217     * don't use params being computed in a call-param
02218     * First lookup expects the variable name and URI to
02219     * come from the disctionnary and hence pointer comparison.
02220     */
02221     if (tctxt->varsNr != 0) {
02222     int i;
02223     xsltStackElemPtr variable = NULL, cur;
02224 
02225     for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
02226         cur = tctxt->varsTab[i-1];
02227         if ((cur->name == name) && (cur->nameURI == ns_uri)) {
02228 #if 0
02229         stack_addr++;
02230 #endif
02231         variable = cur;
02232         goto local_variable_found;
02233         }
02234         cur = cur->next;
02235     }   
02236     /*
02237     * Redo the lookup with interned strings to avoid string comparison.
02238     *
02239     * OPTIMIZE TODO: The problem here is, that if we request a
02240     *  global variable, then this will be also executed.
02241     */
02242     {
02243         const xmlChar *tmpName = name, *tmpNsName = ns_uri;
02244 
02245         name = xmlDictLookup(tctxt->dict, name, -1);
02246         if (ns_uri)
02247         ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
02248         if ((tmpName != name) || (tmpNsName != ns_uri)) {       
02249         for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
02250             cur = tctxt->varsTab[i-1];
02251             if ((cur->name == name) && (cur->nameURI == ns_uri)) {
02252 #if 0
02253             stack_cmp++;
02254 #endif
02255             variable = cur;
02256             goto local_variable_found;
02257             }
02258         }
02259         }
02260     }
02261 
02262 local_variable_found:
02263 
02264     if (variable) {
02265         if (variable->computed == 0) {
02266         
02267 #ifdef WITH_XSLT_DEBUG_VARIABLE
02268         XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
02269             "uncomputed variable '%s'\n", name));
02270 #endif
02271         variable->value = xsltEvalVariable(tctxt, variable, NULL);
02272         variable->computed = 1;
02273         }
02274         if (variable->value != NULL) {
02275         valueObj = xmlXPathObjectCopy(variable->value); 
02276         }
02277         return(valueObj);
02278     }
02279     }
02280     /*
02281     * Global variables/params --------------------------------------------
02282     */    
02283     if (tctxt->globalVars) {
02284     valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
02285     }
02286 
02287     if (valueObj == NULL) {
02288 
02289 #ifdef WITH_XSLT_DEBUG_VARIABLE
02290     XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
02291              "variable not found '%s'\n", name));
02292 #endif
02293 
02294     if (ns_uri) {
02295         xsltTransformError(tctxt, NULL, tctxt->inst,
02296         "Variable '{%s}%s' has not been declared.\n", ns_uri, name);
02297     } else {
02298         xsltTransformError(tctxt, NULL, tctxt->inst,
02299         "Variable '%s' has not been declared.\n", name);
02300     }
02301     } else {
02302 
02303 #ifdef WITH_XSLT_DEBUG_VARIABLE
02304     XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
02305         "found variable '%s'\n", name));
02306 #endif
02307     }
02308 
02309     return(valueObj);
02310 }
02311 
02312 

Generated on Sat May 26 2012 04:18:29 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.