further enhancement to the original fix for bug #381319 (which was not
authorWilliam M. Brack <wbrack@src.gnome.org>
Mon, 11 Dec 2006 22:51:47 +0000 (22:51 +0000)
committerWilliam M. Brack <wbrack@src.gnome.org>
Mon, 11 Dec 2006 22:51:47 +0000 (22:51 +0000)
* libexslt/functions.c: further enhancement to the original
  fix for bug #381319 (which was not correct).
* tests/exslt/functions: minor enhancement to function.9.xsl;
  function.10.[xsl,xml,out] added to regression tests to check
  recursive calls.

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

index 65c71bd..b325594 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Dec 11 14:38:22 PST 2006 William Brack <wbrack@mmm.com.hk>
+
+       * libexslt/functions.c: further enhancement to the original
+         fix for bug #381319 (which was not correct).
+       * tests/exslt/functions: minor enhancement to function.9.xsl;
+         function.10.[xsl,xml,out] added to regression tests to check
+         recursive calls.
+
 Mon Dec 11 12:13:14 CET 2006 Daniel Veillard <daniel@veillard.com>
 
        * configure python/generator.py python/libxsl.py
index 58bd71e..e7ae02b 100644 (file)
@@ -274,14 +274,19 @@ exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
  */
 static void
 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
-    xmlXPathObjectPtr obj, oldResult, ret;
+    xmlXPathObjectPtr oldResult, ret;
     exsltFuncData *data;
     exsltFuncFunctionData *func;
     xmlNodePtr paramNode, oldInsert, fake;
     int oldBase;
     xsltStackElemPtr params = NULL, param;
     xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
-    int i, notSet;;
+    int i, notSet;
+    struct objChain {
+       struct objChain *next;
+       xmlXPathObjectPtr obj;
+    };
+    struct objChain    *savedObjChain = NULL, *savedObj;
 
     /*
      * retrieve func:function template
@@ -316,40 +321,65 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
                         "param == NULL\n");
        return;
     }
+    /*
+     * We have a problem with the evaluation of function parameters.
+     * The original library code did not evaluate XPath expressions until
+     * the last moment.  After version 1.1.17 of the libxslt, the logic
+     * of other parts of the library was changed, and the evaluation of
+     * XPath expressions within parameters now takes place as soon as the
+     * parameter is parsed/evaluated (xsltParseStylesheetCallerParam).
+     * This means that the parameters need to be evaluated in lexical
+     * order (since a variable is "in scope" as soon as it is declared).
+     * However, on entry to this routine, the values (from the caller) are
+     * in reverse order (held on the XPath context variable stack).  To
+     * accomplish what is required, I have added code to pop the XPath
+     * objects off of the stack at the beginning and save them, then use
+     * them (in the reverse order) as the params are evaluated.  This
+     * requires an xmlMalloc/xmlFree for each param set by the caller,
+     * which is not very nice.  There is probably a much better solution
+     * (like change other code to delay the evaluation).
+     */
     /* 
      * 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) {
+        /* Fetch the stored argument values from the caller */
+       for (i = 0; i < nargs; i++) {
+           savedObj = xmlMalloc(sizeof(struct objChain));
+           savedObj->next = savedObjChain;
+           savedObj->obj = valuePop(ctxt);
+           savedObjChain = savedObj;
+       }
+
        /*
-        * 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.
+        * Prepare to process params in reverse order.  First, go to
+        * the beginning of the param chain.
         */
        for (i = 1; i <= func->nargs; i++) {
-           if (paramNode->prev == NULL)
-               break;
+           if (paramNode->prev == NULL)
+               break;
            paramNode = paramNode->prev;
        }
        /*
         * i has total # params found, nargs is number which are present
         * as arguments from the caller
+        * Calculate the number of un-set parameters
         */
        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;
+               savedObj = savedObjChain;       /* get next val from chain */
+               param->value = savedObj->obj;
+               savedObjChain = savedObjChain->next;
+               xmlFree(savedObj);
            }
            xsltLocalVariablePush(tctxt, param, -1);
            param->next = params;
index d178746..88e8c8d 100644 (file)
@@ -12,7 +12,8 @@ EXTRA_DIST =                                          \
        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.9.out  function.9.xml  function.9.xsl
+       function.9.out  function.9.xml  function.9.xsl  \
+       function.10.out function.10.xml function.10.xsl
 
 all:
 
diff --git a/tests/exslt/functions/function.10.err b/tests/exslt/functions/function.10.err
new file mode 100644 (file)
index 0000000..d45035b
--- /dev/null
@@ -0,0 +1,5 @@
+using 5 and 1
+using 4 and 1
+using 3 and 1
+using 2 and 1
+using 1 and 1
diff --git a/tests/exslt/functions/function.10.out b/tests/exslt/functions/function.10.out
new file mode 100644 (file)
index 0000000..9eb1fda
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+15
diff --git a/tests/exslt/functions/function.10.xml b/tests/exslt/functions/function.10.xml
new file mode 100644 (file)
index 0000000..e586af3
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<root>
+   <a>5</a>
+   <b>1</b>
+</root>
diff --git a/tests/exslt/functions/function.10.xsl b/tests/exslt/functions/function.10.xsl
new file mode 100644 (file)
index 0000000..089911f
--- /dev/null
@@ -0,0 +1,26 @@
+<xsl:stylesheet version="1.0" 
+   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+   xmlns:func="http://exslt.org/functions"   
+   xmlns:mg="mg"
+   extension-element-prefixes="func">
+
+   <xsl:template match="root">
+      <xsl:value-of select="mg:recurse(a, b)"/>
+   </xsl:template>
+
+   <func:function name="mg:recurse">
+      <xsl:param name="a"/>
+      <xsl:param name="b"/>
+      <xsl:choose>
+         <xsl:when test="$a > 0">            
+           <xsl:message>using <xsl:value-of select="$a"/> and <xsl:value-of select="$b"/></xsl:message>
+            <func:result select="$a+mg:recurse($a - $b, $b)"/>
+         </xsl:when>
+         <xsl:otherwise>
+            <func:result select="0"/>
+         </xsl:otherwise>
+      </xsl:choose>     
+   </func:function>
+</xsl:stylesheet>
+
+
index 72d9599..f609280 100644 (file)
@@ -8,13 +8,15 @@
   extension-element-prefixes="exsl func">
 
   <xsl:template match="table">          
-    <xsl:variable name="cols" select="mg:function(.)"/>         
+    <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="t2" select="$table/tr[1]"/>
     <xsl:param name="tr" select="$table/tr[1]"/>                
+    <xsl:param name="trd" select="$tr/td[1]"/>
     <func:result select="$tr"/>
   </func:function>      
 </xsl:stylesheet>