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