Line data Source code
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 :
22 : #include "formula/formulahelper.hxx"
23 : #include <unotools/charclass.hxx>
24 : #include <unotools/syslocale.hxx>
25 :
26 : #include <boost/scoped_ptr.hpp>
27 :
28 : namespace formula
29 : {
30 :
31 : namespace
32 : {
33 :
34 : class OEmptyFunctionDescription : public IFunctionDescription
35 : {
36 : public:
37 0 : OEmptyFunctionDescription(){}
38 0 : virtual ~OEmptyFunctionDescription(){}
39 :
40 0 : virtual OUString getFunctionName() const SAL_OVERRIDE { return OUString(); }
41 0 : virtual const IFunctionCategory* getCategory() const SAL_OVERRIDE { return NULL; }
42 0 : virtual OUString getDescription() const SAL_OVERRIDE { return OUString(); }
43 0 : virtual sal_Int32 getSuppressedArgumentCount() const SAL_OVERRIDE { return 0; }
44 0 : virtual OUString getFormula(const ::std::vector< OUString >& ) const SAL_OVERRIDE { return OUString(); }
45 0 : virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const SAL_OVERRIDE {}
46 0 : virtual void initArgumentInfo() const SAL_OVERRIDE {}
47 0 : virtual OUString getSignature() const SAL_OVERRIDE { return OUString(); }
48 0 : virtual OString getHelpId() const SAL_OVERRIDE { return ""; }
49 0 : virtual sal_uInt32 getParameterCount() const SAL_OVERRIDE { return 0; }
50 0 : virtual OUString getParameterName(sal_uInt32 ) const SAL_OVERRIDE { return OUString(); }
51 0 : virtual OUString getParameterDescription(sal_uInt32 ) const SAL_OVERRIDE { return OUString(); }
52 0 : virtual bool isParameterOptional(sal_uInt32 ) const SAL_OVERRIDE { return false; }
53 : };
54 : }
55 :
56 : // class FormulaHelper - static Method
57 :
58 :
59 : #define FUNC_NOTFOUND -1
60 :
61 0 : FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
62 0 : :m_pSysLocale(new SvtSysLocale)
63 : ,m_pFunctionManager(_pFunctionManager)
64 0 : ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
65 0 : ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
66 0 : ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
67 0 : ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
68 0 : ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
69 : {
70 0 : m_pCharClass = m_pSysLocale->GetCharClassPtr();
71 0 : }
72 :
73 0 : bool FormulaHelper::GetNextFunc( const OUString& rFormula,
74 : bool bBack,
75 : sal_Int32& rFStart, // Input and output
76 : sal_Int32* pFEnd, // = NULL
77 : const IFunctionDescription** ppFDesc, // = NULL
78 : ::std::vector< OUString>* pArgs ) const // = NULL
79 : {
80 0 : sal_Int32 nOldStart = rFStart;
81 0 : OUString aFname;
82 :
83 0 : rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL );
84 0 : bool bFound = ( rFStart != FUNC_NOTFOUND );
85 :
86 0 : if ( bFound )
87 : {
88 0 : if ( pFEnd )
89 0 : *pFEnd = GetFunctionEnd( rFormula, rFStart );
90 :
91 0 : if ( ppFDesc )
92 : {
93 0 : *ppFDesc = NULL;
94 0 : const OUString sTemp( aFname );
95 0 : const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
96 0 : for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
97 : {
98 0 : boost::scoped_ptr<const IFunctionCategory> pCategory(m_pFunctionManager->getCategory(j));
99 0 : const sal_uInt32 nCount = pCategory->getCount();
100 0 : for(sal_uInt32 i = 0 ; i < nCount; ++i)
101 : {
102 0 : const IFunctionDescription* pCurrent = pCategory->getFunction(i);
103 0 : if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(sTemp) )
104 : {
105 0 : *ppFDesc = pCurrent;
106 0 : break;
107 : }
108 : }// for(sal_uInt32 i = 0 ; i < nCount; ++i)
109 0 : }
110 0 : if ( *ppFDesc && pArgs )
111 : {
112 0 : GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
113 : }
114 : else
115 : {
116 0 : static OEmptyFunctionDescription s_aFunctionDescription;
117 0 : *ppFDesc = &s_aFunctionDescription;
118 0 : }
119 : }
120 : }
121 : else
122 0 : rFStart = nOldStart;
123 :
124 0 : return bFound;
125 : }
126 :
127 :
128 :
129 0 : void FormulaHelper::FillArgStrings( const OUString& rFormula,
130 : sal_Int32 nFuncPos,
131 : sal_uInt16 nArgs,
132 : ::std::vector< OUString >& _rArgs ) const
133 : {
134 0 : sal_Int32 nStart = 0;
135 0 : sal_Int32 nEnd = 0;
136 : sal_uInt16 i;
137 0 : bool bLast = false;
138 :
139 0 : for ( i=0; i<nArgs && !bLast; i++ )
140 : {
141 0 : nStart = GetArgStart( rFormula, nFuncPos, i );
142 :
143 0 : if ( i+1<nArgs ) // last argument?
144 : {
145 0 : nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
146 :
147 0 : if ( nEnd != nStart )
148 0 : _rArgs.push_back(rFormula.copy( nStart, nEnd-1-nStart ));
149 : else
150 0 : _rArgs.push_back(OUString()), bLast = true;
151 : }
152 : else
153 : {
154 0 : nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
155 0 : if ( nStart < nEnd )
156 0 : _rArgs.push_back( rFormula.copy( nStart, nEnd-nStart ) );
157 : else
158 0 : _rArgs.push_back(OUString());
159 : }
160 : }
161 :
162 0 : if ( bLast )
163 0 : for ( ; i<nArgs; i++ )
164 0 : _rArgs.push_back(OUString());
165 0 : }
166 :
167 :
168 :
169 0 : void FormulaHelper::GetArgStrings( ::std::vector< OUString >& _rArgs,
170 : const OUString& rFormula,
171 : sal_Int32 nFuncPos,
172 : sal_uInt16 nArgs ) const
173 : {
174 0 : if (nArgs)
175 : {
176 0 : FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
177 : }
178 0 : }
179 :
180 :
181 :
182 0 : inline bool IsFormulaText( const CharClass* _pCharClass,const OUString& rStr, sal_Int32 nPos )
183 : {
184 0 : if( _pCharClass->isLetterNumeric( rStr, nPos ) )
185 0 : return true;
186 : else
187 : { // In internationalized versions function names may contain a dot
188 : // and in every version also an underscore... ;-)
189 0 : sal_Unicode c = rStr[nPos];
190 0 : return c == '.' || c == '_';
191 : }
192 :
193 : }
194 :
195 0 : sal_Int32 FormulaHelper::GetFunctionStart( const OUString& rFormula,
196 : sal_Int32 nStart,
197 : bool bBack,
198 : OUString* pFuncName ) const
199 : {
200 0 : sal_Int32 nStrLen = rFormula.getLength();
201 :
202 0 : if ( nStrLen < nStart )
203 0 : return nStart;
204 :
205 0 : sal_Int32 nFStart = FUNC_NOTFOUND;
206 0 : sal_Int32 nParPos = bBack ? ::std::min( nStart, nStrLen - 1) : nStart;
207 :
208 : bool bRepeat;
209 0 : do
210 : {
211 0 : bool bFound = false;
212 0 : bRepeat = false;
213 :
214 0 : if ( bBack )
215 : {
216 0 : while ( !bFound && (nParPos > 0) )
217 : {
218 0 : if ( rFormula[nParPos] == '"' )
219 : {
220 0 : nParPos--;
221 0 : while ( (nParPos > 0) && rFormula[nParPos] != '"' )
222 0 : nParPos--;
223 0 : if (nParPos > 0)
224 0 : nParPos--;
225 : }
226 0 : else if ( !(bFound = ( rFormula[nParPos] == '(' ) ) )
227 0 : nParPos--;
228 : }
229 : }
230 : else
231 : {
232 0 : while ( !bFound && (0 <= nParPos && nParPos < nStrLen) )
233 : {
234 0 : if ( rFormula[nParPos] == '"' )
235 : {
236 0 : nParPos++;
237 0 : while ( (nParPos < nStrLen) && rFormula[nParPos] != '"' )
238 0 : nParPos++;
239 0 : nParPos++;
240 : }
241 0 : else if ( !(bFound = ( rFormula[nParPos] == '(' ) ) )
242 0 : nParPos++;
243 : }
244 : }
245 :
246 0 : if ( bFound && (nParPos > 0) )
247 : {
248 0 : nFStart = nParPos-1;
249 :
250 0 : while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
251 0 : nFStart--;
252 : }
253 :
254 0 : nFStart++;
255 :
256 0 : if ( bFound )
257 : {
258 0 : if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
259 : {
260 : // Function found
261 0 : if ( pFuncName )
262 0 : *pFuncName = rFormula.copy( nFStart, nParPos-nFStart );
263 : }
264 : else // Brackets without function -> keep searching
265 : {
266 0 : bRepeat = true;
267 0 : if ( !bBack )
268 0 : nParPos++;
269 0 : else if (nParPos > 0)
270 0 : nParPos--;
271 : else
272 0 : bRepeat = false;
273 : }
274 : }
275 : else // No brackets found
276 : {
277 0 : nFStart = FUNC_NOTFOUND;
278 0 : if ( pFuncName )
279 0 : pFuncName->clear();
280 : }
281 : }
282 : while(bRepeat);
283 :
284 0 : return nFStart;
285 : }
286 :
287 :
288 :
289 0 : sal_Int32 FormulaHelper::GetFunctionEnd( const OUString& rStr, sal_Int32 nStart ) const
290 : {
291 0 : sal_Int32 nStrLen = rStr.getLength();
292 :
293 0 : if ( nStrLen < nStart )
294 0 : return nStart;
295 :
296 0 : short nParCount = 0;
297 0 : bool bInArray = false;
298 0 : bool bFound = false;
299 :
300 0 : while ( !bFound && (nStart < nStrLen) )
301 : {
302 0 : sal_Unicode c = rStr[nStart];
303 :
304 0 : if ( c == '"' )
305 : {
306 0 : nStart++;
307 0 : while ( (nStart < nStrLen) && rStr[nStart] != '"' )
308 0 : nStart++;
309 : }
310 0 : else if ( c == open )
311 0 : nParCount++;
312 0 : else if ( c == close )
313 : {
314 0 : nParCount--;
315 0 : if ( nParCount == 0 )
316 0 : bFound = true;
317 0 : else if ( nParCount < 0 )
318 : {
319 0 : bFound = true;
320 0 : nStart--; // read one too far
321 : }
322 : }
323 0 : else if ( c == arrayOpen )
324 : {
325 0 : bInArray = true;
326 : }
327 0 : else if ( c == arrayClose )
328 : {
329 0 : bInArray = false;
330 : }
331 0 : else if ( c == sep )
332 : {
333 0 : if ( !bInArray && nParCount == 0 )
334 : {
335 0 : bFound = true;
336 0 : nStart--; // read one too far
337 : }
338 : }
339 0 : nStart++; // Set behind found position
340 : }
341 :
342 0 : return nStart;
343 : }
344 :
345 :
346 :
347 0 : sal_Int32 FormulaHelper::GetArgStart( const OUString& rStr, sal_Int32 nStart, sal_uInt16 nArg ) const
348 : {
349 0 : sal_Int32 nStrLen = rStr.getLength();
350 :
351 0 : if ( nStrLen < nStart )
352 0 : return nStart;
353 :
354 0 : short nParCount = 0;
355 0 : bool bInArray = false;
356 0 : bool bFound = false;
357 :
358 0 : while ( !bFound && (nStart < nStrLen) )
359 : {
360 0 : sal_Unicode c = rStr[nStart];
361 :
362 0 : if ( c == '"' )
363 : {
364 0 : nStart++;
365 0 : while ( (nStart < nStrLen) && rStr[nStart] != '"' )
366 0 : nStart++;
367 : }
368 0 : else if ( c == open )
369 : {
370 0 : bFound = ( nArg == 0 );
371 0 : nParCount++;
372 : }
373 0 : else if ( c == close )
374 : {
375 0 : nParCount--;
376 0 : bFound = ( nParCount == 0 );
377 : }
378 0 : else if ( c == arrayOpen )
379 : {
380 0 : bInArray = true;
381 : }
382 0 : else if ( c == arrayClose )
383 : {
384 0 : bInArray = false;
385 : }
386 0 : else if ( c == sep )
387 : {
388 0 : if ( !bInArray && nParCount == 1 )
389 : {
390 0 : nArg--;
391 0 : bFound = ( nArg == 0 );
392 : }
393 : }
394 0 : nStart++;
395 : }
396 :
397 0 : return nStart;
398 : }
399 :
400 : } // formula
401 :
402 :
403 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|