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