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