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 OUStringBuffer aBuf;
144
145 ScRange aRefRange(rRefPos);
146 aRefRange.aEnd.IncRow(nLen-1);
147 OUString aRangeStr = aRefRange.Format(mpImpl->mrDoc, getRefFlags(rCellPos, rRefPos));
148 aBuf.append(aRangeStr);
149 aBuf.append(": ");
150
151 if (rArray.mpNumericArray)
152 {
153 if (rArray.mpStringArray)
154 {
155 // mixture of numeric and string cells.
156 aBuf.append("numeric and string");
157 }
158 else
159 {
160 // numeric cells only.
161 aBuf.append("numeric only");
162 }
163 }
164 else
165 {
166 if (rArray.mpStringArray)
167 {
168 // string cells only.
169 aBuf.append("string only");
170 }
171 else
172 {
173 // empty cells.
174 aBuf.append("empty");
175 }
176 }
177
178 mpImpl->maMessages.push_back(aBuf.makeStringAndClear());
179}
180
182 const ScAddress& rCellPos, const ScAddress& rRefPos, size_t nLen,
183 const std::vector<formula::VectorRefArray>& rArrays )
184{
185 ScAddress aPos(rRefPos); // copy
186 for (const formula::VectorRefArray& rArray : rArrays)
187 {
188 addRefMessage(rCellPos, aPos, nLen, rArray);
189 aPos.IncCol();
190 }
191}
192
194 const ScAddress& rCellPos, const ScAddress& rRefPos,
195 const formula::FormulaToken& rToken )
196{
197 OUStringBuffer aBuf;
198 OUString aPosStr = rRefPos.Format(getRefFlags(rCellPos, rRefPos), &mpImpl->mrDoc);
199 aBuf.append(aPosStr);
200 aBuf.append(": ");
201
202 switch (rToken.GetType())
203 {
205 aBuf.append("numeric value");
206 break;
208 aBuf.append("string value");
209 break;
210 default:
211 aBuf.append("unknown value");
212 }
213
214 mpImpl->maMessages.push_back(aBuf.makeStringAndClear());
215}
216
218{
219 OUStringBuffer aBuf;
220 aBuf.append("group length below minimum threshold (");
221 aBuf.append(rCell.GetWeight());
222 aBuf.append(" < ");
223 aBuf.append(ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize);
224 aBuf.append(")");
225 mpImpl->maMessages.push_back(aBuf.makeStringAndClear());
226}
227
229{
230 mpImpl->mbCalcComplete = true;
231 addMessage("calculation performed");
232}
233
234FormulaLogger::FormulaLogger()
235{
236 mpLogFile = initFile();
237
238 if (!mpLogFile)
239 return;
240
241 osl::FileBase::RC eRC = mpLogFile->open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
242
243 if (eRC == osl::FileBase::E_EXIST)
244 {
245 eRC = mpLogFile->open(osl_File_OpenFlag_Write);
246
247 if (eRC != osl::FileBase::E_None)
248 {
249 // Failed to open an existing log file.
250 mpLogFile.reset();
251 return;
252 }
253
254 if (mpLogFile->setPos(osl_Pos_End, 0) != osl::FileBase::E_None)
255 {
256 // Failed to set the position to the end of the file.
257 mpLogFile.reset();
258 return;
259 }
260 }
261 else if (eRC != osl::FileBase::E_None)
262 {
263 // Failed to create a new file.
264 mpLogFile.reset();
265 return;
266 }
267
268 // Output the header information.
269 writeAscii("---\n");
270 writeAscii("OpenCL: ");
271 writeAscii(ScCalcConfig::isOpenCLEnabled() ? "enabled\n" : "disabled\n");
272 writeAscii("---\n");
273
274 sync();
275}
276
277FormulaLogger::~FormulaLogger()
278{
279 if (mpLogFile)
280 mpLogFile->close();
281}
282
283void FormulaLogger::writeAscii( const char* s )
284{
285 if (!mpLogFile)
286 return;
287
288 sal_uInt64 nBytes;
289 mpLogFile->write(s, strlen(s), nBytes);
290}
291
292void FormulaLogger::writeAscii( const char* s, size_t n )
293{
294 if (!mpLogFile)
295 return;
296
297 sal_uInt64 nBytes;
298 mpLogFile->write(s, n, nBytes);
299}
300
301void FormulaLogger::write( std::u16string_view ou )
302{
303 OString s = OUStringToOString(ou, RTL_TEXTENCODING_UTF8).getStr();
304 writeAscii(s.getStr(), s.getLength());
305}
306
307void FormulaLogger::write( sal_Int32 n )
308{
309 OString s = OString::number(n);
310 writeAscii(s.getStr(), s.getLength());
311}
312
313void FormulaLogger::sync()
314{
315 if (!mpLogFile)
316 return;
317
318 mpLogFile->sync();
319}
320
321void FormulaLogger::writeNestLevel()
322{
323 // Write the nest level, but keep it only 1-character length to avoid
324 // messing up the spacing.
325 if (mnNestLevel < 10)
326 write(mnNestLevel);
327 else
328 writeAscii("!");
329
330 writeAscii(": ");
331 for (sal_Int32 i = 1; i < mnNestLevel; ++i)
332 writeAscii(" ");
333}
334
335FormulaLogger::GroupScope FormulaLogger::enterGroup(
336 const ScDocument& rDoc, const ScFormulaCell& rCell )
337{
338 // Get the file name if available.
339 const SfxObjectShell* pShell = rDoc.GetDocumentShell();
340 const SfxMedium* pMedium = pShell ? pShell->GetMedium() : nullptr;
341 OUString aName;
342 if (pMedium)
343 aName = pMedium->GetURLObject().GetLastName();
344 if (aName.isEmpty())
345 aName = "-"; // unsaved document.
346
347 OUString aGroupPrefix = aName + ": formula-group: " +
349
350 bool bOutputEnabled = mpLastGroup != rCell.GetCellGroup().get();
351 mpLastGroup = rCell.GetCellGroup().get();
352
353 return GroupScope(*this, aGroupPrefix, rDoc, rCell, bOutputEnabled);
354}
355
356}
357
358/* 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:502
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1008
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1081
SCROW GetSharedLength() const
const ScFormulaCellGroupRef & GetCellGroup() const
sal_Int32 GetWeight() const
ScTokenArray * GetCode()
ScAddress aPos
static const ScCalcConfig & GetGlobalConfig()
Definition: interpr4.cxx:3890
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:5217
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
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.
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().