1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
8 #include <formulalogger.hxx>
9 #include <formulacell.hxx>
10 #include <tokenarray.hxx>
11 #include <document.hxx>
13 #include <tokenstringcontext.hxx>
14 #include <address.hxx>
15 #include <interpre.hxx>
17 #include <osl/file.hxx>
18 #include <sfx2/objsh.hxx>
19 #include <sfx2/docfile.hxx>
20 #include <tools/urlobj.hxx>
21 #include <formula/vectortoken.hxx>
22 #include <rtl/ustrbuf.hxx>
31 std::unique_ptr
<osl::File
> initFile()
33 const char* pPath
= std::getenv("LIBO_FORMULA_LOG_FILE");
37 // Support both file:///... and system file path notations.
38 OUString aPath
= OUString::createFromAscii(pPath
);
40 aURL
.SetSmartURL(aPath
);
41 aPath
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
43 return std::make_unique
<osl::File
>(aPath
);
46 ScRefFlags
getRefFlags( const ScAddress
& rCellPos
, const ScAddress
& rRefPos
)
48 ScRefFlags eFlags
= ScRefFlags::VALID
;
49 if (rCellPos
.Tab() != rRefPos
.Tab())
50 eFlags
|= ScRefFlags::TAB_3D
;
56 FormulaLogger
& FormulaLogger::get()
58 static FormulaLogger aLogger
;
62 struct FormulaLogger::GroupScope::Impl
64 FormulaLogger
& mrLogger
;
65 const ScDocument
& mrDoc
;
68 std::vector
<OUString
> maMessages
;
73 Impl( FormulaLogger
& rLogger
, OUString aPrefix
, const ScDocument
& rDoc
,
74 const ScFormulaCell
& rCell
, bool bOutputEnabled
) :
75 mrLogger(rLogger
), mrDoc(rDoc
), maPrefix(std::move(aPrefix
)),
76 mbCalcComplete(false), mbOutputEnabled(bOutputEnabled
)
78 ++mrLogger
.mnNestLevel
;
83 sc::TokenStringContext
aCxt(rDoc
, rDoc
.GetGrammar());
84 OUString aFormula
= rCell
.GetCode()->CreateString(aCxt
, rCell
.aPos
);
86 mrLogger
.write(maPrefix
);
87 mrLogger
.writeNestLevel();
89 mrLogger
.writeAscii("-- enter (formula='");
90 mrLogger
.write(aFormula
);
91 mrLogger
.writeAscii("', size=");
92 mrLogger
.write(rCell
.GetSharedLength());
93 mrLogger
.writeAscii(")\n");
100 for (const OUString
& rMsg
: maMessages
)
102 mrLogger
.write(maPrefix
);
103 mrLogger
.writeNestLevel();
104 mrLogger
.writeAscii(" * ");
105 mrLogger
.write(rMsg
);
106 mrLogger
.writeAscii("\n");
109 mrLogger
.write(maPrefix
);
110 mrLogger
.writeNestLevel();
111 mrLogger
.writeAscii("-- exit (");
113 mrLogger
.writeAscii("calculation complete");
115 mrLogger
.writeAscii("without calculation");
117 mrLogger
.writeAscii(")\n");
122 --mrLogger
.mnNestLevel
;
126 FormulaLogger::GroupScope::GroupScope(
127 FormulaLogger
& rLogger
, const OUString
& rPrefix
, const ScDocument
& rDoc
,
128 const ScFormulaCell
& rCell
, bool bOutputEnabled
) :
129 mpImpl(std::make_unique
<Impl
>(rLogger
, rPrefix
, rDoc
, rCell
, bOutputEnabled
)) {}
131 FormulaLogger::GroupScope::GroupScope(GroupScope
&& r
) noexcept
: mpImpl(std::move(r
.mpImpl
)) {}
133 FormulaLogger::GroupScope::~GroupScope() {}
135 void FormulaLogger::GroupScope::addMessage( const OUString
& rMsg
)
137 mpImpl
->maMessages
.push_back(rMsg
);
140 void FormulaLogger::GroupScope::addRefMessage(
141 const ScAddress
& rCellPos
, const ScAddress
& rRefPos
, size_t nLen
,
142 const formula::VectorRefArray
& rArray
)
144 ScRange
aRefRange(rRefPos
);
145 aRefRange
.aEnd
.IncRow(nLen
-1);
146 OUString aRangeStr
= aRefRange
.Format(mpImpl
->mrDoc
, getRefFlags(rCellPos
, rRefPos
));
148 std::u16string_view aMsg
;
149 if (rArray
.mpNumericArray
)
151 if (rArray
.mpStringArray
)
153 // mixture of numeric and string cells.
154 aMsg
= u
"numeric and string";
158 // numeric cells only.
159 aMsg
= u
"numeric only";
164 if (rArray
.mpStringArray
)
166 // string cells only.
167 aMsg
= u
"string only";
176 mpImpl
->maMessages
.push_back(aRangeStr
+ ": " + aMsg
);
179 void FormulaLogger::GroupScope::addRefMessage(
180 const ScAddress
& rCellPos
, const ScAddress
& rRefPos
, size_t nLen
,
181 const std::vector
<formula::VectorRefArray
>& rArrays
)
183 ScAddress
aPos(rRefPos
); // copy
184 for (const formula::VectorRefArray
& rArray
: rArrays
)
186 addRefMessage(rCellPos
, aPos
, nLen
, rArray
);
191 void FormulaLogger::GroupScope::addRefMessage(
192 const ScAddress
& rCellPos
, const ScAddress
& rRefPos
,
193 const formula::FormulaToken
& rToken
)
195 OUString aPosStr
= rRefPos
.Format(getRefFlags(rCellPos
, rRefPos
), &mpImpl
->mrDoc
);
196 std::u16string_view aMsg
;
197 switch (rToken
.GetType())
199 case formula::svDouble
:
200 aMsg
= u
"numeric value";
202 case formula::svString
:
203 aMsg
= u
"string value";
206 aMsg
= u
"unknown value";
209 mpImpl
->maMessages
.push_back(aPosStr
+ ": " + aMsg
);
212 void FormulaLogger::GroupScope::addGroupSizeThresholdMessage( const ScFormulaCell
& rCell
)
214 OUString aBuf
= "group length below minimum threshold ("
215 + OUString::number(rCell
.GetWeight())
217 + OUString::number(ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize
)
219 mpImpl
->maMessages
.push_back(aBuf
);
222 void FormulaLogger::GroupScope::setCalcComplete()
224 mpImpl
->mbCalcComplete
= true;
225 addMessage(u
"calculation performed"_ustr
);
228 FormulaLogger::FormulaLogger()
230 mpLogFile
= initFile();
235 osl::FileBase::RC eRC
= mpLogFile
->open(osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
);
237 if (eRC
== osl::FileBase::E_EXIST
)
239 eRC
= mpLogFile
->open(osl_File_OpenFlag_Write
);
241 if (eRC
!= osl::FileBase::E_None
)
243 // Failed to open an existing log file.
248 if (mpLogFile
->setPos(osl_Pos_End
, 0) != osl::FileBase::E_None
)
250 // Failed to set the position to the end of the file.
255 else if (eRC
!= osl::FileBase::E_None
)
257 // Failed to create a new file.
262 // Output the header information.
264 writeAscii("OpenCL: ");
265 writeAscii(ScCalcConfig::isOpenCLEnabled() ? "enabled\n" : "disabled\n");
271 FormulaLogger::~FormulaLogger()
277 void FormulaLogger::writeAscii( const char* s
)
283 mpLogFile
->write(s
, strlen(s
), nBytes
);
286 void FormulaLogger::writeAscii( const char* s
, size_t n
)
292 mpLogFile
->write(s
, n
, nBytes
);
295 void FormulaLogger::write( std::u16string_view ou
)
297 OString s
= OUStringToOString(ou
, RTL_TEXTENCODING_UTF8
);
298 writeAscii(s
.getStr(), s
.getLength());
301 void FormulaLogger::write( sal_Int32 n
)
303 OString s
= OString::number(n
);
304 writeAscii(s
.getStr(), s
.getLength());
307 void FormulaLogger::sync()
315 void FormulaLogger::writeNestLevel()
317 // Write the nest level, but keep it only 1-character length to avoid
318 // messing up the spacing.
319 if (mnNestLevel
< 10)
325 for (sal_Int32 i
= 1; i
< mnNestLevel
; ++i
)
329 FormulaLogger::GroupScope
FormulaLogger::enterGroup(
330 const ScDocument
& rDoc
, const ScFormulaCell
& rCell
)
332 // Get the file name if available.
333 const ScDocShell
* pShell
= rDoc
.GetDocumentShell();
334 const SfxMedium
* pMedium
= pShell
? pShell
->GetMedium() : nullptr;
337 aName
= pMedium
->GetURLObject().GetLastName();
339 aName
= "-"; // unsaved document.
341 OUString aGroupPrefix
= aName
+ ": formula-group: " +
342 rCell
.aPos
.Format(ScRefFlags::VALID
| ScRefFlags::TAB_3D
, &rDoc
, rDoc
.GetAddressConvention()) + ": ";
344 bool bOutputEnabled
= mpLastGroup
!= rCell
.GetCellGroup().get();
345 mpLastGroup
= rCell
.GetCellGroup().get();
347 return GroupScope(*this, aGroupPrefix
, rDoc
, rCell
, bOutputEnabled
);
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */