[Libreoffice-commits] core.git: 8 commits - config_host/config_options_calc.h.in config_host.mk.in configure.ac sc/inc sc/Library_sc.mk sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Wed Oct 26 03:56:53 UTC 2016


 config_host.mk.in                     |    1 
 config_host/config_options_calc.h.in  |   10 +
 configure.ac                          |   22 +++
 sc/Library_sc.mk                      |    6 
 sc/inc/formulalogger.hxx              |  127 ++++++++++++++++++
 sc/source/core/data/formulacell.cxx   |   18 ++
 sc/source/core/tool/formulalogger.cxx |  238 ++++++++++++++++++++++++++++++++++
 7 files changed, 422 insertions(+)

New commits:
commit 9c34797cc98030614b384b6ea0f233d59ae82253
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Oct 25 07:24:40 2016 -0400

    Keep loplugin:staticmethods happy.
    
    Change-Id: I45b576a4401d51d204007a8dde3b24617b5a17e9

diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
index 1348c63..10a0155 100644
--- a/sc/inc/formulalogger.hxx
+++ b/sc/inc/formulalogger.hxx
@@ -95,6 +95,7 @@ public:
  */
 class FormulaLogger
 {
+    bool mbState = false; // Just to avoid loplugin:staticmethods
 public:
 
     static FormulaLogger get()
@@ -104,13 +105,15 @@ public:
 
     class GroupScope
     {
+        bool mbState = false; // Just to avoid loplugin:staticmethods
     public:
-        void addMessage( const OUString& /*rMsg*/ ) {}
-        void setCalcComplete() {}
+        void addMessage( const OUString& /*rMsg*/ ) { mbState = !mbState; }
+        void setCalcComplete() { mbState = !mbState; }
     };
 
     GroupScope enterGroup( const ScDocument& /*rDoc*/, const ScFormulaCell& /*rCell*/ )
     {
+        mbState = !mbState;
         return GroupScope();
     }
 };
commit dff4e51f5db23baab368ab7e656ad1b74f2663bd
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Oct 24 18:56:51 2016 -0400

    Add configure option --enable-formula-logger to conditionalize it.
    
    Change-Id: I1badbcfa259b22d742e5241bd817ea44769a771e

diff --git a/config_host.mk.in b/config_host.mk.in
index 90c25a6..260acf7 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -130,6 +130,7 @@ export ENABLE_DIRECTX=@ENABLE_DIRECTX@
 export ENABLE_EOT=@ENABLE_EOT@
 export ENABLE_EVOAB2=@ENABLE_EVOAB2@
 export ENABLE_FIREBIRD_SDBC=@ENABLE_FIREBIRD_SDBC@
+export ENABLE_FORMULA_LOGGER=@ENABLE_FORMULA_LOGGER@
 export ENABLE_GIO=@ENABLE_GIO@
 export ENABLE_GRAPHITE=@ENABLE_GRAPHITE@
 export ENABLE_ORCUS=@ENABLE_ORCUS@
diff --git a/config_host/config_options_calc.h.in b/config_host/config_options_calc.h.in
new file mode 100644
index 0000000..f369797
--- /dev/null
+++ b/config_host/config_options_calc.h.in
@@ -0,0 +1,10 @@
+/*
+ * General configuration settings for various options specific to Calc.
+ */
+
+#ifndef CONFIG_OPTIONS_CALC_H
+#define CONFIG_OPTIONS_CALC_H
+
+#define ENABLE_FORMULA_LOGGER 0
+
+#endif
diff --git a/configure.ac b/configure.ac
index af07d13..f06ef8e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1515,6 +1515,13 @@ AC_ARG_ENABLE(dconf,
         [Disable the dconf configuration backend (enabled by default where
          available).]))
 
+AC_ARG_ENABLE(formula-logger,
+    AS_HELP_STRING(
+        [--enable-formula-logger],
+        [Enable formula logger for logging formula calculation flow in Calc.]
+    )
+)
+
 dnl ===================================================================
 dnl Optional Packages (--with/without-)
 dnl ===================================================================
@@ -12754,6 +12761,20 @@ else
 fi
 AC_SUBST(MPL_SUBSET)
 
+dnl ===================================================================
+
+AC_MSG_CHECKING([formula logger])
+ENABLE_FORMULA_LOGGER=
+
+if test "x$enable_formula_logger" = "xyes"; then
+    AC_MSG_RESULT([yes])
+    AC_DEFINE(ENABLE_FORMULA_LOGGER)
+    ENABLE_FORMULA_LOGGER=TRUE
+else
+    AC_MSG_RESULT([no])
+fi
+
+AC_SUBST(ENABLE_FORMULA_LOGGER)
 
 dnl ===================================================================
 dnl Setting up the environment.
@@ -12927,6 +12948,7 @@ AC_CONFIG_HEADERS([config_host/config_kde4.h])
 AC_CONFIG_HEADERS([config_host/config_oox.h])
 AC_CONFIG_HEADERS([config_host/config_opengl.h])
 AC_CONFIG_HEADERS([config_host/config_options.h])
+AC_CONFIG_HEADERS([config_host/config_options_calc.h])
 AC_CONFIG_HEADERS([config_host/config_test.h])
 AC_CONFIG_HEADERS([config_host/config_telepathy.h])
 AC_CONFIG_HEADERS([config_host/config_typesizes.h])
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index f3abc81..0e21903 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -230,7 +230,6 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/core/tool/editutil \
     sc/source/core/tool/filtopt \
     sc/source/core/tool/formulagroup \
-    sc/source/core/tool/formulalogger \
     sc/source/core/tool/formulaopt \
     sc/source/core/tool/formulaparserpool \
     sc/source/core/tool/formularesult \
@@ -671,6 +670,12 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/ui/xmlsource/xmlsourcedlg \
 ))
 
+ifeq ($(ENABLE_FORMULA_LOGGER),TRUE)
+$(eval $(call gb_Library_add_exception_objects,sc,\
+    sc/source/core/tool/formulalogger \
+))
+endif
+
 ifneq (,$(gb_ENABLE_DBGUTIL))
 $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/ui/view/gridwin_dbgutil \
diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
index 144fabf..1348c63 100644
--- a/sc/inc/formulalogger.hxx
+++ b/sc/inc/formulalogger.hxx
@@ -12,11 +12,15 @@
 #include <memory>
 #include <vector>
 
+#include <config_options_calc.h>
+
 class ScFormulaCell;
 class ScDocument;
 
 namespace sc {
 
+#if ENABLE_FORMULA_LOGGER
+
 /**
  * Outputs formula calculation log outputs to specified file.
  */
@@ -84,6 +88,35 @@ public:
     GroupScope enterGroup( const ScDocument& rDoc, const ScFormulaCell& rCell );
 };
 
+#else
+
+/**
+ * Dummy class with all empty inline methods.
+ */
+class FormulaLogger
+{
+public:
+
+    static FormulaLogger get()
+    {
+        return FormulaLogger();
+    }
+
+    class GroupScope
+    {
+    public:
+        void addMessage( const OUString& /*rMsg*/ ) {}
+        void setCalcComplete() {}
+    };
+
+    GroupScope enterGroup( const ScDocument& /*rDoc*/, const ScFormulaCell& /*rCell*/ )
+    {
+        return GroupScope();
+    }
+};
+
+#endif // ENABLE_FORMULA_LOGGER
+
 }
 
 #endif
commit 08086d76f86794963b3ab27168f9516edf7b9d2d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Oct 22 21:36:22 2016 -0400

    Ensure that GroupScope can only be instantiated by FormulaLogger.
    
    And also annotate the class a bit.
    
    Change-Id: I7544e49991778be36a9214851f3d7add4bfef626

diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
index d272ed0..144fabf 100644
--- a/sc/inc/formulalogger.hxx
+++ b/sc/inc/formulalogger.hxx
@@ -17,6 +17,9 @@ class ScDocument;
 
 namespace sc {
 
+/**
+ * Outputs formula calculation log outputs to specified file.
+ */
 class FormulaLogger
 {
     std::unique_ptr<osl::File> mpLogFile;
@@ -42,6 +45,8 @@ public:
      */
     class GroupScope
     {
+        friend class FormulaLogger;
+
         struct Impl;
         std::unique_ptr<Impl> mpImpl;
 
@@ -50,13 +55,23 @@ public:
         GroupScope( const GroupScope& ) = delete;
         GroupScope& operator= ( const GroupScope& ) = delete;
 
-        GroupScope( FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc, const ScFormulaCell& rCell );
+    private:
+        GroupScope(
+            FormulaLogger& rLogger, const OUString& rPrefix,
+            const ScDocument& rDoc, const ScFormulaCell& rCell );
 
+    public:
         GroupScope( GroupScope&& r );
         ~GroupScope();
 
-        void addMessage( const OUString& rName );
+        /**
+         * Add an arbitrary message to dump to the log.
+         */
+        void addMessage( const OUString& rMsg );
 
+        /**
+         * Call this when the group calculation has finished successfullly.
+         */
         void setCalcComplete();
     };
 
commit 90b7f35ce3ea8de5cb8a6ad8779c4307f95394d6
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Oct 22 21:28:04 2016 -0400

    LIBO_FORMULA_LOG_FILE env var to specify the log file location.
    
    In theory you can either use file:///foo/bar or /foo/bar style of
    file path.
    
    And also make sure that we don't crash in case a file is not
    specified or the file path is invalid.
    
    Change-Id: Ia1fb11af84f91e678401bde11454522db9893f4c

diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
index d8ce3a4..d272ed0 100644
--- a/sc/inc/formulalogger.hxx
+++ b/sc/inc/formulalogger.hxx
@@ -29,6 +29,8 @@ class FormulaLogger
     void write( const OUString& ou );
     void write( sal_Int32 n );
 
+    void sync();
+
     void writeNestLevel();
 
 public:
diff --git a/sc/source/core/tool/formulalogger.cxx b/sc/source/core/tool/formulalogger.cxx
index 69b1ef9..c7ae53b 100644
--- a/sc/source/core/tool/formulalogger.cxx
+++ b/sc/source/core/tool/formulalogger.cxx
@@ -16,8 +16,29 @@
 #include <sfx2/docfile.hxx>
 #include <tools/urlobj.hxx>
 
+#include <cstdlib>
+
 namespace sc {
 
+namespace {
+
+std::unique_ptr<osl::File> initFile()
+{
+    const char* pPath = std::getenv("LIBO_FORMULA_LOG_FILE");
+    if (!pPath)
+        return nullptr;
+
+    // Support both file:///... and system file path notations.
+    OUString aPath = OUString::createFromAscii(pPath);
+    INetURLObject aURL;
+    aURL.SetSmartURL(aPath);
+    aPath = aURL.GetMainURL(INetURLObject::NO_DECODE);
+
+    return o3tl::make_unique<osl::File>(aPath);
+}
+
+}
+
 FormulaLogger& FormulaLogger::get()
 {
     static FormulaLogger aLogger;
@@ -72,7 +93,7 @@ struct FormulaLogger::GroupScope::Impl
 
         mrLogger.writeAscii(")\n");
 
-        mrLogger.mpLogFile->sync();
+        mrLogger.sync();
 
         --mrLogger.mnNestLevel;
     }
@@ -97,8 +118,13 @@ void FormulaLogger::GroupScope::setCalcComplete()
     addMessage("calculation performed");
 }
 
-FormulaLogger::FormulaLogger() : mpLogFile(o3tl::make_unique<osl::File>("file:///home/kohei/tmp/formula.log"))
+FormulaLogger::FormulaLogger()
 {
+    mpLogFile = initFile();
+
+    if (!mpLogFile)
+        return;
+
     osl::FileBase::RC eRC = mpLogFile->open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
 
     if (eRC == osl::FileBase::E_EXIST)
@@ -126,9 +152,8 @@ FormulaLogger::FormulaLogger() : mpLogFile(o3tl::make_unique<osl::File>("file://
         return;
     }
 
-    sal_uInt64 nBytes;
-    mpLogFile->write("---\n", 4, nBytes);
-    mpLogFile->sync();
+    writeAscii("---\n");
+    sync();
 }
 
 FormulaLogger::~FormulaLogger()
@@ -167,6 +192,14 @@ void FormulaLogger::write( sal_Int32 n )
     writeAscii(s.getStr(), s.getLength());
 }
 
+void FormulaLogger::sync()
+{
+    if (!mpLogFile)
+        return;
+
+    mpLogFile->sync();
+}
+
 void FormulaLogger::writeNestLevel()
 {
     // Write the nest level, but keep it only 1-character length to avoid
@@ -176,8 +209,8 @@ void FormulaLogger::writeNestLevel()
     else
         writeAscii("!");
 
-    writeAscii(":");
-    for (sal_Int32 i = 0; i < mnNestLevel; ++i)
+    writeAscii(": ");
+    for (sal_Int32 i = 1; i < mnNestLevel; ++i)
         writeAscii("   ");
 }
 
commit 12127e1eaf63fec008cba3fe705e23ba86a704f7
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Oct 22 21:03:30 2016 -0400

    Write nest levels in case of nested group calculations.
    
    Change-Id: Ie2a94bf76ab28f792ff5684879365fda81c10e2b

diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
index bc547b9..d8ce3a4 100644
--- a/sc/inc/formulalogger.hxx
+++ b/sc/inc/formulalogger.hxx
@@ -20,14 +20,17 @@ namespace sc {
 class FormulaLogger
 {
     std::unique_ptr<osl::File> mpLogFile;
-    OUString maGroupPrefix;
     std::vector<OUString> maMessages;
 
+    sal_Int32 mnNestLevel = 0;
+
     void writeAscii( const char* s );
     void writeAscii( const char* s, size_t n );
     void write( const OUString& ou );
     void write( sal_Int32 n );
 
+    void writeNestLevel();
+
 public:
 
     static FormulaLogger& get();
@@ -45,7 +48,8 @@ public:
         GroupScope( const GroupScope& ) = delete;
         GroupScope& operator= ( const GroupScope& ) = delete;
 
-        GroupScope( FormulaLogger& rLogger, const OUString& rPrefix );
+        GroupScope( FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc, const ScFormulaCell& rCell );
+
         GroupScope( GroupScope&& r );
         ~GroupScope();
 
diff --git a/sc/source/core/tool/formulalogger.cxx b/sc/source/core/tool/formulalogger.cxx
index db51259..69b1ef9 100644
--- a/sc/source/core/tool/formulalogger.cxx
+++ b/sc/source/core/tool/formulalogger.cxx
@@ -16,8 +16,6 @@
 #include <sfx2/docfile.hxx>
 #include <tools/urlobj.hxx>
 
-#include <iostream>
-
 namespace sc {
 
 FormulaLogger& FormulaLogger::get()
@@ -35,28 +33,54 @@ struct FormulaLogger::GroupScope::Impl
 
     bool mbCalcComplete = false;
 
-    Impl( FormulaLogger& rLogger, const OUString& rPrefix ) :
-        mrLogger(rLogger), maPrefix(rPrefix) {}
+    Impl( FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc, const ScFormulaCell& rCell ) :
+        mrLogger(rLogger), maPrefix(rPrefix)
+    {
+        ++mrLogger.mnNestLevel;
+
+        sc::TokenStringContext aCxt(&rDoc, rDoc.GetGrammar());
+        OUString aFormula = rCell.GetCode()->CreateString(aCxt, rCell.aPos);
+
+        mrLogger.write(maPrefix);
+        mrLogger.writeNestLevel();
+
+        mrLogger.writeAscii("-- enter (formula='");
+        mrLogger.write(aFormula);
+        mrLogger.writeAscii("', size=");
+        mrLogger.write(rCell.GetSharedLength());
+        mrLogger.writeAscii(")\n");
+    }
 
     ~Impl()
     {
         for (const OUString& rMsg : maMessages)
         {
             mrLogger.write(maPrefix);
-            mrLogger.writeAscii(" * ");
+            mrLogger.writeNestLevel();
+            mrLogger.writeAscii("   * ");
             mrLogger.write(rMsg);
             mrLogger.writeAscii("\n");
         }
 
         mrLogger.write(maPrefix);
-        mrLogger.writeAscii(mbCalcComplete ? " * calculation complete\n" : " * exited without calculation\n");
+        mrLogger.writeNestLevel();
+        mrLogger.writeAscii("-- exit (");
+        if (mbCalcComplete)
+            mrLogger.writeAscii("calculation complete");
+        else
+            mrLogger.writeAscii("without calculation");
+
+        mrLogger.writeAscii(")\n");
 
         mrLogger.mpLogFile->sync();
+
+        --mrLogger.mnNestLevel;
     }
 };
 
-FormulaLogger::GroupScope::GroupScope( FormulaLogger& rLogger, const OUString& rPrefix ) :
-    mpImpl(o3tl::make_unique<Impl>(rLogger, rPrefix)) {}
+FormulaLogger::GroupScope::GroupScope(
+    FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc, const ScFormulaCell& rCell ) :
+    mpImpl(o3tl::make_unique<Impl>(rLogger, rPrefix, rDoc, rCell)) {}
 
 FormulaLogger::GroupScope::GroupScope( GroupScope&& r ) : mpImpl(std::move(r.mpImpl)) {}
 
@@ -69,7 +93,8 @@ void FormulaLogger::GroupScope::addMessage( const OUString& rMsg )
 
 void FormulaLogger::GroupScope::setCalcComplete()
 {
-    mpImpl->mbCalcComplete;
+    mpImpl->mbCalcComplete = true;
+    addMessage("calculation performed");
 }
 
 FormulaLogger::FormulaLogger() : mpLogFile(o3tl::make_unique<osl::File>("file:///home/kohei/tmp/formula.log"))
@@ -142,11 +167,23 @@ void FormulaLogger::write( sal_Int32 n )
     writeAscii(s.getStr(), s.getLength());
 }
 
+void FormulaLogger::writeNestLevel()
+{
+    // Write the nest level, but keep it only 1-character length to avoid
+    // messing up the spacing.
+    if (mnNestLevel < 10)
+        write(mnNestLevel);
+    else
+        writeAscii("!");
+
+    writeAscii(":");
+    for (sal_Int32 i = 0; i < mnNestLevel; ++i)
+        writeAscii("   ");
+}
+
 FormulaLogger::GroupScope FormulaLogger::enterGroup(
     const ScDocument& rDoc, const ScFormulaCell& rCell )
 {
-    maGroupPrefix = "formula-group: ";
-
     // Get the file name if available.
     const SfxObjectShell* pShell = rDoc.GetDocumentShell();
     const SfxMedium* pMedium = pShell->GetMedium();
@@ -154,22 +191,13 @@ FormulaLogger::GroupScope FormulaLogger::enterGroup(
     if (aName.isEmpty())
         aName = "-"; // unsaved document.
 
-    maGroupPrefix += aName;
-    maGroupPrefix += ": ";
-    maGroupPrefix += rCell.aPos.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, rDoc.GetAddressConvention());
-    maGroupPrefix += ": ";
-    write(maGroupPrefix);
-
-    writeAscii("(formula='");
-
-    sc::TokenStringContext aCxt(&rDoc, rDoc.GetGrammar());
-    write(rCell.GetCode()->CreateString(aCxt, rCell.aPos));
+    OUString aGroupPrefix = aName;
 
-    writeAscii("', size=");
-    write(rCell.GetSharedLength());
-    writeAscii(")\n");
+    aGroupPrefix += ": formula-group: ";
+    aGroupPrefix += rCell.aPos.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, rDoc.GetAddressConvention());
+    aGroupPrefix += ": ";
 
-    return GroupScope(*this, maGroupPrefix);
+    return GroupScope(*this, aGroupPrefix, rDoc, rCell);
 }
 
 }
commit 662652d864c6d26096cfc7f650d80d1e80235bca
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Oct 22 19:54:37 2016 -0400

    Use a singleton pattern here.
    
    Change-Id: I45e8bcdb4ee2717ac7e223e68e0c03da9473db5b

diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
index 581a2eb..bc547b9 100644
--- a/sc/inc/formulalogger.hxx
+++ b/sc/inc/formulalogger.hxx
@@ -30,6 +30,8 @@ class FormulaLogger
 
 public:
 
+    static FormulaLogger& get();
+
     /**
      * This class is only moveable.
      */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index f5c82c4..7f97e26 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -215,13 +215,6 @@ struct DebugCalculationStacker
 
 namespace {
 
-
-sc::FormulaLogger& getLogger()
-{
-    static sc::FormulaLogger aLogger;
-    return aLogger;
-}
-
 // More or less arbitrary, of course all recursions must fit into available
 // stack space (which is what on all systems we don't know yet?). Choosing a
 // lower value may be better than trying a much higher value that also isn't
@@ -4038,7 +4031,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (!mxGroup || !pCode)
         return false;
 
-    auto aScope = getLogger().enterGroup(*pDocument, *this);
+    auto aScope = sc::FormulaLogger::get().enterGroup(*pDocument, *this);
 
     if (mxGroup->meCalcState == sc::GroupCalcDisabled)
     {
diff --git a/sc/source/core/tool/formulalogger.cxx b/sc/source/core/tool/formulalogger.cxx
index a9ea3ba..db51259 100644
--- a/sc/source/core/tool/formulalogger.cxx
+++ b/sc/source/core/tool/formulalogger.cxx
@@ -20,6 +20,12 @@
 
 namespace sc {
 
+FormulaLogger& FormulaLogger::get()
+{
+    static FormulaLogger aLogger;
+    return aLogger;
+}
+
 struct FormulaLogger::GroupScope::Impl
 {
     FormulaLogger& mrLogger;
commit 28a11eee99a0d20566c26ad285e81eac7b7badd6
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 21 22:43:32 2016 -0400

    Have the logger instantiate on first use.
    
    Change-Id: Ia2e3c011a66030aafa479f3ea47dcc1fb0c5e8be

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index a56e128..f5c82c4 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -215,7 +215,12 @@ struct DebugCalculationStacker
 
 namespace {
 
-sc::FormulaLogger aLogger;
+
+sc::FormulaLogger& getLogger()
+{
+    static sc::FormulaLogger aLogger;
+    return aLogger;
+}
 
 // More or less arbitrary, of course all recursions must fit into available
 // stack space (which is what on all systems we don't know yet?). Choosing a
@@ -4033,7 +4038,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (!mxGroup || !pCode)
         return false;
 
-    auto aScope = aLogger.enterGroup(*pDocument, *this);
+    auto aScope = getLogger().enterGroup(*pDocument, *this);
 
     if (mxGroup->meCalcState == sc::GroupCalcDisabled)
     {
commit 3ab685241af77f6361b694b06dde6b6c709956e1
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 19 22:28:26 2016 -0400

    Initial take on group formula logging.
    
    For now, this logger only logs group formula calculations.
    
    Change-Id: Idab3cf58f8d9e5fd24fc9f7498d55e385ca93ca7

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 0aa859e..f3abc81 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -230,6 +230,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/core/tool/editutil \
     sc/source/core/tool/filtopt \
     sc/source/core/tool/formulagroup \
+    sc/source/core/tool/formulalogger \
     sc/source/core/tool/formulaopt \
     sc/source/core/tool/formulaparserpool \
     sc/source/core/tool/formularesult \
diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx
new file mode 100644
index 0000000..581a2eb
--- /dev/null
+++ b/sc/inc/formulalogger.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SC_INC_FORMULALOGGER_HXX
+#define INCLUDED_SC_INC_FORMULALOGGER_HXX
+
+#include <osl/file.hxx>
+#include <memory>
+#include <vector>
+
+class ScFormulaCell;
+class ScDocument;
+
+namespace sc {
+
+class FormulaLogger
+{
+    std::unique_ptr<osl::File> mpLogFile;
+    OUString maGroupPrefix;
+    std::vector<OUString> maMessages;
+
+    void writeAscii( const char* s );
+    void writeAscii( const char* s, size_t n );
+    void write( const OUString& ou );
+    void write( sal_Int32 n );
+
+public:
+
+    /**
+     * This class is only moveable.
+     */
+    class GroupScope
+    {
+        struct Impl;
+        std::unique_ptr<Impl> mpImpl;
+
+    public:
+        GroupScope() = delete;
+        GroupScope( const GroupScope& ) = delete;
+        GroupScope& operator= ( const GroupScope& ) = delete;
+
+        GroupScope( FormulaLogger& rLogger, const OUString& rPrefix );
+        GroupScope( GroupScope&& r );
+        ~GroupScope();
+
+        void addMessage( const OUString& rName );
+
+        void setCalcComplete();
+    };
+
+    FormulaLogger( const FormulaLogger& ) = delete;
+    FormulaLogger& operator= ( const FormulaLogger& ) = delete;
+
+    FormulaLogger();
+    ~FormulaLogger();
+
+    GroupScope enterGroup( const ScDocument& rDoc, const ScFormulaCell& rCell );
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index b95417b..a56e128 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -61,6 +61,7 @@
 #include <listenerquery.hxx>
 #include <listenerqueryids.hxx>
 #include <grouparealistener.hxx>
+#include <formulalogger.hxx>
 
 #if HAVE_FEATURE_OPENCL
 #include <opencl/openclwrapper.hxx>
@@ -214,6 +215,8 @@ struct DebugCalculationStacker
 
 namespace {
 
+sc::FormulaLogger aLogger;
+
 // More or less arbitrary, of course all recursions must fit into available
 // stack space (which is what on all systems we don't know yet?). Choosing a
 // lower value may be better than trying a much higher value that also isn't
@@ -4030,18 +4033,25 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (!mxGroup || !pCode)
         return false;
 
+    auto aScope = aLogger.enterGroup(*pDocument, *this);
+
     if (mxGroup->meCalcState == sc::GroupCalcDisabled)
+    {
+        aScope.addMessage("group calc disabled");
         return false;
+    }
 
     if (GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize)
     {
         mxGroup->meCalcState = sc::GroupCalcDisabled;
+        aScope.addMessage("group length below minimum threshold");
         return false;
     }
 
     if (cMatrixFlag != MM_NONE)
     {
         mxGroup->meCalcState = sc::GroupCalcDisabled;
+        aScope.addMessage("matrix skipped");
         return false;
     }
 
@@ -4055,11 +4065,15 @@ bool ScFormulaCell::InterpretFormulaGroup()
         case FormulaVectorUnknown:
         default:
             // Not good.
+            aScope.addMessage("group calc disabled due to vector state");
             return false;
     }
 
     if (!ScCalcConfig::isOpenCLEnabled() && !ScCalcConfig::isSwInterpreterEnabled())
+    {
+        aScope.addMessage("opencl not enabled");
         return false;
+    }
 
     // Guard against endless recursion of Interpret() calls, for this to work
     // ScFormulaCell::InterpretFormulaGroup() must never be called through
@@ -4126,6 +4140,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
                 xGroup->mpCode = nullptr;
             }
 
+            aScope.addMessage("group token conversion failed");
             return false;
         }
 
@@ -4133,6 +4148,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
         // generate them.
         xGroup->meCalcState = mxGroup->meCalcState = sc::GroupCalcRunning;
         sc::FormulaGroupInterpreter *pInterpreter = sc::FormulaGroupInterpreter::getStatic();
+
         if (pInterpreter == nullptr ||
             !pInterpreter->interpret(*pDocument, xGroup->mpTopCell->aPos, xGroup, aCode))
         {
@@ -4147,8 +4163,12 @@ bool ScFormulaCell::InterpretFormulaGroup()
                 xGroup->mpCode = nullptr;
             }
 
+            aScope.addMessage("group interpretation unsuccessful");
             return false;
         }
+
+        aScope.setCalcComplete();
+
         if (nNumParts > 1)
         {
             xGroup->mpTopCell = nullptr;
diff --git a/sc/source/core/tool/formulalogger.cxx b/sc/source/core/tool/formulalogger.cxx
new file mode 100644
index 0000000..a9ea3ba
--- /dev/null
+++ b/sc/source/core/tool/formulalogger.cxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <formulalogger.hxx>
+#include <formulacell.hxx>
+#include <tokenarray.hxx>
+#include <document.hxx>
+#include <tokenstringcontext.hxx>
+
+#include <o3tl/make_unique.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+
+#include <iostream>
+
+namespace sc {
+
+struct FormulaLogger::GroupScope::Impl
+{
+    FormulaLogger& mrLogger;
+
+    OUString maPrefix;
+    std::vector<OUString> maMessages;
+
+    bool mbCalcComplete = false;
+
+    Impl( FormulaLogger& rLogger, const OUString& rPrefix ) :
+        mrLogger(rLogger), maPrefix(rPrefix) {}
+
+    ~Impl()
+    {
+        for (const OUString& rMsg : maMessages)
+        {
+            mrLogger.write(maPrefix);
+            mrLogger.writeAscii(" * ");
+            mrLogger.write(rMsg);
+            mrLogger.writeAscii("\n");
+        }
+
+        mrLogger.write(maPrefix);
+        mrLogger.writeAscii(mbCalcComplete ? " * calculation complete\n" : " * exited without calculation\n");
+
+        mrLogger.mpLogFile->sync();
+    }
+};
+
+FormulaLogger::GroupScope::GroupScope( FormulaLogger& rLogger, const OUString& rPrefix ) :
+    mpImpl(o3tl::make_unique<Impl>(rLogger, rPrefix)) {}
+
+FormulaLogger::GroupScope::GroupScope( GroupScope&& r ) : mpImpl(std::move(r.mpImpl)) {}
+
+FormulaLogger::GroupScope::~GroupScope() {}
+
+void FormulaLogger::GroupScope::addMessage( const OUString& rMsg )
+{
+    mpImpl->maMessages.push_back(rMsg);
+}
+
+void FormulaLogger::GroupScope::setCalcComplete()
+{
+    mpImpl->mbCalcComplete;
+}
+
+FormulaLogger::FormulaLogger() : mpLogFile(o3tl::make_unique<osl::File>("file:///home/kohei/tmp/formula.log"))
+{
+    osl::FileBase::RC eRC = mpLogFile->open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
+
+    if (eRC == osl::FileBase::E_EXIST)
+    {
+        eRC = mpLogFile->open(osl_File_OpenFlag_Write);
+
+        if (eRC != osl::FileBase::E_None)
+        {
+            // Failed to open an existing log file.
+            mpLogFile.reset();
+            return;
+        }
+
+        if (mpLogFile->setPos(osl_Pos_End, 0) != osl::FileBase::E_None)
+        {
+            // Failed to set the position to the end of the file.
+            mpLogFile.reset();
+            return;
+        }
+    }
+    else if (eRC != osl::FileBase::E_None)
+    {
+        // Failed to create a new file.
+        mpLogFile.reset();
+        return;
+    }
+
+    sal_uInt64 nBytes;
+    mpLogFile->write("---\n", 4, nBytes);
+    mpLogFile->sync();
+}
+
+FormulaLogger::~FormulaLogger()
+{
+    if (mpLogFile)
+        mpLogFile->close();
+}
+
+void FormulaLogger::writeAscii( const char* s )
+{
+    if (!mpLogFile)
+        return;
+
+    sal_uInt64 nBytes;
+    mpLogFile->write(s, strlen(s), nBytes);
+}
+
+void FormulaLogger::writeAscii( const char* s, size_t n )
+{
+    if (!mpLogFile)
+        return;
+
+    sal_uInt64 nBytes;
+    mpLogFile->write(s, n, nBytes);
+}
+
+void FormulaLogger::write( const OUString& ou )
+{
+    OString s = rtl::OUStringToOString(ou, RTL_TEXTENCODING_UTF8).getStr();
+    writeAscii(s.getStr(), s.getLength());
+}
+
+void FormulaLogger::write( sal_Int32 n )
+{
+    OString s = OString::number(n);
+    writeAscii(s.getStr(), s.getLength());
+}
+
+FormulaLogger::GroupScope FormulaLogger::enterGroup(
+    const ScDocument& rDoc, const ScFormulaCell& rCell )
+{
+    maGroupPrefix = "formula-group: ";
+
+    // Get the file name if available.
+    const SfxObjectShell* pShell = rDoc.GetDocumentShell();
+    const SfxMedium* pMedium = pShell->GetMedium();
+    OUString aName = pMedium->GetURLObject().GetLastName();
+    if (aName.isEmpty())
+        aName = "-"; // unsaved document.
+
+    maGroupPrefix += aName;
+    maGroupPrefix += ": ";
+    maGroupPrefix += rCell.aPos.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, rDoc.GetAddressConvention());
+    maGroupPrefix += ": ";
+    write(maGroupPrefix);
+
+    writeAscii("(formula='");
+
+    sc::TokenStringContext aCxt(&rDoc, rDoc.GetGrammar());
+    write(rCell.GetCode()->CreateString(aCxt, rCell.aPos));
+
+    writeAscii("', size=");
+    write(rCell.GetSharedLength());
+    writeAscii(")\n");
+
+    return GroupScope(*this, maGroupPrefix);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list