Branch data 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 ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); }
37 : 0 : virtual const IFunctionCategory* getCategory() const { return NULL; }
38 : 0 : virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); }
39 : 0 : virtual xub_StrLen getSuppressedArgumentCount() const { return 0; }
40 : 0 : virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); }
41 : 0 : virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {}
42 : 0 : virtual void initArgumentInfo() const {}
43 : 0 : virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); }
44 : 0 : virtual rtl::OString getHelpId() const { return ""; }
45 : 0 : virtual sal_uInt32 getParameterCount() const { return 0; }
46 : 0 : virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); }
47 : 0 : virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); }
48 : 0 : virtual bool isParameterOptional(sal_uInt32 ) const { return sal_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 : 0 : sal_Bool FormulaHelper::GetNextFunc( const String& rFormula,
69 : : sal_Bool bBack,
70 : : xub_StrLen& rFStart, // Input and output
71 : : xub_StrLen* pFEnd, // = NULL
72 : : const IFunctionDescription** ppFDesc, // = NULL
73 : : ::std::vector< ::rtl::OUString>* pArgs ) const // = NULL
74 : : {
75 : 0 : sal_Bool bFound = sal_False;
76 : 0 : xub_StrLen nOldStart = rFStart;
77 [ # # ]: 0 : String aFname;
78 : :
79 [ # # ][ # # ]: 0 : rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL );
80 : 0 : 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 ::rtl::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 String& rFormula,
126 : : xub_StrLen nFuncPos,
127 : : sal_uInt16 nArgs,
128 : : ::std::vector< ::rtl::OUString >& _rArgs ) const
129 : : {
130 : 0 : xub_StrLen nStart = 0;
131 : 0 : xub_StrLen 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(String()), 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(String());
155 : : }
156 : : }
157 : :
158 [ # # ]: 0 : if ( bLast )
159 [ # # ]: 0 : for ( ; i<nArgs; i++ )
160 [ # # ][ # # ]: 0 : _rArgs.push_back(String());
161 : 0 : }
162 : :
163 : : //------------------------------------------------------------------------
164 : :
165 : 0 : void FormulaHelper::GetArgStrings( ::std::vector< ::rtl::OUString >& _rArgs
166 : : ,const String& rFormula,
167 : : xub_StrLen 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 String& rStr, xub_StrLen 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.GetChar(nPos);
186 [ # # ][ # # ]: 0 : return c == '.' || c == '_';
187 : : }
188 : :
189 : : }
190 : :
191 : 0 : xub_StrLen FormulaHelper::GetFunctionStart( const String& rFormula,
192 : : xub_StrLen nStart,
193 : : sal_Bool bBack,
194 : : String* pFuncName ) const
195 : : {
196 : 0 : xub_StrLen nStrLen = rFormula.Len();
197 : :
198 [ # # ]: 0 : if ( nStrLen < nStart )
199 : 0 : return nStart;
200 : :
201 : 0 : xub_StrLen nFStart = FUNC_NOTFOUND;
202 : 0 : xub_StrLen 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.GetChar(nParPos) == '"' )
215 : : {
216 : 0 : nParPos--;
217 [ # # ][ # # ]: 0 : while ( (nParPos > 0) && rFormula.GetChar(nParPos) != '"' )
[ # # ]
218 : 0 : nParPos--;
219 [ # # ]: 0 : if (nParPos > 0)
220 : 0 : nParPos--;
221 : : }
222 [ # # ]: 0 : else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
223 : 0 : nParPos--;
224 : : }
225 : : }
226 : : else
227 : : {
228 [ # # ][ # # ]: 0 : while ( !bFound && (nParPos < nStrLen) )
[ # # ]
229 : : {
230 [ # # ]: 0 : if ( rFormula.GetChar(nParPos) == '"' )
231 : : {
232 : 0 : nParPos++;
233 [ # # ][ # # ]: 0 : while ( (nParPos < nStrLen) && rFormula.GetChar(nParPos) != '"' )
[ # # ]
234 : 0 : nParPos++;
235 : 0 : nParPos++;
236 : : }
237 [ # # ]: 0 : else if ( (bFound = ( rFormula.GetChar(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->Erase();
276 : : }
277 : : }
278 : : while(bRepeat);
279 : :
280 : 0 : return nFStart;
281 : : }
282 : :
283 : : //------------------------------------------------------------------------
284 : :
285 : 0 : xub_StrLen FormulaHelper::GetFunctionEnd( const String& rStr, xub_StrLen nStart ) const
286 : : {
287 : 0 : xub_StrLen nStrLen = rStr.Len();
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.GetChar(nStart);
299 : :
300 [ # # ]: 0 : if ( c == '"' )
301 : : {
302 : 0 : nStart++;
303 [ # # ][ # # ]: 0 : while ( (nStart < nStrLen) && rStr.GetChar(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 : xub_StrLen FormulaHelper::GetArgStart( const String& rStr, xub_StrLen nStart, sal_uInt16 nArg ) const
344 : : {
345 : 0 : xub_StrLen nStrLen = rStr.Len();
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.GetChar(nStart);
357 : :
358 [ # # ]: 0 : if ( c == '"' )
359 : : {
360 : 0 : nStart++;
361 [ # # ][ # # ]: 0 : while ( (nStart < nStrLen) && rStr.GetChar(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: */
|