LibreOffice Module sc (master) 1
formulalogger.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8#include <formulalogger.hxx>
9#include <formulacell.hxx>
10#include <tokenarray.hxx>
11#include <document.hxx>
13#include <address.hxx>
14#include <interpre.hxx>
15
16#include <osl/file.hxx>
17#include <sfx2/objsh.hxx>
18#include <sfx2/docfile.hxx>
19#include <tools/urlobj.hxx>
21#include <rtl/ustrbuf.hxx>
22
23#include <cstdlib>
24#include <utility>
25
26namespace sc {
27
28namespace {
29
30std::unique_ptr<osl::File> initFile()
31{
32 const char* pPath = std::getenv("LIBO_FORMULA_LOG_FILE");
33 if (!pPath)
34 return nullptr;
35
36 // Support both file:///... and system file path notations.
37 OUString aPath = OUString::createFromAscii(pPath);
39 aURL.SetSmartURL(aPath);
41
42 return std::make_unique<osl::File>(aPath);
43}
44
45ScRefFlags getRefFlags( const ScAddress& rCellPos, const ScAddress& rRefPos )
46{
48 if (rCellPos.Tab() != rRefPos.Tab())
49 eFlags |= ScRefFlags::TAB_3D;
50 return eFlags;
51}
52
53}
54
55FormulaLogger& FormulaLogger::get()
56{
57 static FormulaLogger aLogger;
58 return aLogger;
59}
60
62{
65
66 OUString maPrefix;
67 std::vector<OUString> maMessages;
68
71
72 Impl( FormulaLogger& rLogger, OUString aPrefix, const ScDocument& rDoc,
73 const ScFormulaCell& rCell, bool bOutputEnabled ) :
74 mrLogger(rLogger), mrDoc(rDoc), maPrefix(std::move(aPrefix)),
75 mbCalcComplete(false), mbOutputEnabled(bOutputEnabled)
76 {
77 ++mrLogger.mnNestLevel;
78
79 if (!mbOutputEnabled)
80 return;
81
82 sc::TokenStringContext aCxt(rDoc, rDoc.GetGrammar());
83 OUString aFormula = rCell.GetCode()->CreateString(aCxt, rCell.aPos);
84
85 mrLogger.write(maPrefix);
86 mrLogger.writeNestLevel();
87
88 mrLogger.writeAscii("-- enter (formula='");
89 mrLogger.write(aFormula);
90 mrLogger.writeAscii("', size=");
91 mrLogger.write(rCell.GetSharedLength());
92 mrLogger.writeAscii(")\n");
93 }
94
96 {
98 {
99 for (const OUString& rMsg : maMessages)
100 {
101 mrLogger.write(maPrefix);
102 mrLogger.writeNestLevel();
103 mrLogger.writeAscii(" * ");
104 mrLogger.write(rMsg);
105 mrLogger.writeAscii("\n");
106 }
107
108 mrLogger.write(maPrefix);
109 mrLogger.writeNestLevel();
110 mrLogger.writeAscii("-- exit (");
111 if (mbCalcComplete)
112 mrLogger.writeAscii("calculation complete");
113 else
114 mrLogger.writeAscii("without calculation");
115
116 mrLogger.writeAscii(")\n");
117
118 mrLogger.sync();
119 }
120
121 --mrLogger.mnNestLevel;
122 }
123};
124
125FormulaLogger::GroupScope::GroupScope(
126 FormulaLogger& rLogger, const OUString& rPrefix, const ScDocument& rDoc,
127 const ScFormulaCell& rCell, bool bOutputEnabled ) :
128 mpImpl(std::make_unique<Impl>(rLogger, rPrefix, rDoc, rCell, bOutputEnabled)) {}
129
130FormulaLogger::GroupScope::GroupScope(GroupScope&& r) noexcept : mpImpl(std::move(r.mpImpl)) {}
131
132FormulaLogger::GroupScope::~GroupScope() {}
133
134void FormulaLogger::GroupScope::addMessage( const OUString& rMsg )
135{
136 mpImpl->maMessages.push_back(rMsg);
137}
138
140 const ScAddress& rCellPos, const ScAddress& rRefPos, size_t nLen,
141 const formula::VectorRefArray& rArray )
142{
143 ScRange aRefRange(rRefPos);
144 aRefRange.aEnd.IncRow(nLen-1);
145 OUString aRangeStr = aRefRange.Format(mpImpl->mrDoc, getRefFlags(rCellPos, rRefPos));
146
147 std::u16string_view aMsg;
148 if (rArray.mpNumericArray)
149 {
150 if (rArray.mpStringArray)
151 {
152 // mixture of numeric and string cells.
153 aMsg = u"numeric and string";
154 }
155 else
156 {
157 // numeric cells only.
158 aMsg = u"numeric only";
159 }
160 }
161 else
162 {
163 if (rArray.mpStringArray)
164 {
165 // string cells only.
166 aMsg = u"string only";
167 }
168 else
169 {
170 // empty cells.
171 aMsg = u"empty";
172 }
173 }
174
175 mpImpl->maMessages.push_back(aRangeStr + ": " + aMsg);
176}
177
179 const ScAddress& rCellPos, const ScAddress& rRefPos, size_t nLen,
180 const std::vector<formula::VectorRefArray>& rArrays )
181{
182 ScAddress aPos(rRefPos); // copy
183 for (const formula::VectorRefArray& rArray : rArrays)
184 {
185 addRefMessage(rCellPos, aPos, nLen, rArray);
186 aPos.IncCol();
187 }
188}
189
191 const ScAddress& rCellPos, const ScAddress& rRefPos,
192 const formula::FormulaToken& rToken )
193{
194 OUString aPosStr = rRefPos.Format(getRefFlags(rCellPos, rRefPos), &mpImpl->mrDoc);
195 std::u16string_view aMsg;
196 switch (rToken.GetType())
197 {
199 aMsg = u"numeric value";
200 break;
202 aMsg = u"string value";
203 break;
204 default:
205 aMsg = u"unknown value";
206 }
207
208 mpImpl->maMessages.push_back(aPosStr + ": " + aMsg);
209}
210
212{
213 OUString aBuf = "group length below minimum threshold ("
214 + OUString::number(rCell.GetWeight())
215 + " < "
216 + OUString::number(ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize)
217 + ")";
218 mpImpl->maMessages.push_back(aBuf);
219}
220
222{
223 mpImpl->mbCalcComplete = true;
224 addMessage("calculation performed");
225}
226
227FormulaLogger::FormulaLogger()
228{
229 mpLogFile = initFile();
230
231 if (!mpLogFile)
232 return;
233
234 osl::FileBase::RC eRC = mpLogFile->open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
235
236 if (eRC == osl::FileBase::E_EXIST)
237 {
238 eRC = mpLogFile->open(osl_File_OpenFlag_Write);
239
240 if (eRC != osl::FileBase::E_None)
241 {
242 // Failed to open an existing log file.
243 mpLogFile.reset();
244 return;
245 }
246
247 if (mpLogFile->setPos(osl_Pos_End, 0) != osl::FileBase::E_None)
248 {
249 // Failed to set the position to the end of the file.
250 mpLogFile.reset();
251 return;
252 }
253 }
254 else if (eRC != osl::FileBase::E_None)
255 {
256 // Failed to create a new file.
257 mpLogFile.reset();
258 return;
259 }
260
261 // Output the header information.
262 writeAscii("---\n");
263 writeAscii("OpenCL: ");
264 writeAscii(ScCalcConfig::isOpenCLEnabled() ? "enabled\n" : "disabled\n");
265 writeAscii("---\n");
266
267 sync();
268}
269
270FormulaLogger::~FormulaLogger()
271{
272 if (mpLogFile)
273 mpLogFile->close();
274}
275
276void FormulaLogger::writeAscii( const char* s )
277{
278 if (!mpLogFile)
279 return;
280
281 sal_uInt64 nBytes;
282 mpLogFile->write(s, strlen(s), nBytes);
283}
284
285void FormulaLogger::writeAscii( const char* s, size_t n )
286{
287 if (!mpLogFile)
288 return;
289
290 sal_uInt64 nBytes;
291 mpLogFile->write(s, n, nBytes);
292}
293
294void FormulaLogger::write( std::u16string_view ou )
295{
296 OString s = OUStringToOString(ou, RTL_TEXTENCODING_UTF8);
297 writeAscii(s.getStr(), s.getLength());
298}
299
300void FormulaLogger::write( sal_Int32 n )
301{
302 OString s = OString::number(n);
303 writeAscii(s.getStr(), s.getLength());
304}
305
306void FormulaLogger::sync()
307{
308 if (!mpLogFile)
309 return;
310
311 mpLogFile->sync();
312}
313
314void FormulaLogger::writeNestLevel()
315{
316 // Write the nest level, but keep it only 1-character length to avoid
317 // messing up the spacing.
318 if (mnNestLevel < 10)
319 write(mnNestLevel);
320 else
321 writeAscii("!");
322
323 writeAscii(": ");
324 for (sal_Int32 i = 1; i < mnNestLevel; ++i)
325 writeAscii(" ");
326}
327
328FormulaLogger::GroupScope FormulaLogger::enterGroup(
329 const ScDocument& rDoc, const ScFormulaCell& rCell )
330{
331 // Get the file name if available.
332 const SfxObjectShell* pShell = rDoc.GetDocumentShell();
333 const SfxMedium* pMedium = pShell ? pShell->GetMedium() : nullptr;
334 OUString aName;
335 if (pMedium)
336 aName = pMedium->GetURLObject().GetLastName();
337 if (aName.isEmpty())
338 aName = "-"; // unsaved document.
339
340 OUString aGroupPrefix = aName + ": formula-group: " +
342
343 bool bOutputEnabled = mpLastGroup != rCell.GetCellGroup().get();
344 mpLastGroup = rCell.GetCellGroup().get();
345
346 return GroupScope(*this, aGroupPrefix, rDoc, rCell, bOutputEnabled);
347}
348
349}
350
351/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScRefFlags
Definition: address.hxx:158
OUString GetLastName(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
SCTAB Tab() const
Definition: address.hxx:283
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2074
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:492
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1010
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
SCROW GetSharedLength() const
const ScFormulaCellGroupRef & GetCellGroup() const
sal_Int32 GetWeight() const
ScTokenArray * GetCode()
ScAddress aPos
static const ScCalcConfig & GetGlobalConfig()
Definition: interpr4.cxx:3902
OUString CreateString(sc::TokenStringContext &rCxt, const ScAddress &rPos) const
Create a string representation of formula token array without modifying the internal state of the tok...
Definition: token.cxx:5238
const INetURLObject & GetURLObject() const
SfxMedium * GetMedium() const
StackVar GetType() const
void addRefMessage(const ScAddress &, const ScAddress &, size_t, const formula::VectorRefArray &)
void addMessage(const OUString &)
void addGroupSizeThresholdMessage(const ScFormulaCell &)
Dummy class with all empty inline methods.
static FormulaLogger get()
GroupScope enterGroup(const ScDocument &, const ScFormulaCell &)
URL aURL
float u
OUString aName
aBuf
int i
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
CAUTION! The following defines must be in the same namespace as the respective type.
Definition: broadcast.cxx:15
static bool isOpenCLEnabled()
Definition: calcconfig.cxx:69
const double * mpNumericArray
rtl_uString ** mpStringArray
std::vector< OUString > maMessages
Impl(FormulaLogger &rLogger, OUString aPrefix, const ScDocument &rDoc, const ScFormulaCell &rCell, bool bOutputEnabled)
Context for creating string from an array of formula tokens, used in ScTokenArray::CreateString().