2016-10-19 22:28:26 -04:00
|
|
|
/* -*- 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>
|
2016-11-03 21:55:18 -04:00
|
|
|
#include <address.hxx>
|
2016-10-19 22:28:26 -04:00
|
|
|
|
|
|
|
#include <o3tl/make_unique.hxx>
|
|
|
|
#include <sfx2/objsh.hxx>
|
|
|
|
#include <sfx2/docfile.hxx>
|
|
|
|
#include <tools/urlobj.hxx>
|
2016-11-03 21:55:18 -04:00
|
|
|
#include <formula/vectortoken.hxx>
|
|
|
|
#include <rtl/ustrbuf.hxx>
|
2016-10-19 22:28:26 -04:00
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
#include <cstdlib>
|
|
|
|
|
2016-10-19 22:28:26 -04:00
|
|
|
namespace sc {
|
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-10-22 19:54:37 -04:00
|
|
|
FormulaLogger& FormulaLogger::get()
|
|
|
|
{
|
|
|
|
static FormulaLogger aLogger;
|
|
|
|
return aLogger;
|
|
|
|
}
|
|
|
|
|
2016-10-19 22:28:26 -04:00
|
|
|
struct FormulaLogger::GroupScope::Impl
|
|
|
|
{
|
|
|
|
FormulaLogger& mrLogger;
|
2016-11-03 21:55:18 -04:00
|
|
|
const ScDocument& mrDoc;
|
2016-10-19 22:28:26 -04:00
|
|
|
|
|
|
|
OUString maPrefix;
|
|
|
|
std::vector<OUString> maMessages;
|
|
|
|
|
|
|
|
bool mbCalcComplete = false;
|
|
|
|
|
2016-10-22 21:03:30 -04:00
|
|
|
Impl( FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc, const ScFormulaCell& rCell ) :
|
2016-11-03 21:55:18 -04:00
|
|
|
mrLogger(rLogger), mrDoc(rDoc), maPrefix(rPrefix)
|
2016-10-22 21:03:30 -04:00
|
|
|
{
|
|
|
|
++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");
|
|
|
|
}
|
2016-10-19 22:28:26 -04:00
|
|
|
|
|
|
|
~Impl()
|
|
|
|
{
|
|
|
|
for (const OUString& rMsg : maMessages)
|
|
|
|
{
|
|
|
|
mrLogger.write(maPrefix);
|
2016-10-22 21:03:30 -04:00
|
|
|
mrLogger.writeNestLevel();
|
|
|
|
mrLogger.writeAscii(" * ");
|
2016-10-19 22:28:26 -04:00
|
|
|
mrLogger.write(rMsg);
|
|
|
|
mrLogger.writeAscii("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
mrLogger.write(maPrefix);
|
2016-10-22 21:03:30 -04:00
|
|
|
mrLogger.writeNestLevel();
|
|
|
|
mrLogger.writeAscii("-- exit (");
|
|
|
|
if (mbCalcComplete)
|
|
|
|
mrLogger.writeAscii("calculation complete");
|
|
|
|
else
|
|
|
|
mrLogger.writeAscii("without calculation");
|
|
|
|
|
|
|
|
mrLogger.writeAscii(")\n");
|
2016-10-19 22:28:26 -04:00
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
mrLogger.sync();
|
2016-10-22 21:03:30 -04:00
|
|
|
|
|
|
|
--mrLogger.mnNestLevel;
|
2016-10-19 22:28:26 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-22 21:03:30 -04:00
|
|
|
FormulaLogger::GroupScope::GroupScope(
|
|
|
|
FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc, const ScFormulaCell& rCell ) :
|
|
|
|
mpImpl(o3tl::make_unique<Impl>(rLogger, rPrefix, rDoc, rCell)) {}
|
2016-10-19 22:28:26 -04:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-11-03 21:55:18 -04:00
|
|
|
void FormulaLogger::GroupScope::addRefMessage(
|
|
|
|
const ScAddress& rPos, size_t nLen, const formula::VectorRefArray& rArray )
|
|
|
|
{
|
|
|
|
OUStringBuffer aBuf;
|
|
|
|
|
|
|
|
ScRange aRefRange(rPos);
|
|
|
|
aRefRange.aEnd.IncRow(nLen-1);
|
|
|
|
OUString aRangeStr = aRefRange.Format(ScRefFlags::VALID, &mpImpl->mrDoc);
|
|
|
|
aBuf.append(aRangeStr);
|
|
|
|
aBuf.appendAscii(": ");
|
|
|
|
|
|
|
|
if (rArray.mpNumericArray)
|
|
|
|
{
|
|
|
|
if (rArray.mpStringArray)
|
|
|
|
{
|
|
|
|
// mixture of numeric and string cells.
|
|
|
|
aBuf.appendAscii("numeric and string");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// numeric cells only.
|
|
|
|
aBuf.appendAscii("numeric only");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rArray.mpStringArray)
|
|
|
|
{
|
|
|
|
// string cells only.
|
|
|
|
aBuf.appendAscii("string only");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// empty cells.
|
|
|
|
aBuf.appendAscii("empty");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mpImpl->maMessages.push_back(aBuf.makeStringAndClear());
|
|
|
|
}
|
|
|
|
|
2016-10-19 22:28:26 -04:00
|
|
|
void FormulaLogger::GroupScope::setCalcComplete()
|
|
|
|
{
|
2016-10-22 21:03:30 -04:00
|
|
|
mpImpl->mbCalcComplete = true;
|
|
|
|
addMessage("calculation performed");
|
2016-10-19 22:28:26 -04:00
|
|
|
}
|
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
FormulaLogger::FormulaLogger()
|
2016-10-19 22:28:26 -04:00
|
|
|
{
|
2016-10-22 21:28:04 -04:00
|
|
|
mpLogFile = initFile();
|
|
|
|
|
|
|
|
if (!mpLogFile)
|
|
|
|
return;
|
|
|
|
|
2016-10-19 22:28:26 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:42:22 -04:00
|
|
|
// Output the header information.
|
2016-10-22 21:28:04 -04:00
|
|
|
writeAscii("---\n");
|
2016-11-03 19:42:22 -04:00
|
|
|
writeAscii("OpenCL: ");
|
|
|
|
writeAscii(ScCalcConfig::isOpenCLEnabled() ? "enabled\n" : "disabled\n");
|
|
|
|
writeAscii("Software Interpreter: ");
|
|
|
|
writeAscii(ScCalcConfig::isSwInterpreterEnabled() ? "enabled\n" : "disabled\n");
|
|
|
|
writeAscii("---\n");
|
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
sync();
|
2016-10-19 22:28:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
void FormulaLogger::sync()
|
|
|
|
{
|
|
|
|
if (!mpLogFile)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mpLogFile->sync();
|
|
|
|
}
|
|
|
|
|
2016-10-22 21:03:30 -04:00
|
|
|
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("!");
|
|
|
|
|
2016-10-22 21:28:04 -04:00
|
|
|
writeAscii(": ");
|
|
|
|
for (sal_Int32 i = 1; i < mnNestLevel; ++i)
|
2016-10-22 21:03:30 -04:00
|
|
|
writeAscii(" ");
|
|
|
|
}
|
|
|
|
|
2016-10-19 22:28:26 -04:00
|
|
|
FormulaLogger::GroupScope FormulaLogger::enterGroup(
|
|
|
|
const ScDocument& rDoc, const ScFormulaCell& rCell )
|
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
|
2016-10-22 21:03:30 -04:00
|
|
|
OUString aGroupPrefix = aName;
|
2016-10-19 22:28:26 -04:00
|
|
|
|
2016-10-22 21:03:30 -04:00
|
|
|
aGroupPrefix += ": formula-group: ";
|
|
|
|
aGroupPrefix += rCell.aPos.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, rDoc.GetAddressConvention());
|
|
|
|
aGroupPrefix += ": ";
|
2016-10-19 22:28:26 -04:00
|
|
|
|
2016-10-22 21:03:30 -04:00
|
|
|
return GroupScope(*this, aGroupPrefix, rDoc, rCell);
|
2016-10-19 22:28:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|