add recursion watchdog, configuration function and preference 60/17260/6
Antoine ELIAS [Fri, 25 Sep 2015 12:39:42 +0000 (14:39 +0200)]
Change-Id: Ie9b3b988caf41a6018d0c07da29e8a5a417ebcb8

37 files changed:
scilab/CHANGES_6.0.X
scilab/modules/ast/includes/ast/runvisitor.hxx
scilab/modules/ast/includes/ast/scilabexception.hxx
scilab/modules/ast/includes/system_env/configvariable.hxx
scilab/modules/ast/includes/system_env/configvariable_interface.h
scilab/modules/ast/src/cpp/ast/runvisitor.cpp
scilab/modules/ast/src/cpp/system_env/configvariable.cpp
scilab/modules/ast/src/cpp/system_env/configvariable_interface.cpp
scilab/modules/ast/src/cpp/types/callable.cpp
scilab/modules/ast/src/cpp/types/function.cpp
scilab/modules/ast/src/cpp/types/overload.cpp
scilab/modules/commons/etc/XConfiguration-general.xsl [deleted file]
scilab/modules/commons/src/java/org/scilab/modules/commons/ScilabCommons.java
scilab/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsJNI.java
scilab/modules/commons/src/java/org/scilab/modules/commons/ScilabGeneralPrefs.java
scilab/modules/commons/src/jni/ScilabCommons.i
scilab/modules/commons/src/jni/ScilabCommons_wrap.c
scilab/modules/console/etc/XConfiguration-general.xml
scilab/modules/console/etc/XConfiguration-general.xsl
scilab/modules/core/Makefile.am
scilab/modules/core/Makefile.in
scilab/modules/core/help/en_US/configuration/recursionlimit.xml [new file with mode: 0644]
scilab/modules/core/includes/core_gw.hxx
scilab/modules/core/sci_gateway/cpp/core_gw.cpp
scilab/modules/core/sci_gateway/cpp/core_gw.vcxproj
scilab/modules/core/sci_gateway/cpp/core_gw.vcxproj.filters
scilab/modules/core/sci_gateway/cpp/sci_recursionlimit.cpp [new file with mode: 0644]
scilab/modules/core/src/c/InitializePreferences.c
scilab/modules/core/src/cpp/InitScilab.cpp
scilab/modules/core/src/cpp/runner.cpp
scilab/modules/core/tests/nonreg_tests/bug_14113.dia.ref [new file with mode: 0644]
scilab/modules/core/tests/nonreg_tests/bug_14113.tst [new file with mode: 0644]
scilab/modules/functions/sci_gateway/cpp/sci_exec.cpp
scilab/modules/functions/sci_gateway/cpp/sci_execstr.cpp
scilab/modules/preferences/etc/XConfiguration.xml
scilab/modules/preferences/includes/getScilabPreference.h
scilab/modules/preferences/src/c/getScilabPreference.c

index f672f35..06dcc82 100644 (file)
@@ -6,6 +6,9 @@ New Features
 
 * valgrind error detection added to test_run (Linux Only)
 
+* Introduction of a call stack limit. Default maximum depth is setup to 1000 and
+  can be changed by new function recursionlimit or by preferences interface.
+
 Deprecated Behaviors
 =====================
 
@@ -67,6 +70,8 @@ Scilab Bug Fixes
 
 * Bug #14109 fixed - lsq function crashed Scilab when Scilab version depended on mkl library.
 
+* Bug #14113 fixed - Scilab 6 did not detect infinite loop.
+
 * Bug #14144 fixed - Scilab crashed with int64(2^63).
 
 * Bug #14149 fixed - hdf5 could not restore hypermatrix with good dimensions.
index 47cd148..7211e99 100644 (file)
@@ -350,6 +350,7 @@ public :
     void visitprivate(const DAXPYExp &e);
     void visitprivate(const IntSelectExp &e);
     void visitprivate(const StringSelectExp &e);
+    void visitprivate(const TryCatchExp  &e);
 
     void visitprivate(const StringExp &e)
     {
@@ -460,30 +461,6 @@ public :
         setResult(types::Polynom::Dollar());
     }
 
-    void visitprivate(const TryCatchExp  &e)
-    {
-        //save current prompt mode
-        int oldVal = ConfigVariable::getSilentError();
-        //set mode silent for errors
-        ConfigVariable::setSilentError(1);
-        try
-        {
-            e.getTry().accept(*this);
-            //restore previous prompt mode
-            ConfigVariable::setSilentError(oldVal);
-        }
-        catch (const InternalError& /* ie */)
-        {
-            //restore previous prompt mode
-            ConfigVariable::setSilentError(oldVal);
-            //to lock lasterror
-            ConfigVariable::setLastErrorCall();
-            // reset call stack filled when error occured
-            ConfigVariable::resetWhereError();
-            e.getCatch().accept(*this);
-        }
-    }
-
     void visitprivate(const BreakExp &e)
     {
         const_cast<BreakExp*>(&e)->setBreak();
index 6558bac..33d8810 100644 (file)
@@ -144,10 +144,17 @@ public :
     }
 };
 
+
 class InternalAbort : public ScilabException
 {
-public :
+public:
     InternalAbort() {}
 };
+
+class RecursionException : public ScilabException
+{
+public:
+    RecursionException() {}
+};
 }
 #endif // !AST_SCILABEXCEPTION_HXX
index 7794ebd..ed807b1 100644 (file)
@@ -482,6 +482,19 @@ public :
     static bool isExecutionBreak();
     static void setExecutionBreak();
     static void resetExecutionBreak();
+    private:
+    static int recursionLimit;
+    static int recursionLevel;
+
+    // manage recursion stack
+public :
+    static int getRecursionLimit();
+    static int setRecursionLimit(int val);
+
+    static int getRecursionLevel();
+    static void resetRecursionLevel();
+    static bool increaseRecursion();
+    static void decreaseRecursion();
 };
 
 #endif /* !__CONFIGVARIABLE_HXX__ */
index 33dbb27..33f87d1 100644 (file)
@@ -83,4 +83,5 @@ EXTERN_AST int isExecutionBreak();
 EXTERN_AST void setExecutionBreak();
 EXTERN_AST void resetExecutionBreak();
 
+EXTERN_AST int setRecursionLimit(int);
 #endif /* !__CONFIGVARIABLE_INTERFACE_H__ */
index 9705c62..8756da4 100644 (file)
@@ -934,8 +934,6 @@ void RunVisitorT<T>::visitprivate(const SeqExp  &e)
             StaticRunner_setInterruptibleCommand(1);
         }
 
-
-
         try
         {
             //reset default values
@@ -1570,6 +1568,63 @@ void RunVisitorT<T>::visitprivate(const DAXPYExp &e)
     return;
 }
 
+template <class T>
+void RunVisitorT<T>::visitprivate(const TryCatchExp  &e)
+{
+    //save current prompt mode
+    int oldVal = ConfigVariable::getSilentError();
+    int oldMode = ConfigVariable::getPromptMode();
+    //set mode silent for errors
+    ConfigVariable::setSilentError(1);
+
+    symbol::Context* pCtx = symbol::Context::getInstance();
+    try
+    {
+        int scope = pCtx->getScopeLevel();
+        int level = ConfigVariable::getRecursionLevel();
+        try
+        {
+            e.getTry().accept(*this);
+            //restore previous prompt mode
+            ConfigVariable::setSilentError(oldVal);
+        }
+        catch (const RecursionException& /* re */)
+        {
+            ConfigVariable::setPromptMode(oldMode);
+
+            //close opened scope during try
+            while (pCtx->getScopeLevel() > scope)
+            {
+                pCtx->scope_end();
+            }
+
+            //decrease recursion to init value and close where
+            while (ConfigVariable::getRecursionLevel() > level)
+            {
+                ConfigVariable::where_end();
+                ConfigVariable::decreaseRecursion();
+            }
+
+            //print msg about recursion limit and trigger an error
+            wchar_t sz[1024];
+            os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
+            throw ast::InternalError(sz);
+        }
+
+    }
+    catch (const InternalError& /* ie */)
+    {
+        //restore previous prompt mode
+        ConfigVariable::setSilentError(oldVal);
+        //to lock lasterror
+        ConfigVariable::setLastErrorCall();
+        // reset call stack filled when error occured
+        ConfigVariable::resetWhereError();
+        e.getCatch().accept(*this);
+    }
+}
+
+
 } /* namespace ast */
 
 #include "run_CallExp.hpp"
index 201464e..8387c62 100644 (file)
@@ -1499,3 +1499,48 @@ void ConfigVariable::resetExecutionBreak()
 }
 
 
+#ifdef _DEBUG
+int ConfigVariable::recursionLimit = 25;
+#else
+int ConfigVariable::recursionLimit = 1000;
+#endif
+int ConfigVariable::recursionLevel = 0;
+
+int ConfigVariable::getRecursionLimit()
+{
+    return recursionLimit;
+}
+
+int ConfigVariable::setRecursionLimit(int val)
+{
+    int old = recursionLimit;
+    recursionLimit = std::max(10, val);
+    return old;
+}
+
+int ConfigVariable::getRecursionLevel()
+{
+    return recursionLevel;
+}
+
+bool ConfigVariable::increaseRecursion()
+{
+    if (recursionLevel < recursionLimit)
+    {
+        ++recursionLevel;
+        return true;
+    }
+
+    return false;
+}
+
+void ConfigVariable::decreaseRecursion()
+{
+    //recursionLevel = std::max(--recursionLevel, 0);
+    --recursionLevel;
+}
+
+void ConfigVariable::resetRecursionLevel()
+{
+    recursionLevel = 0;
+}
index f1afadb..8e9fc06 100644 (file)
@@ -212,3 +212,7 @@ void resetExecutionBreak()
     ConfigVariable::resetExecutionBreak();
 }
 
+int setRecursionLimit(int val)
+{
+    return ConfigVariable::setRecursionLimit(val);
+}
index 6905f82..ea66182 100644 (file)
@@ -22,42 +22,50 @@ namespace types
 
 bool Callable::invoke(typed_list & in, optional_list & opt, int _iRetCount, typed_list & out, const ast::Exp & e)
 {
-    //reset previous error before call function
-    ConfigVariable::resetError();
-    //update verbose";" flag
-    ConfigVariable::setVerbose(e.isVerbose());
-    // add line and function name in where
-    int iFirstLine = e.getLocation().first_line;
-    ConfigVariable::where_begin(iFirstLine + 1 - ConfigVariable::getMacroFirstLines(), iFirstLine, this);
-    Callable::ReturnValue Ret;
-
-    try
-    {
-        Ret = call(in, opt, _iRetCount, out);
-        ConfigVariable::where_end();
-    }
-    catch (ast::InternalError & ie)
+    //check recursion before try catch, to make difference with  errors
+    if (ConfigVariable::increaseRecursion())
     {
-        ConfigVariable::where_end();
-        ConfigVariable::setLastErrorFunction(getName());
+        //reset previous error before call function
+        ConfigVariable::resetError();
+        //update verbose";" flag
+        ConfigVariable::setVerbose(e.isVerbose());
+        // add line and function name in where
+        int iFirstLine = e.getLocation().first_line;
+        ConfigVariable::where_begin(iFirstLine + 1 - ConfigVariable::getMacroFirstLines(), iFirstLine, this);
+        Callable::ReturnValue Ret;
 
-        throw ie;
-    }
-    catch (ast::InternalAbort & ia)
-    {
-        ConfigVariable::where_end();
-        ConfigVariable::setLastErrorFunction(getName());
+        try
+        {
+            Ret = call(in, opt, _iRetCount, out);
+            ConfigVariable::where_end();
+            ConfigVariable::decreaseRecursion();
+        }
+        catch (ast::InternalError & ie)
+        {
+            ConfigVariable::where_end();
+            ConfigVariable::setLastErrorFunction(getName());
+            ConfigVariable::decreaseRecursion();
+            throw ie;
+        }
+        catch (ast::InternalAbort & ia)
+        {
+            ConfigVariable::where_end();
+            ConfigVariable::setLastErrorFunction(getName());
+            ConfigVariable::decreaseRecursion();
+            throw ia;
+        }
 
-        throw ia;
+        if (Ret == Callable::Error)
+        {
+            ConfigVariable::setLastErrorFunction(getName());
+            ConfigVariable::setLastErrorLine(e.getLocation().first_line);
+            throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
+        }
     }
-
-    if (Ret == Callable::Error)
+    else
     {
-        ConfigVariable::setLastErrorFunction(getName());
-        ConfigVariable::setLastErrorLine(e.getLocation().first_line);
-        throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
+        throw ast::RecursionException();
     }
-
     return true;
 }
 }
index 705fa35..a68750e 100644 (file)
@@ -31,7 +31,6 @@ extern "C"
 #include "sci_malloc.h"
 #include "os_string.h"
 #include "lasterror.h"
-#include "configvariable_interface.h"
 #include "dynamic_module.h"
 }
 
index b716224..3eb7e08 100644 (file)
@@ -107,20 +107,27 @@ types::Function::ReturnValue Overload::call(const std::wstring& _stOverloadingFu
             throw ie;
         }
 
-        pCall = pIT->getAs<types::Callable>();
-
-        types::optional_list opt;
+        if (ConfigVariable::increaseRecursion())
+        {
+            pCall = pIT->getAs<types::Callable>();
 
-        // add line and function name in where
-        ConfigVariable::where_begin(0, 0, pCall);
+            types::optional_list opt;
 
-        types::Function::ReturnValue ret;
-        ret = pCall->call(in, opt, _iRetCount, out);
+            // add line and function name in where
+            ConfigVariable::where_begin(0, 0, pCall);
 
-        // remove function name in where
-        ConfigVariable::where_end();
+            types::Function::ReturnValue ret;
+            ret = pCall->call(in, opt, _iRetCount, out);
 
-        return ret;
+            // remove function name in where
+            ConfigVariable::where_end();
+            ConfigVariable::decreaseRecursion();
+            return ret;
+        }
+        else
+        {
+            throw ast::RecursionException();
+        }
     }
     catch (ast::InternalError ie)
     {
@@ -135,6 +142,7 @@ types::Function::ReturnValue Overload::call(const std::wstring& _stOverloadingFu
 
             // remove function name in where
             ConfigVariable::where_end();
+            ConfigVariable::decreaseRecursion();
         }
 
         throw ie;
diff --git a/scilab/modules/commons/etc/XConfiguration-general.xsl b/scilab/modules/commons/etc/XConfiguration-general.xsl
deleted file mode 100644 (file)
index 8afa52c..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>\r
-<xsl:stylesheet version ="1.0"\r
-                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
-                ><!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r
-                      ::\r
-                      ::     M A I N   P A N E L :   G E N E R A L\r
-                      ::\r
-                 -->\r
-  <xsl:template match="environment" mode="tooltip">Settings environment</xsl:template>\r
-  <xsl:template match="environment">\r
-    <Title text="Environment">\r
-      <Grid>\r
-        <Label gridx="1" gridy="1" weightx="0" text="Floating point exception: "/>\r
-       <Panel gridx="2" gridy="1" weightx="1"/>\r
-        <Panel gridx="3" gridy="1" weightx="0">\r
-          <xsl:call-template name="Select">\r
-            <xsl:with-param name="among">\r
-              <option floating-point-exception="Produces an error"/>\r
-              <option floating-point-exception="Produces a warning"/>\r
-              <option floating-point-exception="Produces Inf or Nan"/>\r
-            </xsl:with-param>\r
-          </xsl:call-template>\r
-        </Panel>\r
-        <Label gridx="1" gridy="2" weightx="0" text="Printing format: "/>\r
-       <Panel gridx="2" gridy="2" weightx="1"/>\r
-        <Panel gridx="3" gridy="2" weightx="0">\r
-          <xsl:call-template name="Select">\r
-            <xsl:with-param name="among">\r
-              <option printing-format="short"/>\r
-              <option printing-format="long"/>\r
-              <option printing-format="short e"/>\r
-              <option printing-format="long e"/>\r
-              <option printing-format="short g"/>\r
-              <option printing-format="long g"/>\r
-              <option printing-format="variable format"/>\r
-            </xsl:with-param>\r
-          </xsl:call-template>\r
-        </Panel>\r
-        <Label gridx="1" gridy="3" weightx="0" text="Width: "/>\r
-       <Panel gridx="2" gridy="3" weightx="1"/>\r
-        <NumericalSpinner gridx="3"\r
-                          gridy="3"\r
-                         weightx="0"\r
-                          min-value = "1"\r
-                          increment = "1"\r
-                          length = "3"\r
-                          listener = "ActionListener"\r
-                          value = "{@width}">\r
-          <actionPerformed choose="width">\r
-            <xsl:call-template name="context"/>\r
-          </actionPerformed>\r
-        </NumericalSpinner>\r
-      </Grid>\r
-    </Title>\r
-  </xsl:template>\r
-\r
-  <xsl:template match="java-heap-memory" mode="tooltip"> and java heap size.</xsl:template>\r
-  <xsl:template match="java-heap-memory">\r
-    <VSpace height="25"/>\r
-    <Title text="Java Heap Memory">\r
-      <Grid>\r
-        <Label text="Select the memory (in MB) available in Java: " gridx="1" gridy="1" anchor="baseline" weightx="0"/>\r
-       <Panel gridx="2" gridy="1" weightx="1"/>\r
-        <NumericalSpinner min-value = "128"\r
-                          increment = "128"\r
-                          length = "6"\r
-                          listener = "ActionListener"\r
-                          value = "{@heap-size}"\r
-                         gridx="3" gridy="1" anchor="baseline" weightx="0">\r
-          <actionPerformed choose="heap-size">\r
-            <xsl:call-template name="context"/>\r
-          </actionPerformed>\r
-        </NumericalSpinner>\r
-      </Grid>\r
-    </Title>\r
-\r
-  </xsl:template>\r
-\r
-  <xsl:template match="tools">\r
-    <VBox>\r
-      <VSpace height="1"/>\r
-      <HBox>\r
-        <HSpace width="200"/>\r
-        <VBox>\r
-          <HBox>&lt;HTML&gt;&lt;I&gt;The following dialog boxes\r
-          require user confirmation.\r
-          </HBox>\r
-          <HBox>&lt;HTML&gt;&lt;I&gt;Select a check\r
-          box if you want that dialog box to appear.\r
-          </HBox>\r
-        </VBox>\r
-      </HBox>\r
-\r
-      <Title text="Confirmation dialogs">\r
-        <Grid>\r
-          <Label gridy="1" gridx="1" text="&lt;HTML&gt;&lt;B&gt;Dialog box description"/>\r
-          <Label gridy="1" gridx="2" text="&lt;HTML&gt;&lt;B&gt;Tool"/>\r
-          <Icon  gridy="1" gridx="3" listener="MouseListener">\r
-            <xsl:attribute name="src">\r
-              <xsl:choose>\r
-                <xsl:when test="@order='ascending'">\r
-                  <xsl:text>go-up.png</xsl:text>\r
-                </xsl:when>\r
-                <xsl:otherwise>\r
-                  <xsl:text>go-down.png</xsl:text>\r
-                </xsl:otherwise>\r
-              </xsl:choose>\r
-            </xsl:attribute>\r
-            <mouseClicked set="order">\r
-              <xsl:attribute name="value">\r
-                <xsl:choose>\r
-                  <xsl:when test="@order='ascending'">\r
-                    <xsl:text>descending</xsl:text>\r
-                  </xsl:when>\r
-                  <xsl:otherwise>\r
-                    <xsl:text>ascending</xsl:text>\r
-                  </xsl:otherwise>\r
-                </xsl:choose>\r
-              </xsl:attribute>\r
-              <xsl:call-template name="context"/>\r
-            </mouseClicked>\r
-          </Icon>\r
-          <xsl:for-each select="tool">\r
-            <xsl:sort order="{@order}" select="@name"/>\r
-            <Checkbox\r
-                gridy    = "{position() + 1}"\r
-                gridx    = "1"\r
-                listener = "ActionListener"\r
-                checked  = "{@state}"\r
-                text     = "{@description}"\r
-                >\r
-              <actionPerformed choose="state">\r
-                <xsl:call-template name="context"/>\r
-              </actionPerformed>\r
-            </Checkbox>\r
-            <Label\r
-                gridy    = "{position() + 1}"\r
-                gridx    = "2"\r
-                text     = "{@name}"/>\r
-          </xsl:for-each>\r
-        </Grid>\r
-      </Title>\r
-      <Glue/>\r
-      <HBox>\r
-        <Glue/>\r
-        <Button text="Select All" listener="ActionListener">\r
-          <xsl:for-each select="tool">\r
-            <actionPerformed set="state" value="checked">\r
-              <xsl:call-template name="context"/>\r
-            </actionPerformed>\r
-          </xsl:for-each>\r
-        </Button>\r
-        <Glue/>\r
-        <Button text="Clear All" listener="ActionListener">\r
-          <xsl:for-each select="tool">\r
-            <actionPerformed set="state" value="unchecked">\r
-              <xsl:call-template name="context"/>\r
-            </actionPerformed>\r
-          </xsl:for-each>\r
-        </Button>\r
-        <Glue/>\r
-      </HBox>\r
-    </VBox>\r
-  </xsl:template>\r
-\r
-  <xsl:template match="actions">\r
-    <Grid>\r
-      <Label gridy="1" gridx="1" text="Active settings: "/>\r
-      <Panel gridy="1" gridx="2">\r
-        <xsl:call-template name="Select">\r
-          <xsl:with-param name="among">\r
-            <option active="scilab"/>\r
-            <option active="emacs"/>\r
-            <option active="browse..."/>\r
-          </xsl:with-param>\r
-        </xsl:call-template>\r
-      </Panel>\r
-      <File gridy="2" gridx="1" gridwidth="2" href="{@browse}" mask="*.xml" desc="Choose a shortcut description file" listener="ActionListener">\r
-        <xsl:if test="not(@active='browse...')">\r
-          <xsl:attribute name="enable">false</xsl:attribute>\r
-        </xsl:if>\r
-        <actionPerformed choose="browse">\r
-          <xsl:call-template name="context"/>\r
-        </actionPerformed>\r
-      </File>\r
-      <Label gridy="3" gridx="1" gridwidth="2" text="Strike return to search by action name or shortcut:"/>\r
-      <Entry gridy="4" gridx="1" gridwidth="2" text="{@filter}" listener="ActionListener">\r
-        <actionPerformed choose="filter">\r
-          <xsl:call-template name="context"/>\r
-        </actionPerformed>\r
-      </Entry>\r
-    </Grid>\r
-    <Title background="#ffffff" text="General shortcuts preferences">\r
-      <VBox>\r
-        <xsl:variable name="filtered-actions"\r
-                      select="action-folder/action[contains(\r
-                              translate(\r
-                              concat(@description,@ctrl),\r
-                              'abcdefghijklmnopqrstuvwxyz',\r
-                              'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),\r
-                              translate(current()/@filter,\r
-                              'abcdefghijklmnopqrstuvwxyz',\r
-                              'ABCDEFGHIJKLMNOPQRSTUVWXYZ')\r
-                              )]"/>\r
-        <xsl:variable name="filtered-folder"\r
-                      select="action-folder[action [@description=$filtered-actions/@description][@ctrl=$filtered-actions/@ctrl]]"/>\r
-        <HBox>&lt;HTML&gt;&lt;B&gt;Action name\r
-        <Glue/>\r
-        <Label halign="right" text="&lt;HTML&gt;&lt;B&gt;Shortcut"/>\r
-        </HBox>\r
-        <VBox width="200" height="300">\r
-          <Scroll>\r
-            <Grid >\r
-              <VBox anchor="north">\r
-                <xsl:for-each select="$filtered-folder">\r
-                  <HBox>\r
-                    <Icon listener="MouseListener">\r
-                      <xsl:attribute name="src">\r
-                        <xsl:choose>\r
-                          <xsl:when test="@state='close'">\r
-                            <xsl:text>list-add.png</xsl:text>\r
-                          </xsl:when>\r
-                          <xsl:otherwise>\r
-                            <xsl:text>list-remove.png</xsl:text>\r
-                          </xsl:otherwise>\r
-                        </xsl:choose>\r
-                      </xsl:attribute>\r
-                      <mouseClicked set="state">\r
-                        <xsl:attribute name="value">\r
-                          <xsl:choose>\r
-                            <xsl:when test="@state='close'">\r
-                              <xsl:text>open</xsl:text>\r
-                            </xsl:when>\r
-                            <xsl:otherwise>\r
-                              <xsl:text>close</xsl:text>\r
-                            </xsl:otherwise>\r
-                          </xsl:choose>\r
-                        </xsl:attribute>\r
-                        <xsl:call-template name="context"/>\r
-                      </mouseClicked>\r
-                    </Icon>\r
-                    <Label text="  {@name}"/>\r
-                    <Glue/>\r
-                  </HBox>\r
-                  <xsl:if test="@state='open'">\r
-                    <xsl:for-each select="action[@description=$filtered-actions/@description][@ctrl=$filtered-actions/@ctrl]">\r
-                      <HBox>\r
-                        <HSpace width="30"/>\r
-                        <Label text="{@description}"/>\r
-                        <Glue/>\r
-                        <Label font-family="Courier 10 Pitch" text="{concat('CTRL + ', @ctrl)}"/>\r
-                      </HBox>\r
-                    </xsl:for-each>\r
-                  </xsl:if>\r
-                </xsl:for-each>\r
-              </VBox>\r
-            </Grid>\r
-          </Scroll>\r
-        </VBox>\r
-\r
-      </VBox>\r
-    </Title>\r
-    <HBox>\r
-      <Button text="Restore defaults"/>\r
-      <Glue/>\r
-    </HBox>\r
-    <Glue/>\r
-  </xsl:template>\r
-\r
-</xsl:stylesheet>\r
-\r
index aa06046..945c4b9 100644 (file)
@@ -122,4 +122,8 @@ public static String getScilabVersionAsString() {
     return ScilabCommonsJNI.getScilabVersionAsString();
   }
 
+  public static int setRecursionLimit(int arg0) {
+    return ScilabCommonsJNI.setRecursionLimit(arg0);
+  }
+
 }
index e2e72ac..502fd59 100644 (file)
@@ -58,4 +58,5 @@ public class ScilabCommonsJNI {
   public final static native int getScilabVersionMaintenance();
   public final static native int getScilabVersionTimestamp();
   public final static native String getScilabVersionAsString();
+  public final static native int setRecursionLimit(int jarg1);
 }
index 2da76ca..ba958e1 100644 (file)
@@ -56,6 +56,7 @@ public class ScilabGeneralPrefs implements XConfigurationListener {
             GeneralEnvironment ge = XConfiguration.get(GeneralEnvironment.class, doc, ENV_PATH)[0];
             ScilabCommons.setieee(ge.code);
             ScilabCommons.setformat(ge.format, ge.width);
+            ScilabCommons.setRecursionLimit(ge.recursionLimit);
         }
 
         if (e.getModifiedPaths().contains(LANG_PATH)) {
@@ -111,14 +112,16 @@ public class ScilabGeneralPrefs implements XConfigurationListener {
         public int code;
         public String format;
         public int width;
+        public int recursionLimit;
 
         private GeneralEnvironment() { }
 
-        @XConfAttribute(attributes = {"fpe", "printing-format", "width"})
-        private void set(int fpe, String format, int width) {
+        @XConfAttribute(attributes = {"fpe", "printing-format", "width", "recursion-limit"})
+        private void set(int fpe, String format, int width, int recursionLimit) {
             this.code = fpe;
             this.format = format;
             this.width = Math.min(Math.max(0, width), 25);
+            this.recursionLimit = recursionLimit;
         }
     }
 
index 4dc82d4..8fef323 100644 (file)
@@ -223,3 +223,11 @@ int getScilabVersionTimestamp();
    */
 public";
 char* getScilabVersionAsString();
+/* JavaDoc */
+%javamethodmodifiers setRecursionLimit() "
+ /**
+   * returns the Scilab version as string
+   * @return version Scilab version as a string
+   */
+public";
+int setRecursionLimit(int);
index de22fad..fb12cac 100644 (file)
@@ -418,6 +418,20 @@ SWIGEXPORT jstring JNICALL Java_org_scilab_modules_commons_ScilabCommonsJNI_getS
 }
 
 
+SWIGEXPORT jint JNICALL Java_org_scilab_modules_commons_ScilabCommonsJNI_setRecursionLimit(JNIEnv *jenv, jclass jcls, jint jarg1) {
+  jint jresult = 0 ;
+  int arg1 ;
+  int result;
+  
+  (void)jenv;
+  (void)jcls;
+  arg1 = (int)jarg1; 
+  result = (int)setRecursionLimit(arg1);
+  jresult = (jint)result; 
+  return jresult;
+}
+
+
 #ifdef __cplusplus
 }
 #endif
index 35ded47..4a5dcf2 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <general title="_(General)">
     <body>
-        <environment fpe="0" printing-format="v" width="10">
+        <environment fpe="0" printing-format="v" width="10" recursion-limit="1000">
             <fpe code="0" floating-point-exception="_(Produces an error)"/>
             <fpe code="1" floating-point-exception="_(Produces a warning)"/>
             <fpe code="2" floating-point-exception="_(Produces Inf or NaN)"/>
index 90bbdcc..2993503 100644 (file)
                         <xsl:call-template name="context"/>
                     </actionPerformed>
                 </NumericalSpinner>
+                <Label gridx="1" gridy="4" weightx="0" text="_(Recursion limit: )"/>
+                <Panel gridx="2" gridy="1" weightx="1"/>
+                <NumericalSpinner gridx="3" gridy="4" weightx="0" length="3"
+                    increment="1"
+                    min-value="10"
+                    listener="ActionListener"
+                    value="{@recursion-limit}">
+                    <actionPerformed choose="recursion-limit">
+                        <xsl:call-template name="context"/>
+                    </actionPerformed>
+                </NumericalSpinner>
             </Grid>
         </Title>
     </xsl:template>
             </Grid>
         </Title>
     </xsl:template>
-    
+
     <xsl:template match="startup">
         <VSpace height="10"/>
         <Title text="_(Start-up directory)">
index 35428cf..0d33220 100644 (file)
@@ -110,7 +110,8 @@ GATEWAY_CPP_SOURCES = \
        sci_gateway/cpp/sci_analyzeroptions.cpp \
        sci_gateway/cpp/sci_macr2tree.cpp \
        sci_gateway/cpp/sci_predef.cpp \
-       sci_gateway/cpp/sci_debug.cpp
+       sci_gateway/cpp/sci_debug.cpp \
+       sci_gateway/cpp/sci_recursionlimit.cpp
 
 libscicore_la_CPPFLAGS = \
     -I$(srcdir)/includes/ \
index 4efa48c..503473a 100644 (file)
@@ -285,7 +285,8 @@ am__objects_5 = sci_gateway/cpp/libscicore_la-core_gw.lo \
        sci_gateway/cpp/libscicore_la-sci_analyzeroptions.lo \
        sci_gateway/cpp/libscicore_la-sci_macr2tree.lo \
        sci_gateway/cpp/libscicore_la-sci_predef.lo \
-       sci_gateway/cpp/libscicore_la-sci_debug.lo
+       sci_gateway/cpp/libscicore_la-sci_debug.lo \
+       sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo
 am_libscicore_la_OBJECTS = $(am__objects_4) $(am__objects_5)
 libscicore_la_OBJECTS = $(am_libscicore_la_OBJECTS)
 libscicore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
@@ -782,7 +783,8 @@ GATEWAY_CPP_SOURCES = \
        sci_gateway/cpp/sci_analyzeroptions.cpp \
        sci_gateway/cpp/sci_macr2tree.cpp \
        sci_gateway/cpp/sci_predef.cpp \
-       sci_gateway/cpp/sci_debug.cpp
+       sci_gateway/cpp/sci_debug.cpp \
+       sci_gateway/cpp/sci_recursionlimit.cpp
 
 libscicore_la_CPPFLAGS = -I$(srcdir)/includes/ -I$(srcdir)/src/c/ \
        -I$(srcdir)/src/cpp/ -I$(top_srcdir)/modules/ast/includes/ast/ \
@@ -1303,6 +1305,9 @@ sci_gateway/cpp/libscicore_la-sci_predef.lo:  \
 sci_gateway/cpp/libscicore_la-sci_debug.lo:  \
        sci_gateway/cpp/$(am__dirstamp) \
        sci_gateway/cpp/$(DEPDIR)/$(am__dirstamp)
+sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo:  \
+       sci_gateway/cpp/$(am__dirstamp) \
+       sci_gateway/cpp/$(DEPDIR)/$(am__dirstamp)
 
 libscicore.la: $(libscicore_la_OBJECTS) $(libscicore_la_DEPENDENCIES) $(EXTRA_libscicore_la_DEPENDENCIES) 
        $(AM_V_CXXLD)$(libscicore_la_LINK) $(am_libscicore_la_rpath) $(libscicore_la_OBJECTS) $(libscicore_la_LIBADD) $(LIBS)
@@ -1360,6 +1365,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_pause.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_predef.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_quit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_recursionlimit.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_sciargs.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_typename.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_warning.Plo@am__quote@
@@ -2054,6 +2060,13 @@ sci_gateway/cpp/libscicore_la-sci_debug.lo: sci_gateway/cpp/sci_debug.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libscicore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sci_gateway/cpp/libscicore_la-sci_debug.lo `test -f 'sci_gateway/cpp/sci_debug.cpp' || echo '$(srcdir)/'`sci_gateway/cpp/sci_debug.cpp
 
+sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo: sci_gateway/cpp/sci_recursionlimit.cpp
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libscicore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo -MD -MP -MF sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_recursionlimit.Tpo -c -o sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo `test -f 'sci_gateway/cpp/sci_recursionlimit.cpp' || echo '$(srcdir)/'`sci_gateway/cpp/sci_recursionlimit.cpp
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_recursionlimit.Tpo sci_gateway/cpp/$(DEPDIR)/libscicore_la-sci_recursionlimit.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='sci_gateway/cpp/sci_recursionlimit.cpp' object='sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libscicore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sci_gateway/cpp/libscicore_la-sci_recursionlimit.lo `test -f 'sci_gateway/cpp/sci_recursionlimit.cpp' || echo '$(srcdir)/'`sci_gateway/cpp/sci_recursionlimit.cpp
+
 .f.o:
        $(AM_V_F77)$(F77COMPILE) -c -o $@ $<
 
diff --git a/scilab/modules/core/help/en_US/configuration/recursionlimit.xml b/scilab/modules/core/help/en_US/configuration/recursionlimit.xml
new file mode 100644 (file)
index 0000000..6856970
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns3="http://www.w3.org/1999/xhtml" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org" xml:id="recursionlimit" xml:lang="en">
+    <refnamediv>
+        <refname>recursionlimit</refname>
+        <refpurpose>get or set recursion limit</refpurpose>
+    </refnamediv>
+    <refsynopsisdiv>
+        <title>Calling Sequence</title>
+        <synopsis>limit = recursionlimit()
+            old = recursionlimit(new)
+            current = recursionlimit("current")
+        </synopsis>
+    </refsynopsisdiv>
+    <refsection>
+        <title>Arguments</title>
+        <variablelist>
+            <varlistentry>
+                <term>"current"</term>
+                    <para>used to get current recursion level</para>
+            </varlistentry>
+            <varlistentry>
+                <term>limit</term>
+                <listitem>
+                    <para>current recursion limit</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>new</term>
+                <listitem>
+                    <para>new recursion limit</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>old</term>
+                <listitem>
+                    <para>old recursion limit</para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsection>
+    <refsection>
+        <title>Description</title>
+        <para>
+        Use this function to change the recursion of Scilab.
+        each built-in, macro or overload is a level.
+        This parameter can be setup in Scilab preferences.
+        Default value is set to 1000.
+        </para>
+    </refsection>
+    <refsection>
+        <title>Examples</title>
+        <programlisting role="example"><![CDATA[
+recursionlimit(20);
+function testRecursion()
+    printf("recursion: %d\n", recursionlimit("current") - 1);
+    testRecursion;
+endfunction
+
+testRecursion;
+
+]]></programlisting>
+        <programlisting role="example"><![CDATA[
+//show that cos and %rec_cos increment the current recursion level.
+recursionlimit(40);
+function %rec_cos(val)
+    printf("recursion: %d\n", recursionlimit("current") - 1);
+    val.count = val.count + 1;
+    //disp(val.count);
+    cos(val);
+endfunction
+
+a = tlist(["rec", "count"], 0);
+cos(a)
+
+]]></programlisting>
+        <programlisting role="example"><![CDATA[
+recursionlimit(10);
+function [out] = recfib(in)
+    printf("recursion: %d\n", recursionlimit("current") - 1);
+    if in == 1  then
+        out = 1;
+    elseif in == 2
+        out = 1;
+    else
+        out = recfib(in-1) + recfib(in-2);
+    end
+endfunction
+
+recfib(10); //OK
+recfib(11); //KO
+]]></programlisting>
+    </refsection>
+    <refsection>
+        <title>History</title>
+        <revhistory>
+            <revision>
+                <revnumber>6.0.0</revnumber>
+                <revremark>
+                    Added in Scilab 6 familly
+                </revremark>
+            </revision>
+        </revhistory>
+    </refsection>
+</refentry>
index 0e72cff..0dc1952 100644 (file)
@@ -69,5 +69,6 @@ CPP_GATEWAY_PROTOTYPE(sci_analyzeroptions);
 CPP_GATEWAY_PROTOTYPE(sci_macr2tree);
 CPP_GATEWAY_PROTOTYPE(sci_predef);
 CPP_GATEWAY_PROTOTYPE(sci_debug);
+CPP_GATEWAY_PROTOTYPE(sci_recursionlimit);
 
 #endif /* __CORE_GW_HXX__ */
index 4cf2a52..02c0ba5 100644 (file)
@@ -62,5 +62,6 @@ int CoreModule::Load()
     symbol::Context::getInstance()->addFunction(types::Function::createFunction(L"macr2tree", &sci_macr2tree, MODULE_NAME));
     symbol::Context::getInstance()->addFunction(types::Function::createFunction(L"predef", &sci_predef, MODULE_NAME));
     symbol::Context::getInstance()->addFunction(types::Function::createFunction(L"debug", &sci_debug, MODULE_NAME));
+    symbol::Context::getInstance()->addFunction(types::Function::createFunction(L"recursionlimit", &sci_recursionlimit, MODULE_NAME));
     return 1;
 }
index 9647fa4..a160fcf 100644 (file)
     <ClCompile Include="sci_mode.cpp" />
     <ClCompile Include="sci_newfun.cpp" />
     <ClCompile Include="sci_predef.cpp" />
+    <ClCompile Include="sci_recursionlimit.cpp" />
     <ClCompile Include="sci_sciargs.cpp" />
     <ClCompile Include="..\c\sci_getdebuginfo.c" />
     <ClCompile Include="..\c\sci_type.c" />
index d3bac59..03b47d0 100644 (file)
     <ClCompile Include="sci_debug.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="sci_recursionlimit.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\includes\banner.hxx">
     <Library Include="..\..\..\..\bin\libintl.lib" />
     <Library Include="..\..\..\..\bin\libxml2.lib" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/scilab/modules/core/sci_gateway/cpp/sci_recursionlimit.cpp b/scilab/modules/core/sci_gateway/cpp/sci_recursionlimit.cpp
new file mode 100644 (file)
index 0000000..fe1022d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+*  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+*  Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
+*
+*  This file must be used under the terms of the CeCILL.
+*  This source file is licensed as described in the file COPYING, which
+*  you should have received as part of this distribution.  The terms
+*  are also available at
+*  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+*
+*/
+
+#include "core_gw.hxx"
+#include "function.hxx"
+#include "string.hxx"
+#include "double.hxx"
+#include "configvariable.hxx"
+
+extern "C"
+{
+#include "charEncoding.h"
+#include "localization.h"
+#include "Scierror.h"
+}
+
+static const char fname[] = "recursionLimit";
+
+types::Function::ReturnValue sci_recursionlimit(types::typed_list &in, int _iRetCount, types::typed_list &out)
+{
+    if (in.size() > 1)
+    {
+        Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), fname, 0, 1);
+        return types::Function::Error;
+    }
+
+    if (in.size() == 0)
+    {
+        out.push_back(new types::Double(ConfigVariable::getRecursionLimit()));
+        return types::Function::OK;
+    }
+
+    if (in[0]->isString())
+    {
+        types::String* s = in[0]->getAs<types::String>();
+        if (s->isScalar() == false || wcscmp(s->get()[0], L"current") != 0)
+        {
+            Scierror(999, _("%s: Wrong value for input argument #%d: '%s' expected.\n"), fname, 1, "current");
+            return types::Function::Error;
+        }
+
+        out.push_back(new types::Double(ConfigVariable::getRecursionLevel()));
+        return types::Function::OK;
+    }
+
+    if (in[0]->isDouble())
+    {
+        types::Double* d = in[0]->getAs<types::Double>();
+        if (d->isScalar() == false || d->get()[0] < 10)
+        {
+            Scierror(999, _("%s: Wrong value for input argument #%d: A value >= %d expected.\n"), fname, 1, 10);
+            return types::Function::Error;
+        }
+
+        out.push_back(new types::Double(ConfigVariable::getRecursionLimit()));
+        ConfigVariable::setRecursionLimit(static_cast<int>(d->get()[0]));
+        return types::Function::OK;
+    }
+
+    Scierror(999, _("%s: Wrong type for input argument #%d: String or integer expected.\n"), fname, 1);
+    return types::Function::Error;
+
+}
\ No newline at end of file
index a926843..3dbd8aa 100644 (file)
 void InitializePreferences(int useCWD)
 {
     const ScilabPreferences * prefs = getScilabPreferences();
-    int ieee = 0;
-    int lines = 0;
-    int cols = 0;
-    int formatWidth = 0;
-    int historyLines = 0;
 
     // Set ieee
     if (prefs->ieee)
     {
-        ieee = atoi(prefs->ieee);
+        int ieee = atoi(prefs->ieee);
         setieee(ieee);
     }
 
     // Set format
     if (prefs->formatWidth && prefs->format)
     {
-        formatWidth = (int)atof(prefs->formatWidth);
+        int formatWidth = (int)atof(prefs->formatWidth);
         formatWidth = Max(0, formatWidth);
         formatWidth = Min(25, formatWidth);
         setformat(prefs->format, formatWidth);
@@ -55,6 +50,7 @@ void InitializePreferences(int useCWD)
         {
             if (prefs->historyFile && prefs->historyLines)
             {
+                int historyLines = 0;
                 InitializeHistoryManager();
                 setFilenameScilabHistory((char*)prefs->historyFile);
                 historyLines = (int)atof(prefs->historyLines);
@@ -76,8 +72,8 @@ void InitializePreferences(int useCWD)
         if (stricmp(prefs->adaptToDisplay, "true"))
         {
             // it is not true so ...
-            lines = (int)atof(prefs->linesToDisplay);
-            cols = (int)atof(prefs->columnsToDisplay);
+            int lines = (int)atof(prefs->linesToDisplay);
+            int cols = (int)atof(prefs->columnsToDisplay);
             setConsoleLines(lines);
             setConsoleWidth(cols);
         }
@@ -100,5 +96,13 @@ void InitializePreferences(int useCWD)
         }
     }
 
+    //recursion limit
+    if (prefs->recursionlimit)
+    {
+        int recursionlimit = atoi(prefs->recursionlimit);
+        setRecursionLimit(recursionlimit);
+    }
+
+
     clearScilabPreferences();
 }
index 0a060f9..f2b8094 100644 (file)
@@ -48,7 +48,6 @@ extern "C"
 #include "TerminateGraphics.h"
 #include "loadBackGroundClassPath.h"
 #include "sci_tmpdir.h"
-#include "configvariable_interface.h"
 #include "setgetlanguage.h"
 #include "InitializeConsole.h"
 #include "InitializeHistoryManager.h"
@@ -846,6 +845,10 @@ static int interactiveMain(ScilabEngineInfo* _pSEI)
         {
             // go out when exit/quit is called
         }
+        catch (const ast::RecursionException& /*ia*/)
+        {
+            // go out when exit/quit is called
+        }
         ThreadManagement::SendAwakeRunnerSignal();
     }
     while (ConfigVariable::getForceQuit() == false);
index 8e5b89f..b62a3b5 100644 (file)
@@ -21,6 +21,7 @@ extern "C"
 #include "BrowseVarManager.h"
 #include "FileBrowserChDir.h"
 #include "scicurdir.h"
+#include "Scierror.h"
 }
 
 std::atomic<Runner*> StaticRunner::m_RunMe(nullptr);
@@ -35,9 +36,48 @@ void StaticRunner::launch()
     debugger::DebuggerMagager* manager = debugger::DebuggerMagager::getInstance();
 
     ConfigVariable::resetExecutionBreak();
+    int oldMode = ConfigVariable::getPromptMode();
+    symbol::Context* pCtx = symbol::Context::getInstance();
+    int scope = pCtx->getScopeLevel();
+
     try
     {
-        runMe->getProgram()->accept(*(runMe->getVisitor()));
+        int level = ConfigVariable::getRecursionLevel();
+        try
+        {
+            runMe->getProgram()->accept(*(runMe->getVisitor()));
+        }
+        catch (const ast::RecursionException& re)
+        {
+            // management of pause
+            if (ConfigVariable::getPauseLevel())
+            {
+                ConfigVariable::DecreasePauseLevel();
+                delete runMe;
+                throw re;
+            }
+
+            //close opened scope during try
+            while (pCtx->getScopeLevel() > scope)
+            {
+                pCtx->scope_end();
+            }
+
+            //decrease recursion to init value and close where
+            while (ConfigVariable::getRecursionLevel() > level)
+            {
+                ConfigVariable::where_end();
+                ConfigVariable::decreaseRecursion();
+            }
+
+            ConfigVariable::resetWhereError();
+            ConfigVariable::setPromptMode(oldMode);
+
+            //print msg about recursion limit and trigger an error
+            wchar_t sz[1024];
+            os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
+            throw ast::InternalError(sz);
+        }
     }
     catch (const ast::InternalError& se)
     {
@@ -60,7 +100,7 @@ void StaticRunner::launch()
 
         // close all scope before return to console scope
         symbol::Context* pCtx = symbol::Context::getInstance();
-        while (pCtx->getScopeLevel() != SCOPE_CONSOLE)
+        while (pCtx->getScopeLevel() > scope)
         {
             pCtx->scope_end();
         }
diff --git a/scilab/modules/core/tests/nonreg_tests/bug_14113.dia.ref b/scilab/modules/core/tests/nonreg_tests/bug_14113.dia.ref
new file mode 100644 (file)
index 0000000..ed56c4f
--- /dev/null
@@ -0,0 +1,23 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+//
+// <-- Non-regression test for bug 14113 -->
+//
+// <-- CLI SHELL MODE -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/14113
+//
+// <-- Short Description -->
+// infinite loop is not detected
+old = recursionlimit(20);
+function f()
+    f();
+endfunction
+msg = msprintf(_("Recursion limit reached (%d).\n"), recursionlimit());
+assert_checkerror("f()", msg);
+recursionlimit(old);
diff --git a/scilab/modules/core/tests/nonreg_tests/bug_14113.tst b/scilab/modules/core/tests/nonreg_tests/bug_14113.tst
new file mode 100644 (file)
index 0000000..b8fa0b3
--- /dev/null
@@ -0,0 +1,26 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+//
+// <-- Non-regression test for bug 14113 -->
+//
+// <-- CLI SHELL MODE -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/14113
+//
+// <-- Short Description -->
+// infinite loop is not detected
+
+old = recursionlimit(20);
+function f()
+    f();
+endfunction
+
+msg = msprintf(_("Recursion limit reached (%d).\n"), recursionlimit());
+assert_checkerror("f()", msg);
+
+recursionlimit(old);
index 0cbf244..b6f5a3e 100644 (file)
@@ -286,12 +286,38 @@ types::Function::ReturnValue sci_exec(types::typed_list &in, int _iRetCount, typ
     if (file == NULL || promptMode == 0 || promptMode == 2)
     {
         ast::SeqExp* pSeqExp = pExp->getAs<ast::SeqExp>();
+        ast::ConstVisitor* exec = ConfigVariable::getDefaultVisitor();
 
         try
         {
-            ast::ConstVisitor* exec = ConfigVariable::getDefaultVisitor();
-            pSeqExp->accept(*exec);
-            delete exec;
+            symbol::Context* pCtx = symbol::Context::getInstance();
+            int scope = pCtx->getScopeLevel();
+            int level = ConfigVariable::getRecursionLevel();
+            try
+            {
+                pSeqExp->accept(*exec);
+                delete exec;
+            }
+            catch (const ast::RecursionException& /* re */)
+            {
+                //close opened scope during try
+                while (pCtx->getScopeLevel() > scope)
+                {
+                    pCtx->scope_end();
+                }
+
+                //decrease recursion to init value
+                while (ConfigVariable::getRecursionLevel() > level)
+                {
+                    ConfigVariable::where_end();
+                    ConfigVariable::decreaseRecursion();
+                }
+
+                //print msg about recursion limit and trigger an error
+                wchar_t sz[1024];
+                os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
+                throw ast::InternalError(sz);
+            }
         }
         catch (const ast::InternalAbort& ia)
         {
@@ -365,19 +391,46 @@ types::Function::ReturnValue sci_exec(types::typed_list &in, int _iRetCount, typ
             someExps->assign(j, k);
             k--;
             ast::SeqExp seqExp(Location((*j)->getLocation().first_line,
-                (*k)->getLocation().last_line,
-                (*j)->getLocation().first_column,
-                (*k)->getLocation().last_column),
-                *someExps);
+                                        (*k)->getLocation().last_line,
+                                        (*j)->getLocation().first_column,
+                                        (*k)->getLocation().last_column),
+                               *someExps);
 
             j = k;
 
+            ast::ConstVisitor* exec = ConfigVariable::getDefaultVisitor();
+
             try
             {
-                // execute printed exp
-                ast::ConstVisitor* exec = ConfigVariable::getDefaultVisitor();
-                seqExp.accept(*exec);
-                delete exec;
+                symbol::Context* pCtx = symbol::Context::getInstance();
+                int scope = pCtx->getScopeLevel();
+                int level = ConfigVariable::getRecursionLevel();
+                try
+                {
+                    // execute printed exp
+                    seqExp.accept(*exec);
+                    delete exec;
+                }
+                catch (const ast::RecursionException& /* re */)
+                {
+                    //close opened scope during try
+                    while (pCtx->getScopeLevel() > scope)
+                    {
+                        pCtx->scope_end();
+                    }
+
+                    //decrease recursion to init value
+                    while (ConfigVariable::getRecursionLevel() > level)
+                    {
+                        ConfigVariable::where_end();
+                        ConfigVariable::decreaseRecursion();
+                    }
+
+                    //print msg about recursion limit and trigger an error
+                    wchar_t sz[1024];
+                    os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
+                    throw ast::InternalError(sz);
+                }
             }
             catch (const ast::InternalAbort& ia)
             {
index 8b1b267..ce47ffa 100644 (file)
@@ -201,11 +201,38 @@ types::Function::ReturnValue sci_execstr(types::typed_list &in, int _iRetCount,
     // to manage line displayed when error occured.
     ConfigVariable::macroFirstLine_begin(1);
 
+    ast::ConstVisitor* run = ConfigVariable::getDefaultVisitor();
+
     try
     {
-        ast::ConstVisitor* run = ConfigVariable::getDefaultVisitor();
-        pSeqExp->accept(*run);
-        delete run;
+        symbol::Context* pCtx = symbol::Context::getInstance();
+        int scope = pCtx->getScopeLevel();
+        int level = ConfigVariable::getRecursionLevel();
+        try
+        {
+            pSeqExp->accept(*run);
+            delete run;
+        }
+        catch (const ast::RecursionException& /* re */)
+        {
+            //close opened scope during try
+            while (pCtx->getScopeLevel() > scope)
+            {
+                pCtx->scope_end();
+            }
+
+            //decrease recursion to init value
+            while (ConfigVariable::getRecursionLevel() > level)
+            {
+                ConfigVariable::where_end();
+                ConfigVariable::decreaseRecursion();
+            }
+
+            //print msg about recursion limit and trigger an error
+            wchar_t sz[1024];
+            os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
+            throw ast::InternalError(sz);
+        }
     }
     catch (const ast::InternalError& ie)
     {
index 400ade4..f5c6739 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<interface version="0.18" path="1/" width="800" height="600">
+<interface version="0.19" path="1/" width="800" height="600">
     <general/>
     <web/>
     <preference/>
index 15cb5a0..2c7109a 100644 (file)
@@ -32,6 +32,7 @@ typedef struct
     const char * startup_dir_use;
     const char * startup_dir_default;
     const char * startup_dir_previous;
+    const char * recursionlimit;
 } ScilabPreferences;
 
 #define HEAPSIZE_XPATH (const xmlChar*)"//general/body/java-heap-memory/@heap-size"
@@ -45,6 +46,7 @@ typedef struct
 #define IEEE_XPATH (const xmlChar*)"//general/body/environment/@fpe"
 #define FORMAT_XPATH (const xmlChar*)"//general/body/environment/@printing-format"
 #define FORMATWIDTH_XPATH (const xmlChar*)"//general/body/environment/@width"
+#define RECURSIONLIMIT_XPATH (const xmlChar*)"//general/body/environment/@recursion-limit"
 #define LANGUAGE_XPATH (const xmlChar*)"//general/body/languages/@lang"
 #define STARTUP_DIR_USE_XPATH (const xmlChar*)"//general/body/startup/@use"
 #define STARTUP_DIR_DEFAULT_XPATH (const xmlChar*)"//general/body/startup/@default"
index 2717a94..5693318 100644 (file)
@@ -58,6 +58,7 @@ void initPrefs()
     scilabPref.startup_dir_use = NULL;
     scilabPref.startup_dir_default = NULL;
     scilabPref.startup_dir_previous = NULL;
+    scilabPref.recursionlimit = NULL;
 }
 /*--------------------------------------------------------------------------*/
 void reloadScilabPreferences()
@@ -130,6 +131,10 @@ void clearScilabPreferences()
         {
             FREE((void*)scilabPref.startup_dir_previous);
         }
+        if (scilabPref.recursionlimit)
+        {
+            FREE((void*)scilabPref.recursionlimit);
+        }
         initPrefs();
     }
     isInit = 0;
@@ -165,6 +170,7 @@ void getPrefs()
         scilabPref.startup_dir_use = os_strdup(getAttribute(doc, xpathCtxt, (char*)STARTUP_DIR_USE_XPATH));
         scilabPref.startup_dir_default = os_strdup(getAttribute(doc, xpathCtxt, (char*)STARTUP_DIR_DEFAULT_XPATH));
         scilabPref.startup_dir_previous = os_strdup(getAttribute(doc, xpathCtxt, (char*)STARTUP_DIR_PREVIOUS_XPATH));
+        scilabPref.recursionlimit = os_strdup(getAttribute(doc, xpathCtxt, (char*)RECURSIONLIMIT_XPATH));
 
         xmlXPathFreeContext(xpathCtxt);
         xmlFreeDoc(doc);