changed handling of function params to fix bug #381319 exposed
authorWilliam M. Brack <wbrack@src.gnome.org>
Sat, 9 Dec 2006 23:18:21 +0000 (23:18 +0000)
committerWilliam M. Brack <wbrack@src.gnome.org>
Sat, 9 Dec 2006 23:18:21 +0000 (23:18 +0000)
* libexslt/functions.c: changed handling of function params
  to fix bug #381319
* libxslt/transform.[ch]: exposed xsltLocalVariablePush and
  xsltLocalVariablePop as global entries so that they could
  be used from within libexslt/functions.c
* tests/exslt/functions/function.9.[xsl,xml,out] added to
  regression tests

ChangeLog
libexslt/functions.c
libxslt/transform.c
libxslt/transform.h
tests/exslt/functions/Makefile.am
tests/exslt/functions/function.9.out [new file with mode: 0644]
tests/exslt/functions/function.9.xml [new file with mode: 0644]
tests/exslt/functions/function.9.xsl [new file with mode: 0644]

index 2e05714..a9b2f80 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Sat Dec  9 15:22:34 PST 2006 William Brack <wbrack@mmm.com.hk>
+
+       * libexslt/functions.c: changed handling of function params
+         to fix bug #381319
+       * libxslt/transform.[ch]: exposed xsltLocalVariablePush and
+         xsltLocalVariablePop as global entries so that they could
+         be used from within libexslt/functions.c
+       * tests/exslt/functions/function.9.[xsl,xml,out] added to
+         regression tests
+
 Tue Dec  5 10:45:04 CET 2006 Daniel Veillard <daniel@veillard.com>
 
        * libxslt/extensions.c: applied patch from Marcus Meissner removing
index bbeb182..58bd71e 100644 (file)
@@ -281,7 +281,7 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     int oldBase;
     xsltStackElemPtr params = NULL, param;
     xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
-    int i;
+    int i, notSet;;
 
     /*
      * retrieve func:function template
@@ -316,46 +316,47 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
                         "param == NULL\n");
        return;
     }
-    /*
-    * Process xsl:param instructions which were not set by the
-    * invoking function call.
-    */
-    for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
+    /* 
+     * In order to give the function params and variables a new 'scope'
+     * we change varsBase in the context.
+     */
+    oldBase = tctxt->varsBase;
+    tctxt->varsBase = tctxt->varsNr;
+
+    /* If there are any parameters */
+    if (paramNode != NULL) {
        /*
-       * Those are the xsl:param instructions, which were not
-       * set by the calling function.  
-       */
-       param = xsltParseStylesheetCallerParam (tctxt, paramNode);
-       param->next = params;
-       params = param;
-       paramNode = paramNode->prev;
-    }
-    /*
-    * Process xsl:param instructions which are set by the
-    * invoking function call.
-    */
-    while ((i-- > 0) && (paramNode != NULL)) {
-       obj = valuePop(ctxt);
+        * We need to process params which have been set by the invoking
+        * function call before those which were not (in case the set values
+        * are used within non-set 'select' default values), so we position
+        * to the beginning of the params.
+        */
+       for (i = 1; i <= func->nargs; i++) {
+           if (paramNode->prev == NULL)
+               break;
+           paramNode = paramNode->prev;
+       }
        /*
-       * TODO: Using xsltParseStylesheetCallerParam() is actually
-       * not correct, since we are processing an xsl:param; but
-       * using xsltParseStylesheetParam() won't work, as it puts
-       * the param on the varible stack and does not give access to
-       * the created xsltStackElemPtr.
-       * It's also not correct, as xsltParseStylesheetCallerParam()
-       * will report error messages indicating an "xsl:with-param" and
-       * not the actual "xsl:param".
-       */
-       param = xsltParseStylesheetCallerParam (tctxt, paramNode);
-       param->computed = 1;
-       if (param->value != NULL)
-           xmlXPathFreeObject(param->value);
-       param->value = obj;
-       param->next = params;
-       params = param;
-       paramNode = paramNode->prev;
+        * i has total # params found, nargs is number which are present
+        * as arguments from the caller
+        */
+       notSet = func->nargs - nargs;
+       for (; i > 0; i--) {
+           if (i > notSet)     /* if parameter value set */
+               obj = valuePop(ctxt);
+           param = xsltParseStylesheetCallerParam (tctxt, paramNode);
+           if (i > notSet) {   /* if parameter value set */
+               param->computed = 1;
+               if (param->value != NULL)
+                   xmlXPathFreeObject(param->value);
+               param->value = obj;
+           }
+           xsltLocalVariablePush(tctxt, param, -1);
+           param->next = params;
+           params = param;
+           paramNode = paramNode->next;
+       }
     }
-    
     /*
      * actual processing
      */
@@ -363,14 +364,9 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
                         (const xmlChar *)"fake", NULL);
     oldInsert = tctxt->insert;
     tctxt->insert = fake;
-    /* 
-     * In order to give the function variables a new 'scope' we
-     * change varsBase in the context.
-     */
-    oldBase = tctxt->varsBase;
-    tctxt->varsBase = tctxt->varsNr;
     xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
-                         func->content, NULL, params);
+                         func->content, NULL, NULL);
+    xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
     tctxt->insert = oldInsert;
     tctxt->varsBase = oldBase; /* restore original scope */
     if (params != NULL)
index 1c4f5c7..07f8d28 100644 (file)
@@ -173,8 +173,10 @@ templPop(xsltTransformContextPtr ctxt)
  * Pops all variable values at the given @depth from the stack.
  *
  * Returns the stored variable value
+ * **NOTE:**
+ * This is an internal routine and should not be called by users!
  */
-static void
+void
 xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
 {
     xsltStackElemPtr variable;
@@ -2067,7 +2069,19 @@ xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
     return(debugedNode);
 }
 
-static int
+/**
+ * xsltVariablePush:
+ * @ctxt: the transformation context
+ * @variable: variable to be pushed to the variable stack
+ * @level: new value for variable's level
+ *
+ * Places the variable onto the local variable stack
+ *
+ * Returns: 0 for success, -1 for any error
+ * **NOTE:**
+ * This is an internal routine and should not be called by users!
+ */
+int
 xsltLocalVariablePush(xsltTransformContextPtr ctxt,
                      xsltStackElemPtr variable,
                      int level)
@@ -3132,6 +3146,11 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
     CHECK_STOPPED;
 
     if (params) {
+       /*
+        * This code should be obsolete - was previously used
+        * by libexslt/functions.c, but due to bug 381319 the
+        * logic there was changed.
+        */
        int oldVarsNr = ctxt->varsNr;
 
        /*
index 1e030d2..105ac2d 100644 (file)
@@ -176,6 +176,16 @@ XSLTPUBFUN xmlNodePtr XSLTCALL
                                         xmlNodePtr target,
                                         const xmlChar *string,
                                         int noescape);
+
+/* Following 2 functions needed for libexslt/functions.c */
+XSLTPUBFUN void XSLTCALL
+               xsltLocalVariablePop    (xsltTransformContextPtr ctxt,
+                                        int limitNr,
+                                        int level);
+XSLTPUBFUN int XSLTCALL
+               xsltLocalVariablePush   (xsltTransformContextPtr ctxt,
+                                        xsltStackElemPtr variable,
+                                        int level);
 /*
  * Hook for the debugger if activated.
  */
index d5dc12f..d178746 100644 (file)
@@ -11,7 +11,8 @@ EXTRA_DIST =                                          \
        function.5.out  function.5.xml  function.5.xsl  \
        function.6.out  function.6.xml  function.6.xsl  \
        function.7.out  function.7.xml  function.7.xsl  \
-       function.8.out  function.8.xml  function.8.xsl
+       function.8.out  function.8.xml  function.8.xsl  \
+       function.9.out  function.9.xml  function.9.xsl
 
 all:
 
diff --git a/tests/exslt/functions/function.9.out b/tests/exslt/functions/function.9.out
new file mode 100644 (file)
index 0000000..1224d96
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+
+  
+      a                 
+    
+
diff --git a/tests/exslt/functions/function.9.xml b/tests/exslt/functions/function.9.xml
new file mode 100644 (file)
index 0000000..6a3c717
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<root>
+  <table>
+    <tr>
+      <td align="center">a</td>                 
+    </tr>
+  </table>
+</root>
+
diff --git a/tests/exslt/functions/function.9.xsl b/tests/exslt/functions/function.9.xsl
new file mode 100644 (file)
index 0000000..72d9599
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:exsl="http://exslt.org/common"
+  xmlns:func="http://exslt.org/functions"
+  xmlns:math="http://exslt.org/math"
+  xmlns:mg="mg"
+  extension-element-prefixes="exsl func">
+
+  <xsl:template match="table">          
+    <xsl:variable name="cols" select="mg:function(.)"/>         
+    <xsl:value-of select="$cols"/>
+  </xsl:template>       
+
+  <func:function name="mg:function">
+    <xsl:param name="table"/>
+    <xsl:param name="tr" select="$table/tr[1]"/>                
+    <func:result select="$tr"/>
+  </func:function>      
+</xsl:stylesheet>
+
+