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: 38 OEmptyFunctionDescription(){} 39 virtual ~OEmptyFunctionDescription(){} 40 41 virtual ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); } 42 virtual const IFunctionCategory* getCategory() const { return NULL; } 43 virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); } 44 virtual xub_StrLen getSuppressedArgumentCount() const { return 0; } 45 virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); } 46 virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {} 47 virtual void initArgumentInfo() const {} 48 virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); } 49 virtual rtl::OString getHelpId() const { return ""; } 50 virtual sal_uInt32 getParameterCount() const { return 0; } 51 virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); } 52 virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); } 53 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 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 } 73 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 130 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 170 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 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 196 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 290 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 348 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