fixed bug 119699 (missing error on shadowed variable) removed dependency
[platform/upstream/libxslt.git] / libxslt / variables.c
index 1a0a921..a543ae4 100644 (file)
 
 /************************************************************************
  *                                                                     *
+ *                     Result Value Tree interfaces                    *
+ *                                                                     *
+ ************************************************************************/
+/**
+ * xsltCreateRVT:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Create a result value tree
+ *
+ * Returns the result value tree or NULL in case of error
+ */
+xmlDocPtr
+xsltCreateRVT(xsltTransformContextPtr ctxt)
+{
+    xmlDocPtr container;
+
+    if (ctxt == NULL) return(NULL);
+
+    container = xmlNewDoc(NULL);
+    if (container == NULL)
+       return(NULL);
+
+    container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
+    container->doc = container;
+    container->parent = NULL;
+    return(container);
+}
+
+/**
+ * xsltRegisterTmpRVT:
+ * @ctxt:  an XSLT transformation context
+ * @RVT:  a result value tree
+ *
+ * Register the result value tree for destruction at the end of the context
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+int
+xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
+{
+    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
+
+    RVT->next = (xmlNodePtr) ctxt->tmpRVT;
+    if (ctxt->tmpRVT != NULL)
+       ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
+    ctxt->tmpRVT = RVT;
+    return(0);
+}
+
+/**
+ * xsltRegisterPersistRVT:
+ * @ctxt:  an XSLT transformation context
+ * @RVT:  a result value tree
+ *
+ * Register the result value tree for destruction at the end of the processing
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+int
+xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
+{
+    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
+
+    RVT->next = (xmlNodePtr) ctxt->persistRVT;
+    if (ctxt->persistRVT != NULL)
+       ctxt->persistRVT->prev = (xmlNodePtr) RVT;
+    ctxt->persistRVT = RVT;
+    return(0);
+}
+
+/**
+ * xsltFreeRVTs:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Free all the registered result value tree of the transformation
+ */
+void
+xsltFreeRVTs(xsltTransformContextPtr ctxt)
+{
+    xmlDocPtr cur, next;
+
+    if (ctxt == NULL) return;
+
+    cur = ctxt->tmpRVT;
+    while (cur != NULL) {
+        next = (xmlDocPtr) cur->next;
+       xmlFreeDoc(cur);
+       cur = next;
+    }
+    cur = ctxt->persistRVT;
+    while (cur != NULL) {
+        next = (xmlDocPtr) cur->next;
+       xmlFreeDoc(cur);
+       cur = next;
+    }
+}
+
+/************************************************************************
+ *                                                                     *
  *                     Module interfaces                               *
  *                                                                     *
  ************************************************************************/
@@ -135,6 +234,52 @@ xsltFreeStackElemList(xsltStackElemPtr elem) {
 }
 
 /**
+ * xsltStackLookup:
+ * @ctxt:  an XSLT transformation context
+ * @name:  the local part of the name
+ * @nameURI:  the URI part of the name
+ *
+ * Locate an element in the stack based on its name.
+ */
+static xsltStackElemPtr
+xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
+               const xmlChar *nameURI) {
+    xsltStackElemPtr ret = NULL;
+    int i;
+    xsltStackElemPtr cur;
+
+    if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
+       return(NULL);
+
+    /*
+     * Do the lookup from the top of the stack, but
+     * don't use params being computed in a call-param
+     */
+    ;
+
+    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
+       cur = ctxt->varsTab[i-1];
+       while (cur != NULL) {
+           if (xmlStrEqual(cur->name, name)) {
+               if (nameURI == NULL) {
+                   if (cur->nameURI == NULL) {
+                       return(cur);
+                   }
+               } else {
+                   if ((cur->nameURI != NULL) &&
+                       (xmlStrEqual(cur->nameURI, nameURI))) {
+                       return(cur);
+                   }
+               }
+
+           }
+           cur = cur->next;
+       }
+    }
+    return(ret);
+}
+
+/**
  * xsltCheckStackElem:
  * @ctxt:  xn XSLT transformation context
  * @name:  the variable name
@@ -153,24 +298,17 @@ xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
     if ((ctxt == NULL) || (name == NULL))
        return(-1);
 
-    cur = ctxt->vars;
-    while (cur != NULL) {
-       if (xmlStrEqual(name, cur->name)) {
-           if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
-               ((nameURI != NULL) && (cur->nameURI != NULL) &&
-                (xmlStrEqual(nameURI, cur->nameURI)))) {
-               if ((cur->comp != NULL) &&
-                   (cur->comp->type == XSLT_FUNC_WITHPARAM))
-                   return(3);
-               if ((cur->comp != NULL) &&
-                   (cur->comp->type == XSLT_FUNC_PARAM))
-                   return(2);
-               return(1);
-           }
-       }
-       cur = cur->next;
+    cur = xsltStackLookup(ctxt, name, nameURI);
+    if (cur == NULL)
+        return(0);
+    if (cur->comp != NULL) {
+        if (cur->comp->type == XSLT_FUNC_WITHPARAM)
+           return(3);
+       else if (cur->comp->type == XSLT_FUNC_PARAM)
+           return(2);
     }
-    return(0);
+    
+    return(1);
 }
 
 /**
@@ -223,52 +361,6 @@ xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
     return(0);
 }
 
-/**
- * xsltStackLookup:
- * @ctxt:  an XSLT transformation context
- * @name:  the local part of the name
- * @nameURI:  the URI part of the name
- *
- * Locate an element in the stack based on its name.
- */
-static xsltStackElemPtr
-xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
-               const xmlChar *nameURI) {
-    xsltStackElemPtr ret = NULL;
-    int i;
-    xsltStackElemPtr cur;
-
-    if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
-       return(NULL);
-
-    /*
-     * Do the lookup from the top of the stack, but
-     * don't use params being computed in a call-param
-     */
-    ;
-
-    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
-       cur = ctxt->varsTab[i-1];
-       while (cur != NULL) {
-           if (xmlStrEqual(cur->name, name)) {
-               if (nameURI == NULL) {
-                   if (cur->nameURI == NULL) {
-                       return(cur);
-                   }
-               } else {
-                   if ((cur->nameURI != NULL) &&
-                       (xmlStrEqual(cur->nameURI, nameURI))) {
-                       return(cur);
-                   }
-               }
-
-           }
-           cur = cur->next;
-       }
-    }
-    return(ret);
-}
-
 /************************************************************************
  *                                                                     *
  *                     Module interfaces                               *
@@ -364,13 +456,13 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
            xmlNodePtr oldInsert;
            xmlDocPtr  oldoutput;
 
-           container = xmlNewDoc(NULL);
+           container = xsltCreateRVT(ctxt);
            if (container == NULL)
                return(NULL);
-           container->name = xmlStrdup(BAD_CAST " fake node libxslt");
-           container->doc = container;
-           container->parent = NULL;
-
+           /*
+            * Tag the subtree for removal once consumed
+            */
+           xsltRegisterTmpRVT(ctxt, container);
            oldoutput = ctxt->output;
            ctxt->output = container;
            oldInsert = ctxt->insert;
@@ -379,14 +471,11 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
            ctxt->insert = oldInsert;
            ctxt->output = oldoutput;
 
-           result = xmlXPathNewValueTree(container);
+           result = xmlXPathNewValueTree((xmlNodePtr) container);
            if (result == NULL) {
                result = xmlXPathNewCString("");
            } else {
-               /*
-                * Tag the subtree for removal once consumed
-                */
-               result->boolval = 1;
+               result->boolval = 0; /* Freeing is not handled there anymore */
            }
 #ifdef WITH_XSLT_DEBUG_VARIABLE
 #ifdef LIBXML_DEBUG_ENABLED
@@ -501,13 +590,17 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
            xmlNodePtr oldInsert;
            xmlDocPtr  oldoutput;
 
-           container = xmlNewDoc(NULL);
+           container = xsltCreateRVT(ctxt);
            if (container == NULL)
                return(NULL);
-           container->name = xmlStrdup(BAD_CAST " fake node libxslt");
-           container->doc = container;
-           container->parent = NULL;
-
+           /*
+            * Tag the subtree for removal once consumed
+            */
+           xsltRegisterTmpRVT(ctxt, container);
+           /*
+            * Save a pointer to the global variable for later cleanup
+            */
+           container->_private = elem;
            oldoutput = ctxt->output;
            ctxt->output = container;
            oldInsert = ctxt->insert;
@@ -516,14 +609,11 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
            ctxt->insert = oldInsert;
            ctxt->output = oldoutput;
 
-           result = xmlXPathNewValueTree(container);
+           result = xmlXPathNewValueTree((xmlNodePtr) container);
            if (result == NULL) {
                result = xmlXPathNewCString("");
            } else {
-               /*
-                * Tag the subtree for removal once consumed
-                */
-               result->boolval = 1;
+               result->boolval = 0; /* Freeing is not handled there anymore */
            }
 #ifdef WITH_XSLT_DEBUG_VARIABLE
 #ifdef LIBXML_DEBUG_ENABLED
@@ -557,13 +647,14 @@ xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
     xsltStackElemPtr elem;
     xsltStylesheetPtr style;
 
-    if (ctxt == NULL)
+    if ((ctxt == NULL) || (ctxt->document == NULL))
        return(-1);
  
 #ifdef WITH_XSLT_DEBUG_VARIABLE
     xsltGenericDebug(xsltGenericDebugContext,
        "Registering global variables\n");
 #endif
+
     ctxt->node = (xmlNodePtr) ctxt->document->doc;
     ctxt->xpathCtxt->contextSize = 1;
     ctxt->xpathCtxt->proximityPosition = 1;
@@ -593,10 +684,9 @@ xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
                    xmlHashLookup2(ctxt->globalVars,
                                 elem->name, elem->nameURI);
            if (def == NULL) {
-               int res;
 
                def = xsltCopyStackElem(elem);
-               res = xmlHashAddEntry2(ctxt->globalVars,
+               xmlHashAddEntry2(ctxt->globalVars,
                                 elem->name, elem->nameURI, def);
            } else if ((elem->comp != NULL) &&
                       (elem->comp->type == XSLT_FUNC_VARIABLE)) {
@@ -755,6 +845,7 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
     xmlNsPtr *oldNamespaces;
     xsltStackElemPtr elem;
     int res;
+    void *res_ptr;
 
     if (ctxt == NULL)
        return(-1);
@@ -804,6 +895,32 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
     if (ncname == NULL)
        return (-1);
 
+    res_ptr = xmlHashLookup2(ctxt->globalVars, ncname, href);
+    if (res_ptr != 0) {
+       xsltTransformError(ctxt, style, NULL,
+           "Global parameter %s already defined\n", ncname);
+    }
+
+    /*
+     * do not overwrite variables with parameters from the command line
+     */
+    while (style != NULL) {
+        elem = ctxt->style->variables;
+       while (elem != NULL) {
+           if ((elem->comp != NULL) &&
+               (elem->comp->type == XSLT_FUNC_VARIABLE) &&
+               (xmlStrEqual(elem->name, ncname)) &&
+               (xmlStrEqual(elem->nameURI, href))) {
+               xmlFree(ncname);
+               return(0);
+           }
+            elem = elem->next;
+       }
+        style = xsltNextImport(style);
+    }
+    style = ctxt->style;
+    elem = NULL;
+
     /*
      * Do the evaluation if @eval is non-zero.
      */