1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 #include "precompiled_formula.hxx" 28 29 #include "formula/formulahelper.hxx" 30 #include <unotools/charclass.hxx> 31 #include <unotools/syslocale.hxx> 32 33 namespace formula 34 { 35 36 namespace 37 { 38 //============================================================================ 39 class OEmptyFunctionDescription : public IFunctionDescription 40 { 41 public: 42 OEmptyFunctionDescription(){} 43 virtual ~OEmptyFunctionDescription(){} 44 45 virtual ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); } 46 virtual const IFunctionCategory* getCategory() const { return NULL; } 47 virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); } 48 virtual xub_StrLen getSuppressedArgumentCount() const { return 0; } 49 virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); } 50 virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {} 51 virtual void initArgumentInfo() const {} 52 virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); } 53 virtual rtl::OString getHelpId() const { return ""; } 54 virtual sal_uInt32 getParameterCount() const { return 0; } 55 virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); } 56 virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); } 57 virtual bool isParameterOptional(sal_uInt32 ) const { return sal_False; } 58 }; 59 } 60 //=================================================================== 61 // class FormulaHelper - statische Methoden 62 //=================================================================== 63 64 #define FUNC_NOTFOUND 0xffff 65 66 FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager) 67 :m_pSysLocale(new SvtSysLocale) 68 ,m_pFunctionManager(_pFunctionManager) 69 ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk)) 70 ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose)) 71 ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep)) 72 ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen)) 73 ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose)) 74 { 75 m_pCharClass = m_pSysLocale->GetCharClassPtr(); 76 } 77 sal_Bool FormulaHelper::GetNextFunc( const String& rFormula, 78 sal_Bool bBack, 79 xub_StrLen& rFStart, // Ein- und Ausgabe 80 xub_StrLen* pFEnd, // = NULL 81 const IFunctionDescription** ppFDesc, // = NULL 82 ::std::vector< ::rtl::OUString>* pArgs ) const // = NULL 83 { 84 sal_Bool bFound = sal_False; 85 xub_StrLen nOldStart = rFStart; 86 String aFname; 87 88 rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL ); 89 bFound = ( rFStart != FUNC_NOTFOUND ); 90 91 if ( bFound ) 92 { 93 if ( pFEnd ) 94 *pFEnd = GetFunctionEnd( rFormula, rFStart ); 95 96 if ( ppFDesc ) 97 { 98 *ppFDesc = NULL; 99 const ::rtl::OUString sTemp( aFname ); 100 const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount(); 101 for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j) 102 { 103 const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j); 104 const sal_uInt32 nCount = pCategory->getCount(); 105 for(sal_uInt32 i = 0 ; i < nCount; ++i) 106 { 107 const IFunctionDescription* pCurrent = pCategory->getFunction(i); 108 if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(sTemp) ) 109 { 110 *ppFDesc = pCurrent; 111 break; 112 } 113 } // for(sal_uInt32 i = 0 ; i < nCount; ++i) 114 } 115 if ( *ppFDesc && pArgs ) 116 { 117 GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() )); 118 } 119 else 120 { 121 static OEmptyFunctionDescription s_aFunctionDescription; 122 *ppFDesc = &s_aFunctionDescription; 123 } 124 } 125 } 126 else 127 rFStart = nOldStart; 128 129 return bFound; 130 } 131 132 //------------------------------------------------------------------------ 133 134 void FormulaHelper::FillArgStrings( const String& rFormula, 135 xub_StrLen nFuncPos, 136 sal_uInt16 nArgs, 137 ::std::vector< ::rtl::OUString >& _rArgs ) const 138 { 139 xub_StrLen nStart = 0; 140 xub_StrLen nEnd = 0; 141 sal_uInt16 i; 142 sal_Bool bLast = sal_False; 143 144 for ( i=0; i<nArgs && !bLast; i++ ) 145 { 146 nStart = GetArgStart( rFormula, nFuncPos, i ); 147 148 if ( i+1<nArgs ) // letztes Argument? 149 { 150 nEnd = GetArgStart( rFormula, nFuncPos, i+1 ); 151 152 if ( nEnd != nStart ) 153 _rArgs.push_back(rFormula.Copy( nStart, nEnd-1-nStart )); 154 else 155 _rArgs.push_back(String()), bLast = sal_True; 156 } 157 else 158 { 159 nEnd = GetFunctionEnd( rFormula, nFuncPos )-1; 160 if ( nStart < nEnd ) 161 _rArgs.push_back( rFormula.Copy( nStart, nEnd-nStart ) ); 162 else 163 _rArgs.push_back(String()); 164 } 165 } 166 167 if ( bLast ) 168 for ( ; i<nArgs; i++ ) 169 _rArgs.push_back(String()); 170 } 171 172 //------------------------------------------------------------------------ 173 174 void FormulaHelper::GetArgStrings( ::std::vector< ::rtl::OUString >& _rArgs 175 ,const String& rFormula, 176 xub_StrLen nFuncPos, 177 sal_uInt16 nArgs ) const 178 { 179 if (nArgs) 180 { 181 FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs ); 182 } 183 } 184 185 //------------------------------------------------------------------------ 186 187 inline sal_Bool IsFormulaText( const CharClass* _pCharClass,const String& rStr, xub_StrLen nPos ) 188 { 189 if( _pCharClass->isLetterNumeric( rStr, nPos ) ) 190 return sal_True; 191 else 192 { // In internationalized versions function names may contain a dot 193 // and in every version also an underscore... ;-) 194 sal_Unicode c = rStr.GetChar(nPos); 195 return c == '.' || c == '_'; 196 } 197 198 } 199 200 xub_StrLen FormulaHelper::GetFunctionStart( const String& rFormula, 201 xub_StrLen nStart, 202 sal_Bool bBack, 203 String* pFuncName ) const 204 { 205 xub_StrLen nStrLen = rFormula.Len(); 206 207 if ( nStrLen < nStart ) 208 return nStart; 209 210 xub_StrLen nFStart = FUNC_NOTFOUND; 211 xub_StrLen nParPos = nStart; 212 213 sal_Bool bRepeat, bFound; 214 do 215 { 216 bFound = sal_False; 217 bRepeat = sal_False; 218 219 if ( bBack ) 220 { 221 while ( !bFound && (nParPos > 0) ) 222 { 223 if ( rFormula.GetChar(nParPos) == '"' ) 224 { 225 nParPos--; 226 while ( (nParPos > 0) && rFormula.GetChar(nParPos) != '"' ) 227 nParPos--; 228 if (nParPos > 0) 229 nParPos--; 230 } 231 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False ) 232 nParPos--; 233 } 234 } 235 else 236 { 237 while ( !bFound && (nParPos < nStrLen) ) 238 { 239 if ( rFormula.GetChar(nParPos) == '"' ) 240 { 241 nParPos++; 242 while ( (nParPos < nStrLen) && rFormula.GetChar(nParPos) != '"' ) 243 nParPos++; 244 nParPos++; 245 } 246 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False ) 247 nParPos++; 248 } 249 } 250 251 if ( bFound && (nParPos > 0) ) 252 { 253 nFStart = nParPos-1; 254 255 while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart )) 256 nFStart--; 257 } 258 259 nFStart++; 260 261 if ( bFound ) 262 { 263 if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) ) 264 { 265 // Funktion gefunden 266 if ( pFuncName ) 267 *pFuncName = rFormula.Copy( nFStart, nParPos-nFStart ); 268 } 269 else // Klammern ohne Funktion -> weitersuchen 270 { 271 bRepeat = sal_True; 272 if ( !bBack ) 273 nParPos++; 274 else if (nParPos > 0) 275 nParPos--; 276 else 277 bRepeat = sal_False; 278 } 279 } 280 else // keine Klammern gefunden 281 { 282 nFStart = FUNC_NOTFOUND; 283 if ( pFuncName ) 284 pFuncName->Erase(); 285 } 286 } 287 while(bRepeat); 288 289 return nFStart; 290 } 291 292 //------------------------------------------------------------------------ 293 294 xub_StrLen FormulaHelper::GetFunctionEnd( const String& rStr, xub_StrLen nStart ) const 295 { 296 xub_StrLen nStrLen = rStr.Len(); 297 298 if ( nStrLen < nStart ) 299 return nStart; 300 301 short nParCount = 0; 302 bool bInArray = false; 303 sal_Bool bFound = sal_False; 304 305 while ( !bFound && (nStart < nStrLen) ) 306 { 307 sal_Unicode c = rStr.GetChar(nStart); 308 309 if ( c == '"' ) 310 { 311 nStart++; 312 while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' ) 313 nStart++; 314 } 315 else if ( c == open ) 316 nParCount++; 317 else if ( c == close ) 318 { 319 nParCount--; 320 if ( nParCount == 0 ) 321 bFound = sal_True; 322 else if ( nParCount < 0 ) 323 { 324 bFound = sal_True; 325 nStart--; // einen zu weit gelesen 326 } 327 } 328 else if ( c == arrayOpen ) 329 { 330 bInArray = true; 331 } 332 else if ( c == arrayClose ) 333 { 334 bInArray = false; 335 } 336 else if ( c == sep ) 337 { 338 if ( !bInArray && nParCount == 0 ) 339 { 340 bFound = sal_True; 341 nStart--; // einen zu weit gelesen 342 } 343 } 344 nStart++; // hinter gefundene Position stellen 345 } 346 347 return nStart; 348 } 349 350 //------------------------------------------------------------------ 351 352 xub_StrLen FormulaHelper::GetArgStart( const String& rStr, xub_StrLen nStart, sal_uInt16 nArg ) const 353 { 354 xub_StrLen nStrLen = rStr.Len(); 355 356 if ( nStrLen < nStart ) 357 return nStart; 358 359 short nParCount = 0; 360 bool bInArray = false; 361 sal_Bool bFound = sal_False; 362 363 while ( !bFound && (nStart < nStrLen) ) 364 { 365 sal_Unicode c = rStr.GetChar(nStart); 366 367 if ( c == '"' ) 368 { 369 nStart++; 370 while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' ) 371 nStart++; 372 } 373 else if ( c == open ) 374 { 375 bFound = ( nArg == 0 ); 376 nParCount++; 377 } 378 else if ( c == close ) 379 { 380 nParCount--; 381 bFound = ( nParCount == 0 ); 382 } 383 else if ( c == arrayOpen ) 384 { 385 bInArray = true; 386 } 387 else if ( c == arrayClose ) 388 { 389 bInArray = false; 390 } 391 else if ( c == sep ) 392 { 393 if ( !bInArray && nParCount == 1 ) 394 { 395 nArg--; 396 bFound = ( nArg == 0 ); 397 } 398 } 399 nStart++; 400 } 401 402 return nStart; 403 } 404 // ============================================================================= 405 } // formula 406 // ============================================================================= 407