1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23 #include "precompiled_formula.hxx"
24
25 #include "formula/formulahelper.hxx"
26 #include <unotools/charclass.hxx>
27 #include <unotools/syslocale.hxx>
28
29 namespace formula
30 {
31
32 namespace
33 {
34 //============================================================================
35 class OEmptyFunctionDescription : public IFunctionDescription
36 {
37 public:
OEmptyFunctionDescription()38 OEmptyFunctionDescription(){}
~OEmptyFunctionDescription()39 virtual ~OEmptyFunctionDescription(){}
40
getFunctionName() const41 virtual ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); }
getCategory() const42 virtual const IFunctionCategory* getCategory() const { return NULL; }
getDescription() const43 virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); }
getSuppressedArgumentCount() const44 virtual xub_StrLen getSuppressedArgumentCount() const { return 0; }
getFormula(const::std::vector<::rtl::OUString> &) const45 virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); }
fillVisibleArgumentMapping(::std::vector<sal_uInt16> &) const46 virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {}
initArgumentInfo() const47 virtual void initArgumentInfo() const {}
getSignature() const48 virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); }
getHelpId() const49 virtual rtl::OString getHelpId() const { return ""; }
getParameterCount() const50 virtual sal_uInt32 getParameterCount() const { return 0; }
getParameterName(sal_uInt32) const51 virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); }
getParameterDescription(sal_uInt32) const52 virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); }
isParameterOptional(sal_uInt32) const53 virtual bool isParameterOptional(sal_uInt32 ) const { return sal_False; }
54 };
55 }
56 //===================================================================
57 // class FormulaHelper - statische Methoden
58 //===================================================================
59
60 #define FUNC_NOTFOUND 0xffff
61
FormulaHelper(const IFunctionManager * _pFunctionManager)62 FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
63 :m_pSysLocale(new SvtSysLocale)
64 ,m_pFunctionManager(_pFunctionManager)
65 ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
66 ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
67 ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
68 ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
69 ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
70 {
71 m_pCharClass = m_pSysLocale->GetCharClassPtr();
72 }
GetNextFunc(const String & rFormula,sal_Bool bBack,xub_StrLen & rFStart,xub_StrLen * pFEnd,const IFunctionDescription ** ppFDesc,::std::vector<::rtl::OUString> * pArgs) const73 sal_Bool FormulaHelper::GetNextFunc( const String& rFormula,
74 sal_Bool bBack,
75 xub_StrLen& rFStart, // Ein- und Ausgabe
76 xub_StrLen* pFEnd, // = NULL
77 const IFunctionDescription** ppFDesc, // = NULL
78 ::std::vector< ::rtl::OUString>* pArgs ) const // = NULL
79 {
80 sal_Bool bFound = sal_False;
81 xub_StrLen nOldStart = rFStart;
82 String aFname;
83
84 rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL );
85 bFound = ( rFStart != FUNC_NOTFOUND );
86
87 if ( bFound )
88 {
89 if ( pFEnd )
90 *pFEnd = GetFunctionEnd( rFormula, rFStart );
91
92 if ( ppFDesc )
93 {
94 *ppFDesc = NULL;
95 const ::rtl::OUString sTemp( aFname );
96 const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
97 for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
98 {
99 const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
100 const sal_uInt32 nCount = pCategory->getCount();
101 for(sal_uInt32 i = 0 ; i < nCount; ++i)
102 {
103 const IFunctionDescription* pCurrent = pCategory->getFunction(i);
104 if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(sTemp) )
105 {
106 *ppFDesc = pCurrent;
107 break;
108 }
109 } // for(sal_uInt32 i = 0 ; i < nCount; ++i)
110 }
111 if ( *ppFDesc && pArgs )
112 {
113 GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
114 }
115 else
116 {
117 static OEmptyFunctionDescription s_aFunctionDescription;
118 *ppFDesc = &s_aFunctionDescription;
119 }
120 }
121 }
122 else
123 rFStart = nOldStart;
124
125 return bFound;
126 }
127
128 //------------------------------------------------------------------------
129
FillArgStrings(const String & rFormula,xub_StrLen nFuncPos,sal_uInt16 nArgs,::std::vector<::rtl::OUString> & _rArgs) const130 void FormulaHelper::FillArgStrings( const String& rFormula,
131 xub_StrLen nFuncPos,
132 sal_uInt16 nArgs,
133 ::std::vector< ::rtl::OUString >& _rArgs ) const
134 {
135 xub_StrLen nStart = 0;
136 xub_StrLen nEnd = 0;
137 sal_uInt16 i;
138 sal_Bool bLast = sal_False;
139
140 for ( i=0; i<nArgs && !bLast; i++ )
141 {
142 nStart = GetArgStart( rFormula, nFuncPos, i );
143
144 if ( i+1<nArgs ) // letztes Argument?
145 {
146 nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
147
148 if ( nEnd != nStart )
149 _rArgs.push_back(rFormula.Copy( nStart, nEnd-1-nStart ));
150 else
151 _rArgs.push_back(String()), bLast = sal_True;
152 }
153 else
154 {
155 nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
156 if ( nStart < nEnd )
157 _rArgs.push_back( rFormula.Copy( nStart, nEnd-nStart ) );
158 else
159 _rArgs.push_back(String());
160 }
161 }
162
163 if ( bLast )
164 for ( ; i<nArgs; i++ )
165 _rArgs.push_back(String());
166 }
167
168 //------------------------------------------------------------------------
169
GetArgStrings(::std::vector<::rtl::OUString> & _rArgs,const String & rFormula,xub_StrLen nFuncPos,sal_uInt16 nArgs) const170 void FormulaHelper::GetArgStrings( ::std::vector< ::rtl::OUString >& _rArgs
171 ,const String& rFormula,
172 xub_StrLen nFuncPos,
173 sal_uInt16 nArgs ) const
174 {
175 if (nArgs)
176 {
177 FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
178 }
179 }
180
181 //------------------------------------------------------------------------
182
IsFormulaText(const CharClass * _pCharClass,const String & rStr,xub_StrLen nPos)183 inline sal_Bool IsFormulaText( const CharClass* _pCharClass,const String& rStr, xub_StrLen nPos )
184 {
185 if( _pCharClass->isLetterNumeric( rStr, nPos ) )
186 return sal_True;
187 else
188 { // In internationalized versions function names may contain a dot
189 // and in every version also an underscore... ;-)
190 sal_Unicode c = rStr.GetChar(nPos);
191 return c == '.' || c == '_';
192 }
193
194 }
195
GetFunctionStart(const String & rFormula,xub_StrLen nStart,sal_Bool bBack,String * pFuncName) const196 xub_StrLen FormulaHelper::GetFunctionStart( const String& rFormula,
197 xub_StrLen nStart,
198 sal_Bool bBack,
199 String* pFuncName ) const
200 {
201 xub_StrLen nStrLen = rFormula.Len();
202
203 if ( nStrLen < nStart )
204 return nStart;
205
206 xub_StrLen nFStart = FUNC_NOTFOUND;
207 xub_StrLen nParPos = nStart;
208
209 sal_Bool bRepeat, bFound;
210 do
211 {
212 bFound = sal_False;
213 bRepeat = sal_False;
214
215 if ( bBack )
216 {
217 while ( !bFound && (nParPos > 0) )
218 {
219 if ( rFormula.GetChar(nParPos) == '"' )
220 {
221 nParPos--;
222 while ( (nParPos > 0) && rFormula.GetChar(nParPos) != '"' )
223 nParPos--;
224 if (nParPos > 0)
225 nParPos--;
226 }
227 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
228 nParPos--;
229 }
230 }
231 else
232 {
233 while ( !bFound && (nParPos < nStrLen) )
234 {
235 if ( rFormula.GetChar(nParPos) == '"' )
236 {
237 nParPos++;
238 while ( (nParPos < nStrLen) && rFormula.GetChar(nParPos) != '"' )
239 nParPos++;
240 nParPos++;
241 }
242 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
243 nParPos++;
244 }
245 }
246
247 if ( bFound && (nParPos > 0) )
248 {
249 nFStart = nParPos-1;
250
251 while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
252 nFStart--;
253 }
254
255 nFStart++;
256
257 if ( bFound )
258 {
259 if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
260 {
261 // Funktion gefunden
262 if ( pFuncName )
263 *pFuncName = rFormula.Copy( nFStart, nParPos-nFStart );
264 }
265 else // Klammern ohne Funktion -> weitersuchen
266 {
267 bRepeat = sal_True;
268 if ( !bBack )
269 nParPos++;
270 else if (nParPos > 0)
271 nParPos--;
272 else
273 bRepeat = sal_False;
274 }
275 }
276 else // keine Klammern gefunden
277 {
278 nFStart = FUNC_NOTFOUND;
279 if ( pFuncName )
280 pFuncName->Erase();
281 }
282 }
283 while(bRepeat);
284
285 return nFStart;
286 }
287
288 //------------------------------------------------------------------------
289
GetFunctionEnd(const String & rStr,xub_StrLen nStart) const290 xub_StrLen FormulaHelper::GetFunctionEnd( const String& rStr, xub_StrLen nStart ) const
291 {
292 xub_StrLen nStrLen = rStr.Len();
293
294 if ( nStrLen < nStart )
295 return nStart;
296
297 short nParCount = 0;
298 bool bInArray = false;
299 sal_Bool bFound = sal_False;
300
301 while ( !bFound && (nStart < nStrLen) )
302 {
303 sal_Unicode c = rStr.GetChar(nStart);
304
305 if ( c == '"' )
306 {
307 nStart++;
308 while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
309 nStart++;
310 }
311 else if ( c == open )
312 nParCount++;
313 else if ( c == close )
314 {
315 nParCount--;
316 if ( nParCount == 0 )
317 bFound = sal_True;
318 else if ( nParCount < 0 )
319 {
320 bFound = sal_True;
321 nStart--; // einen zu weit gelesen
322 }
323 }
324 else if ( c == arrayOpen )
325 {
326 bInArray = true;
327 }
328 else if ( c == arrayClose )
329 {
330 bInArray = false;
331 }
332 else if ( c == sep )
333 {
334 if ( !bInArray && nParCount == 0 )
335 {
336 bFound = sal_True;
337 nStart--; // einen zu weit gelesen
338 }
339 }
340 nStart++; // hinter gefundene Position stellen
341 }
342
343 return nStart;
344 }
345
346 //------------------------------------------------------------------
347
GetArgStart(const String & rStr,xub_StrLen nStart,sal_uInt16 nArg) const348 xub_StrLen FormulaHelper::GetArgStart( const String& rStr, xub_StrLen nStart, sal_uInt16 nArg ) const
349 {
350 xub_StrLen nStrLen = rStr.Len();
351
352 if ( nStrLen < nStart )
353 return nStart;
354
355 short nParCount = 0;
356 bool bInArray = false;
357 sal_Bool bFound = sal_False;
358
359 while ( !bFound && (nStart < nStrLen) )
360 {
361 sal_Unicode c = rStr.GetChar(nStart);
362
363 if ( c == '"' )
364 {
365 nStart++;
366 while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
367 nStart++;
368 }
369 else if ( c == open )
370 {
371 bFound = ( nArg == 0 );
372 nParCount++;
373 }
374 else if ( c == close )
375 {
376 nParCount--;
377 bFound = ( nParCount == 0 );
378 }
379 else if ( c == arrayOpen )
380 {
381 bInArray = true;
382 }
383 else if ( c == arrayClose )
384 {
385 bInArray = false;
386 }
387 else if ( c == sep )
388 {
389 if ( !bInArray && nParCount == 1 )
390 {
391 nArg--;
392 bFound = ( nArg == 0 );
393 }
394 }
395 nStart++;
396 }
397
398 return nStart;
399 }
400 // =============================================================================
401 } // formula
402 // =============================================================================
403