LibreOffice Module formula (master) 1
FormulaHelper.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 file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <algorithm>
21
26
27namespace formula
28{
29
30 namespace
31 {
32
33 class OEmptyFunctionDescription : public IFunctionDescription
34 {
35 public:
36 OEmptyFunctionDescription(){}
37 virtual ~OEmptyFunctionDescription(){}
38
39 virtual OUString getFunctionName() const override { return OUString(); }
40 virtual const IFunctionCategory* getCategory() const override { return nullptr; }
41 virtual OUString getDescription() const override { return OUString(); }
42 virtual sal_Int32 getSuppressedArgumentCount() const override { return 0; }
43 virtual OUString getFormula(const ::std::vector< OUString >& ) const override { return OUString(); }
44 virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const override {}
45 virtual void initArgumentInfo() const override {}
46 virtual OUString getSignature() const override { return OUString(); }
47 virtual OUString getHelpId() const override { return ""; }
48 virtual bool isHidden() const override { return false; }
49 virtual sal_uInt32 getParameterCount() const override { return 0; }
50 virtual sal_uInt32 getVarArgsStart() const override { return 0; }
51 virtual sal_uInt32 getVarArgsLimit() const override { return 0; }
52 virtual OUString getParameterName(sal_uInt32 ) const override { return OUString(); }
53 virtual OUString getParameterDescription(sal_uInt32 ) const override { return OUString(); }
54 virtual bool isParameterOptional(sal_uInt32 ) const override { return false; }
55 };
56 }
57
58// class FormulaHelper - static Method
59
60
61#define FUNC_NOTFOUND -1
62
64 :m_rCharClass(m_aSysLocale.GetCharClass())
65 ,m_pFunctionManager(_pFunctionManager)
66 ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
67 ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
68 ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
69 ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
70 ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
71{
72}
73
75{
77}
78
79bool FormulaHelper::GetNextFunc( const OUString& rFormula,
80 bool bBack,
81 sal_Int32& rFStart, // Input and output
82 sal_Int32* pFEnd, // = NULL
83 const IFunctionDescription** ppFDesc, // = NULL
84 ::std::vector< OUString>* pArgs ) const // = NULL
85{
86 sal_Int32 nOldStart = rFStart;
87 OUString aFname;
88
89 rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : nullptr );
90 bool bFound = ( rFStart != FUNC_NOTFOUND );
91
92 if ( bFound )
93 {
94 if ( pFEnd )
95 *pFEnd = GetFunctionEnd( rFormula, rFStart );
96
97 if ( ppFDesc )
98 {
99 *ppFDesc = nullptr;
100 const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
101 for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
102 {
103 const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
104 const sal_uInt32 nCount = pCategory->getCount();
105 for(sal_uInt32 i = 0 ; i < nCount; ++i)
106 {
107 const IFunctionDescription* pCurrent = pCategory->getFunction(i);
108 if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(aFname) )
109 {
110 *ppFDesc = pCurrent;
111 break;
112 }
113 }// for(sal_uInt32 i = 0 ; i < nCount; ++i)
114 }
115 if ( *ppFDesc && pArgs )
116 {
117 GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
118 }
119 else
120 {
121 static OEmptyFunctionDescription s_aFunctionDescription;
122 *ppFDesc = &s_aFunctionDescription;
123 }
124 }
125 }
126 else
127 rFStart = nOldStart;
128
129 return bFound;
130}
131
132
133void FormulaHelper::FillArgStrings( std::u16string_view rFormula,
134 sal_Int32 nFuncPos,
135 sal_uInt16 nArgs,
136 ::std::vector< OUString >& _rArgs ) const
137{
138 sal_Int32 nStart = 0;
139 sal_Int32 nEnd = 0;
140 sal_uInt16 i;
141 bool bLast = false;
142
143 for ( i=0; i<nArgs && !bLast; i++ )
144 {
145 nStart = GetArgStart( rFormula, nFuncPos, i );
146
147 if ( i+1<nArgs ) // last argument?
148 {
149 nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
150
151 if ( nEnd != nStart )
152 _rArgs.push_back(OUString(rFormula.substr( nStart, nEnd-1-nStart )));
153 else
154 {
155 _rArgs.emplace_back();
156 bLast = true;
157 }
158 }
159 else
160 {
161 nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
162 if ( nStart < nEnd )
163 _rArgs.push_back( OUString(rFormula.substr( nStart, nEnd-nStart )) );
164 else
165 _rArgs.emplace_back();
166 }
167 }
168
169 if ( bLast )
170 for ( ; i<nArgs; i++ )
171 _rArgs.emplace_back();
172}
173
174
175void FormulaHelper::GetArgStrings( ::std::vector< OUString >& _rArgs,
176 std::u16string_view rFormula,
177 sal_Int32 nFuncPos,
178 sal_uInt16 nArgs ) const
179{
180 if (nArgs)
181 {
182 FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
183 }
184}
185
186
187static bool IsFormulaText(const CharClass& rCharClass, const OUString& rStr, sal_Int32 nPos)
188{
189 if( rCharClass.isLetterNumeric( rStr, nPos ) )
190 return true;
191 else
192 { // In internationalized versions function names may contain a dot
193 // and in every version also an underscore... ;-)
194 sal_Unicode c = rStr[nPos];
195 return c == '.' || c == '_';
196 }
197
198}
199
200sal_Int32 FormulaHelper::GetFunctionStart( const OUString& rFormula,
201 sal_Int32 nStart,
202 bool bBack,
203 OUString* pFuncName ) const
204{
205 sal_Int32 nStrLen = rFormula.getLength();
206
207 if ( nStrLen < nStart )
208 return nStart;
209
210 sal_Int32 nFStart = FUNC_NOTFOUND;
211 sal_Int32 nParPos = bBack ? ::std::min( nStart, nStrLen - 1) : nStart;
212
213 bool bRepeat;
214 do
215 {
216 bool bFound = false;
217 bRepeat = false;
218
219 if ( bBack )
220 {
221 while ( !bFound && (nParPos > 0) )
222 {
223 if ( rFormula[nParPos] == '"' )
224 {
225 nParPos--;
226 while ( (nParPos > 0) && rFormula[nParPos] != '"' )
227 nParPos--;
228 if (nParPos > 0)
229 nParPos--;
230 }
231 else
232 {
233 bFound = rFormula[nParPos] == '(';
234 if ( !bFound )
235 nParPos--;
236 }
237 }
238 }
239 else
240 {
241 while ( !bFound && (0 <= nParPos && nParPos < nStrLen) )
242 {
243 if ( rFormula[nParPos] == '"' )
244 {
245 nParPos++;
246 while ( (nParPos < nStrLen) && rFormula[nParPos] != '"' )
247 nParPos++;
248 nParPos++;
249 }
250 else
251 {
252 bFound = rFormula[nParPos] == '(';
253 if ( !bFound )
254 nParPos++;
255 }
256 }
257 }
258
259 if ( bFound && (nParPos > 0) )
260 {
261 nFStart = nParPos-1;
262
263 while ( (nFStart > 0) && IsFormulaText(m_rCharClass, rFormula, nFStart ))
264 nFStart--;
265 }
266
267 nFStart++;
268
269 if ( bFound )
270 {
271 if ( IsFormulaText( m_rCharClass, rFormula, nFStart ) )
272 {
273 // Function found
274 if ( pFuncName )
275 *pFuncName = rFormula.copy( nFStart, nParPos-nFStart );
276 }
277 else // Brackets without function -> keep searching
278 {
279 bRepeat = true;
280 if ( !bBack )
281 nParPos++;
282 else if (nParPos > 0)
283 nParPos--;
284 else
285 bRepeat = false;
286 }
287 }
288 else // No brackets found
289 {
290 nFStart = FUNC_NOTFOUND;
291 if ( pFuncName )
292 pFuncName->clear();
293 }
294 }
295 while(bRepeat);
296
297 return nFStart;
298}
299
300
301sal_Int32 FormulaHelper::GetFunctionEnd( std::u16string_view rStr, sal_Int32 nStart ) const
302{
303 sal_Int32 nStrLen = rStr.size();
304
305 if ( nStrLen < nStart )
306 return nStart;
307
308 short nParCount = 0;
309 bool bInArray = false;
310 bool bFound = false;
311
312 while ( !bFound && (nStart < nStrLen) )
313 {
314 sal_Unicode c = rStr[nStart];
315
316 if ( c == '"' )
317 {
318 nStart++;
319 while ( (nStart < nStrLen) && rStr[nStart] != '"' )
320 nStart++;
321 }
322 else if ( c == open )
323 nParCount++;
324 else if ( c == close )
325 {
326 nParCount--;
327 if ( nParCount == 0 )
328 bFound = true;
329 else if ( nParCount < 0 )
330 {
331 bFound = true;
332 nStart--; // read one too far
333 }
334 }
335 else if ( c == arrayOpen )
336 {
337 bInArray = true;
338 }
339 else if ( c == arrayClose )
340 {
341 bInArray = false;
342 }
343 else if ( c == sep )
344 {
345 if ( !bInArray && nParCount == 0 )
346 {
347 bFound = true;
348 nStart--; // read one too far
349 }
350 }
351 nStart++; // Set behind found position
352 }
353
354 // nStart > nStrLen can happen if there was an unclosed quote; instead of
355 // checking that in every loop iteration check it once here.
356 return std::min(nStart, nStrLen);
357}
358
359
360sal_Int32 FormulaHelper::GetArgStart( std::u16string_view rStr, sal_Int32 nStart, sal_uInt16 nArg ) const
361{
362 sal_Int32 nStrLen = rStr.size();
363
364 if ( nStrLen < nStart )
365 return nStart;
366
367 short nParCount = 0;
368 bool bInArray = false;
369 bool bFound = false;
370
371 while ( !bFound && (nStart < nStrLen) )
372 {
373 sal_Unicode c = rStr[nStart];
374
375 if ( c == '"' )
376 {
377 nStart++;
378 while ( (nStart < nStrLen) && rStr[nStart] != '"' )
379 nStart++;
380 }
381 else if ( c == open )
382 {
383 bFound = ( nArg == 0 );
384 nParCount++;
385 }
386 else if ( c == close )
387 {
388 nParCount--;
389 bFound = ( nParCount == 0 );
390 }
391 else if ( c == arrayOpen )
392 {
393 bInArray = true;
394 }
395 else if ( c == arrayClose )
396 {
397 bInArray = false;
398 }
399 else if ( c == sep )
400 {
401 if ( !bInArray && nParCount == 1 )
402 {
403 nArg--;
404 bFound = ( nArg == 0 );
405 }
406 }
407 nStart++;
408 }
409
410 return nStart;
411}
412
413} // formula
414
415
416/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define FUNC_NOTFOUND
bool isLetterNumeric(const OUString &rStr, sal_Int32 nPos) const
const sal_Unicode open
const CharClass & m_rCharClass
const sal_Unicode close
const sal_Unicode arrayOpen
FormulaHelper(const IFunctionManager *_pFunctionManager)
sal_Int32 GetFunctionEnd(std::u16string_view rFormula, sal_Int32 nStart) const
const sal_Unicode arrayClose
bool GetNextFunc(const OUString &rFormula, bool bBack, sal_Int32 &rFStart, sal_Int32 *pFEnd=nullptr, const IFunctionDescription **ppFDesc=nullptr, ::std::vector< OUString > *pArgs=nullptr) const
sal_Int32 GetFunctionStart(const OUString &rFormula, sal_Int32 nStart, bool bBack, OUString *pFuncName=nullptr) const
void GetArgStrings(::std::vector< OUString > &_rArgs, std::u16string_view rFormula, sal_Int32 nFuncPos, sal_uInt16 nArgs) const
const IFunctionManager * m_pFunctionManager
sal_Int32 GetArgStart(std::u16string_view rFormula, sal_Int32 nStart, sal_uInt16 nArg) const
sal_Int32 GetCategoryCount() const
void FillArgStrings(std::u16string_view rFormula, sal_Int32 nFuncPos, sal_uInt16 nArgs, ::std::vector< OUString > &_rArgs) const
const sal_Unicode sep
virtual const IFunctionDescription * getFunction(sal_uInt32 _nPos) const =0
virtual sal_uInt32 getCount() const =0
virtual OUString getFunctionName() const =0
virtual sal_uInt32 getCount() const =0
int nCount
bool close
sal_uInt16 nPos
eOk
static bool IsFormulaText(const CharClass &rCharClass, const OUString &rStr, sal_Int32 nPos)
int i
sal_uInt16 sal_Unicode