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 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 // INCLUDE --------------------------------------------------------------- 32 33 #include <sfx2/app.hxx> 34 #include <sfx2/objsh.hxx> 35 #include <basic/sbmeth.hxx> 36 #include <basic/sbstar.hxx> 37 #include <svl/zforlist.hxx> 38 #include <tools/rcid.h> 39 #include <tools/rc.hxx> 40 #include <tools/solar.h> 41 #include <unotools/charclass.hxx> 42 #include <com/sun/star/lang/Locale.hpp> 43 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp> 44 #include <com/sun/star/sheet/FormulaLanguage.hpp> 45 #include <com/sun/star/sheet/FormulaMapGroup.hpp> 46 #include <comphelper/processfactory.hxx> 47 #include <unotools/transliterationwrapper.hxx> 48 #include <tools/urlobj.hxx> 49 #include <rtl/math.hxx> 50 #include <ctype.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <math.h> 55 #include "compiler.hxx" 56 #include "rangenam.hxx" 57 #include "dbcolect.hxx" 58 #include "document.hxx" 59 #include "callform.hxx" 60 #include "addincol.hxx" 61 #include "refupdat.hxx" 62 #include "scresid.hxx" 63 #include "sc.hrc" 64 #include "globstr.hrc" 65 #include "cell.hxx" 66 #include "dociter.hxx" 67 #include "docoptio.hxx" 68 #include <formula/errorcodes.hxx> 69 #include "parclass.hxx" 70 #include "autonamecache.hxx" 71 #include "externalrefmgr.hxx" 72 #include "rangeutl.hxx" 73 #include "convuno.hxx" 74 #include "tokenuno.hxx" 75 #include "formulaparserpool.hxx" 76 77 using namespace formula; 78 using namespace ::com::sun::star; 79 using rtl::OUString; 80 using ::std::vector; 81 82 #if OSL_DEBUG_LEVEL > 1 83 // For some unknown reason the identical dbg_dump utilities in 84 // tools/source/string/debugprint.cxx tend to crash when called from within 85 // gdb. Having them here also comes handy as libtl*.so doesn't have to be 86 // replaced. 87 const char* dbg_sc_dump( const ByteString & rStr ) 88 { 89 static ByteString aStr; 90 aStr = rStr; 91 aStr.Append(static_cast<char>(0)); 92 return aStr.GetBuffer(); 93 } 94 const char* dbg_sc_dump( const UniString & rStr ) 95 { 96 return dbg_sc_dump(ByteString(rStr, RTL_TEXTENCODING_UTF8)); 97 } 98 const char* dbg_sc_dump( const sal_Unicode * pBuf ) 99 { 100 return dbg_sc_dump( UniString( pBuf)); 101 } 102 const char* dbg_sc_dump( const sal_Unicode c ) 103 { 104 return dbg_sc_dump( UniString( c)); 105 } 106 #endif 107 108 CharClass* ScCompiler::pCharClassEnglish = NULL; 109 const ScCompiler::Convention* ScCompiler::pConventions[ ] = { NULL, NULL, NULL, NULL, NULL, NULL }; 110 111 enum ScanState 112 { 113 ssGetChar, 114 ssGetBool, 115 ssGetValue, 116 ssGetString, 117 ssSkipString, 118 ssGetIdent, 119 ssGetReference, 120 ssSkipReference, 121 ssStop 122 }; 123 124 static const sal_Char* pInternal[ 1 ] = { "TTT" }; 125 126 using namespace ::com::sun::star::i18n; 127 128 ///////////////////////////////////////////////////////////////////////// 129 130 131 132 class ScCompilerRecursionGuard 133 { 134 private: 135 short& rRecursion; 136 public: 137 ScCompilerRecursionGuard( short& rRec ) 138 : rRecursion( rRec ) { ++rRecursion; } 139 ~ScCompilerRecursionGuard() { --rRecursion; } 140 }; 141 142 143 void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap,FormulaGrammar::Grammar _eGrammar ) const 144 { 145 size_t nSymbolOffset; 146 switch( _eGrammar ) 147 { 148 case FormulaGrammar::GRAM_PODF: 149 nSymbolOffset = offsetof( AddInMap, pUpper); 150 break; 151 default: 152 case FormulaGrammar::GRAM_ODFF: 153 nSymbolOffset = offsetof( AddInMap, pODFF); 154 break; 155 case FormulaGrammar::GRAM_ENGLISH: 156 nSymbolOffset = offsetof( AddInMap, pEnglish); 157 break; 158 } 159 const AddInMap* pMap = GetAddInMap(); 160 const AddInMap* const pStop = pMap + GetAddInMapCount(); 161 for ( ; pMap < pStop; ++pMap) 162 { 163 char const * const * ppSymbol = 164 reinterpret_cast< char const * const * >( 165 reinterpret_cast< char const * >(pMap) + nSymbolOffset); 166 xMap->putExternal( String::CreateFromAscii( *ppSymbol), 167 String::CreateFromAscii( pMap->pOriginal)); 168 } 169 } 170 171 void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const 172 { 173 ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection(); 174 long nCount = pColl->GetFuncCount(); 175 for (long i=0; i < nCount; ++i) 176 { 177 const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i); 178 if (pFuncData) 179 xMap->putExternalSoftly( pFuncData->GetUpperName(), 180 pFuncData->GetOriginalName()); 181 } 182 } 183 184 void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const 185 { 186 ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection(); 187 long nCount = pColl->GetFuncCount(); 188 for (long i=0; i < nCount; ++i) 189 { 190 const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i); 191 if (pFuncData) 192 { 193 String aName; 194 if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName)) 195 xMap->putExternalSoftly( aName, pFuncData->GetOriginalName()); 196 else 197 xMap->putExternalSoftly( pFuncData->GetUpperName(), 198 pFuncData->GetOriginalName()); 199 } 200 } 201 } 202 203 204 #ifdef erGENERATEMAPPING 205 // Run in en-US UI by calling from within gdb, edit pODFF entries afterwards. 206 void dbg_call_generateMappingODFF() 207 { 208 // static ScCompiler members 209 fprintf( stdout, "%s", "static struct AddInMap\n{\n const char* pODFF;\n const char* pEnglish;\n bool bMapDupToInternal;\n const char* pOriginal;\n const char* pUpper;\n} maAddInMap[];\n"); 210 fprintf( stdout, "%s", "static const AddInMap* GetAddInMap();\n"); 211 fprintf( stdout, "%s", "static size_t GetAddInMapCount();\n"); 212 fprintf( stdout, "addinfuncdata___:%s", "ScCompiler::AddInMap ScCompiler::maAddInMap[] =\n{\n"); 213 ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection(); 214 long nCount = pColl->GetFuncCount(); 215 for (long i=0; i < nCount; ++i) 216 { 217 const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i); 218 if (pFuncData) 219 { 220 #define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer()) 221 String aL = pFuncData->GetUpperLocal(); 222 String aP = pFuncData->GetOriginalName(); 223 String aU = pFuncData->GetUpperName(); 224 fprintf( stdout, "addinfuncdata%3ld: { \"%s\", \"%s\", false, \"%s\", \"%s\" },\n", 225 i, out(aL), out(aL), out(aP), out(aU)); 226 #undef out 227 } 228 } 229 fprintf( stdout, "addinfuncdata___:%s", "};\n"); 230 fprintf( stdout, "%s", "\n// static\nconst ScCompiler::AddInMap* ScCompiler::GetAddInMap()\n{\n return maAddInMap;\n}\n"); 231 fprintf( stdout, "%s", "\n// static\nsize_t ScCompiler::GetAddInMapCount()\n{\n return sizeof(maAddInMap)/sizeof(maAddInMap[0]);\n}\n"); 232 fflush( stdout); 233 } 234 #endif // erGENERATEMAPPING 235 236 #ifdef erGENERATEMAPPINGDIFF 237 // Run in en-US UI by calling from within gdb. 238 void dbg_call_generateMappingDiff() 239 { 240 using namespace ::com::sun::star::sheet; 241 ScCompiler::OpCodeMapPtr xPODF = ScCompiler::GetOpCodeMap( 242 FormulaLanguage::ODF_11); 243 ScCompiler::OpCodeMapPtr xODFF = ScCompiler::GetOpCodeMap( 244 FormulaLanguage::ODFF); 245 ScCompiler::OpCodeMapPtr xENUS = ScCompiler::GetOpCodeMap( 246 FormulaLanguage::ENGLISH); 247 sal_uInt16 nPODF = xPODF->getSymbolCount(); 248 sal_uInt16 nODFF = xODFF->getSymbolCount(); 249 sal_uInt16 nENUS = xENUS->getSymbolCount(); 250 printf( "%s\n", "This is a semicolon separated file, you may import it as such to Calc."); 251 printf( "%s\n", "Spreadsheet functions name differences between PODF (ODF < 1.2) and ODFF (ODF >= 1.2), plus English UI names."); 252 printf( "\nInternal OpCodes; PODF: %d; ODFF: %d; ENUS: %d\n", 253 (int)nPODF, (int)nODFF, (int)nENUS); 254 sal_uInt16 nMax = ::std::max( ::std::max( nPODF, nODFF), nENUS); 255 #define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer()) 256 for (sal_uInt16 i=0; i < nMax; ++i) 257 { 258 const String& rPODF = xPODF->getSymbol(static_cast<OpCode>(i)); 259 const String& rODFF = xODFF->getSymbol(static_cast<OpCode>(i)); 260 const String& rENUS = xENUS->getSymbol(static_cast<OpCode>(i)); 261 if (rPODF != rODFF) 262 printf( "%d;%s;%s;%s\n", (int)i, out(rPODF), out(rODFF), out(rENUS)); 263 } 264 // Actually they should all differ, so we could simply list them all, but 265 // this is correct and we would find odd things, if any. 266 const ExternalHashMap* pPODF = xPODF->getReverseExternalHashMap(); 267 const ExternalHashMap* pODFF = xODFF->getReverseExternalHashMap(); 268 const ExternalHashMap* pENUS = xENUS->getReverseExternalHashMap(); 269 printf( "\n%s\n", "Add-In mapping"); 270 for (ExternalHashMap::const_iterator it = pPODF->begin(); it != pPODF->end(); ++it) 271 { 272 ExternalHashMap::const_iterator iLookODFF = pODFF->find( (*it).first); 273 ExternalHashMap::const_iterator iLookENUS = pENUS->find( (*it).first); 274 String aNative( iLookENUS == pENUS->end() ? 275 String::CreateFromAscii( "ENGLISH_SYMBOL_NOT_FOUND") : 276 (*iLookENUS).second); 277 if (iLookODFF == pODFF->end()) 278 printf( "NOT FOUND;%s;;%s\n", out((*it).first), out(aNative)); 279 else if((*it).second == (*iLookODFF).second) // upper equal 280 printf( "EQUAL;%s;%s;%s\n", out((*it).first), out((*iLookODFF).second), out(aNative)); 281 else 282 printf( ";%s;%s;%s\n", out((*it).first), out((*iLookODFF).second), out(aNative)); 283 } 284 #undef out 285 fflush( stdout); 286 } 287 #endif // erGENERATEMAPPINGDIFF 288 289 // static 290 void ScCompiler::DeInit() 291 { 292 if (pCharClassEnglish) 293 { 294 delete pCharClassEnglish; 295 pCharClassEnglish = NULL; 296 } 297 } 298 299 bool ScCompiler::IsEnglishSymbol( const String& rName ) 300 { 301 // function names are always case-insensitive 302 String aUpper( ScGlobal::pCharClass->upper( rName ) ); 303 304 // 1. built-in function name 305 OpCode eOp = ScCompiler::GetEnglishOpCode( aUpper ); 306 if ( eOp != ocNone ) 307 { 308 return true; 309 } 310 // 2. old add in functions 311 sal_uInt16 nIndex; 312 if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) ) 313 { 314 return true; 315 } 316 317 // 3. new (uno) add in functions 318 String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, sal_False )); 319 if (aIntName.Len()) 320 { 321 return true; 322 } 323 return false; // no valid function name 324 } 325 326 // static 327 void ScCompiler::InitCharClassEnglish() 328 { 329 ::com::sun::star::lang::Locale aLocale( 330 OUString( RTL_CONSTASCII_USTRINGPARAM( "en")), 331 OUString( RTL_CONSTASCII_USTRINGPARAM( "US")), 332 OUString()); 333 pCharClassEnglish = new CharClass( 334 ::comphelper::getProcessServiceFactory(), aLocale); 335 } 336 337 338 void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar ) 339 { 340 DBG_ASSERT( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED"); 341 if (eGrammar == GetGrammar()) 342 return; // nothing to be done 343 344 if( eGrammar == FormulaGrammar::GRAM_EXTERNAL ) 345 { 346 meGrammar = eGrammar; 347 mxSymbols = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE); 348 } 349 else 350 { 351 FormulaGrammar::Grammar eMyGrammar = eGrammar; 352 const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar); 353 OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage); 354 DBG_ASSERT( xMap, "ScCompiler::SetGrammar: unknown formula language"); 355 if (!xMap) 356 { 357 xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE); 358 eMyGrammar = xMap->getGrammar(); 359 } 360 361 // Save old grammar for call to SetGrammarAndRefConvention(). 362 FormulaGrammar::Grammar eOldGrammar = GetGrammar(); 363 // This also sets the grammar associated with the map! 364 SetFormulaLanguage( xMap); 365 366 // Override if necessary. 367 if (eMyGrammar != GetGrammar()) 368 SetGrammarAndRefConvention( eMyGrammar, eOldGrammar); 369 } 370 } 371 372 void ScCompiler::SetEncodeUrlMode( EncodeUrlMode eMode ) 373 { 374 meEncodeUrlMode = eMode; 375 } 376 377 ScCompiler::EncodeUrlMode ScCompiler::GetEncodeUrlMode() const 378 { 379 return meEncodeUrlMode; 380 } 381 382 void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap ) 383 { 384 if (xMap.get()) 385 { 386 mxSymbols = xMap; 387 if (mxSymbols->isEnglish()) 388 { 389 if (!pCharClassEnglish) 390 InitCharClassEnglish(); 391 pCharClass = pCharClassEnglish; 392 } 393 else 394 pCharClass = ScGlobal::pCharClass; 395 SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar()); 396 } 397 } 398 399 400 void ScCompiler::SetGrammarAndRefConvention( 401 const FormulaGrammar::Grammar eNewGrammar, const FormulaGrammar::Grammar eOldGrammar ) 402 { 403 meGrammar = eNewGrammar; //! SetRefConvention needs the new grammar set! 404 FormulaGrammar::AddressConvention eConv = FormulaGrammar::extractRefConvention( meGrammar); 405 if (eConv == FormulaGrammar::CONV_UNSPECIFIED && eOldGrammar == FormulaGrammar::GRAM_UNSPECIFIED) 406 { 407 if (pDoc) 408 SetRefConvention( pDoc->GetAddressConvention()); 409 else 410 SetRefConvention( pConvOOO_A1); 411 } 412 else 413 SetRefConvention( eConv ); 414 } 415 416 String ScCompiler::FindAddInFunction( const String& rUpperName, sal_Bool bLocalFirst ) const 417 { 418 return ScGlobal::GetAddInCollection()->FindFunction(rUpperName, bLocalFirst); // bLocalFirst=sal_False for english 419 } 420 421 422 #ifdef erDEBUG 423 void dbg_call_testcreatemapping() 424 { 425 using namespace ::com::sun::star::sheet; 426 ScCompiler::OpCodeMapPtr xMap = ScCompiler::GetOpCodeMap( FormulaLanguage::ODFF); 427 xMap->createSequenceOfAvailableMappings( FormulaMapGroup::FUNCTIONS); 428 } 429 #endif 430 431 //----------------------------------------------------------------------------- 432 433 ScCompiler::Convention::~Convention() 434 { 435 delete [] mpCharTable; 436 mpCharTable = NULL; 437 } 438 439 ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv ) 440 : 441 meConv( eConv ) 442 { 443 int i; 444 sal_uLong *t= new sal_uLong [128]; 445 446 ScCompiler::pConventions[ meConv ] = this; 447 mpCharTable = t; 448 449 for (i = 0; i < 128; i++) 450 t[i] = SC_COMPILER_C_ILLEGAL; 451 452 /* */ t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 453 /* ! */ t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 454 if (FormulaGrammar::CONV_ODF == meConv) 455 /* ! */ t[33] |= SC_COMPILER_C_ODF_LABEL_OP; 456 /* " */ t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP; 457 /* # */ t[35] = SC_COMPILER_C_WORD_SEP; 458 /* $ */ t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; 459 if (FormulaGrammar::CONV_ODF == meConv) 460 /* $ */ t[36] |= SC_COMPILER_C_ODF_NAME_MARKER; 461 /* % */ t[37] = SC_COMPILER_C_VALUE; 462 /* & */ t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 463 /* ' */ t[39] = SC_COMPILER_C_NAME_SEP; 464 /* ( */ t[40] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 465 /* ) */ t[41] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 466 /* * */ t[42] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 467 /* + */ t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN; 468 /* , */ t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE; 469 /* - */ t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN; 470 /* . */ t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME; 471 /* / */ t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 472 473 for (i = 48; i < 58; i++) 474 /* 0-9 */ t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME; 475 476 /* : */ t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD; 477 /* ; */ t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 478 /* < */ t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 479 /* = */ t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 480 /* > */ t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 481 /* ? */ t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME; 482 /* @ */ // FREE 483 484 for (i = 65; i < 91; i++) 485 /* A-Z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME; 486 487 if (FormulaGrammar::CONV_ODF == meConv) 488 { 489 /* [ */ t[91] = SC_COMPILER_C_ODF_LBRACKET; 490 /* \ */ // FREE 491 /* ] */ t[93] = SC_COMPILER_C_ODF_RBRACKET; 492 } 493 else 494 { 495 /* [ */ // FREE 496 /* \ */ // FREE 497 /* ] */ // FREE 498 } 499 /* ^ */ t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 500 /* _ */ t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME; 501 /* ` */ // FREE 502 503 for (i = 97; i < 123; i++) 504 /* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME; 505 506 /* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open 507 /* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific) 508 /* } */ t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close 509 /* ~ */ t[126] = SC_COMPILER_C_CHAR; // OOo specific 510 /* 127 */ // FREE 511 512 if( FormulaGrammar::CONV_XL_A1 == meConv || FormulaGrammar::CONV_XL_R1C1 == meConv || FormulaGrammar::CONV_XL_OOX == meConv ) 513 { 514 /* */ t[32] |= SC_COMPILER_C_WORD; 515 /* ! */ t[33] |= SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD; 516 /* " */ t[34] |= SC_COMPILER_C_WORD; 517 /* # */ t[35] &= (~SC_COMPILER_C_WORD_SEP); 518 /* # */ t[35] |= SC_COMPILER_C_WORD; 519 /* % */ t[37] |= SC_COMPILER_C_WORD; 520 /* ' */ t[39] |= SC_COMPILER_C_WORD; 521 522 /* % */ t[37] |= SC_COMPILER_C_WORD; 523 /* & */ t[38] |= SC_COMPILER_C_WORD; 524 /* ' */ t[39] |= SC_COMPILER_C_WORD; 525 /* ( */ t[40] |= SC_COMPILER_C_WORD; 526 /* ) */ t[41] |= SC_COMPILER_C_WORD; 527 /* * */ t[42] |= SC_COMPILER_C_WORD; 528 /* + */ t[43] |= SC_COMPILER_C_WORD; 529 #if 0 /* this really needs to be locale specific. */ 530 /* , */ t[44] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; 531 #else 532 /* , */ t[44] |= SC_COMPILER_C_WORD; 533 #endif 534 /* - */ t[45] |= SC_COMPILER_C_WORD; 535 536 /* ; */ t[59] |= SC_COMPILER_C_WORD; 537 /* < */ t[60] |= SC_COMPILER_C_WORD; 538 /* = */ t[61] |= SC_COMPILER_C_WORD; 539 /* > */ t[62] |= SC_COMPILER_C_WORD; 540 /* ? */ // question really is not permitted in sheet name 541 /* @ */ t[64] |= SC_COMPILER_C_WORD; 542 /* [ */ t[91] |= SC_COMPILER_C_WORD; 543 /* ] */ t[93] |= SC_COMPILER_C_WORD; 544 /* { */ t[123]|= SC_COMPILER_C_WORD; 545 /* | */ t[124]|= SC_COMPILER_C_WORD; 546 /* } */ t[125]|= SC_COMPILER_C_WORD; 547 /* ~ */ t[126]|= SC_COMPILER_C_WORD; 548 549 if( FormulaGrammar::CONV_XL_R1C1 == meConv ) 550 { 551 /* - */ t[45] |= SC_COMPILER_C_IDENT; 552 /* [ */ t[91] |= SC_COMPILER_C_IDENT; 553 /* ] */ t[93] |= SC_COMPILER_C_IDENT; 554 } 555 if( FormulaGrammar::CONV_XL_OOX == meConv ) 556 { 557 /* [ */ t[91] |= SC_COMPILER_C_CHAR_IDENT; 558 /* ] */ t[93] |= SC_COMPILER_C_IDENT; 559 } 560 } 561 } 562 563 //----------------------------------------------------------------------------- 564 565 static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, ParseResult& rRes ) 566 { 567 // Tokens that start at ' can have anything in them until a final ' 568 // but '' marks an escaped ' 569 // We've earlier guaranteed that a string containing '' will be 570 // surrounded by ' 571 if (rFormula.GetChar(nSrcPos) == '\'') 572 { 573 xub_StrLen nPos = nSrcPos+1; 574 while (nPos < rFormula.Len()) 575 { 576 if (rFormula.GetChar(nPos) == '\'') 577 { 578 if ( (nPos+1 == rFormula.Len()) || (rFormula.GetChar(nPos+1) != '\'') ) 579 { 580 rRes.TokenType = KParseType::SINGLE_QUOTE_NAME; 581 rRes.EndPos = nPos+1; 582 return true; 583 } 584 ++nPos; 585 } 586 ++nPos; 587 } 588 } 589 590 return false; 591 } 592 593 static bool lcl_parseExternalName( 594 const String& rSymbol, 595 String& rFile, 596 String& rName, 597 const sal_Unicode cSep, 598 const ScDocument* pDoc = NULL, 599 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL ) 600 { 601 /* TODO: future versions will have to support sheet-local names too, thus 602 * return a possible sheet name as well. */ 603 const sal_Unicode* const pStart = rSymbol.GetBuffer(); 604 const sal_Unicode* p = pStart; 605 xub_StrLen nLen = rSymbol.Len(); 606 sal_Unicode cPrev = 0; 607 String aTmpFile, aTmpName; 608 xub_StrLen i = 0; 609 bool bInName = false; 610 if (cSep == '!') 611 { 612 // For XL use existing parser that resolves bracketed and quoted and 613 // indexed external document names. 614 ScRange aRange; 615 String aStartTabName, aEndTabName; 616 sal_uInt16 nFlags = 0; 617 p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName, 618 aEndTabName, nFlags, true, pExternalLinks ); 619 if (!p || p == pStart) 620 return false; 621 i = xub_StrLen(p - pStart); 622 cPrev = *(p-1); 623 } 624 for ( ; i < nLen; ++i, ++p) 625 { 626 sal_Unicode c = *p; 627 if (i == 0) 628 { 629 if (c == '.' || c == cSep) 630 return false; 631 632 if (c == '\'') 633 { 634 // Move to the next chart and loop until the second single 635 // quote. 636 cPrev = c; 637 ++i; ++p; 638 for (xub_StrLen j = i; j < nLen; ++j, ++p) 639 { 640 c = *p; 641 if (c == '\'') 642 { 643 if (j == i) 644 { 645 // empty quote e.g. (=''!Name) 646 return false; 647 } 648 649 if (cPrev == '\'') 650 { 651 // two consecutive quotes equals a single 652 // quote in the file name. 653 aTmpFile.Append(c); 654 cPrev = 'a'; 655 } 656 else 657 cPrev = c; 658 659 continue; 660 } 661 662 if (cPrev == '\'' && j != i) 663 { 664 // this is not a quote but the previous one 665 // is. This ends the parsing of the quoted 666 // segment. 667 668 i = j; 669 bInName = true; 670 break; 671 } 672 aTmpFile.Append(c); 673 cPrev = c; 674 } 675 676 if (!bInName) 677 { 678 // premature ending of the quoted segment. 679 return false; 680 } 681 682 if (c != cSep) 683 { 684 // only the separator is allowed after the closing quote. 685 return false; 686 } 687 688 cPrev = c; 689 continue; 690 } 691 } 692 693 if (bInName) 694 { 695 if (c == cSep) 696 { 697 // A second separator ? Not a valid external name. 698 return false; 699 } 700 aTmpName.Append(c); 701 } 702 else 703 { 704 if (c == cSep) 705 { 706 bInName = true; 707 } 708 else 709 { 710 do 711 { 712 if (CharClass::isAsciiAlphaNumeric(c)) 713 // allowed. 714 break; 715 716 if (c > 128) 717 // non-ASCII character is allowed. 718 break; 719 720 bool bValid = false; 721 switch (c) 722 { 723 case '_': 724 case '-': 725 case '.': 726 // these special characters are allowed. 727 bValid = true; 728 break; 729 } 730 if (bValid) 731 break; 732 733 return false; 734 } 735 while (false); 736 aTmpFile.Append(c); 737 } 738 } 739 cPrev = c; 740 } 741 742 if (!bInName) 743 { 744 // No name found - most likely the symbol has no '!'s. 745 return false; 746 } 747 748 rFile = aTmpFile; 749 rName = aTmpName; 750 return true; 751 } 752 753 static String lcl_makeExternalNameStr( const String& rFile, const String& rName, 754 const sal_Unicode cSep, bool bODF ) 755 { 756 String aFile( rFile), aName( rName), aEscQuote( RTL_CONSTASCII_USTRINGPARAM("''")); 757 aFile.SearchAndReplaceAllAscii( "'", aEscQuote); 758 if (bODF) 759 aName.SearchAndReplaceAllAscii( "'", aEscQuote); 760 rtl::OUStringBuffer aBuf( aFile.Len() + aName.Len() + 9); 761 if (bODF) 762 aBuf.append( sal_Unicode( '[')); 763 aBuf.append( sal_Unicode( '\'')); 764 aBuf.append( aFile); 765 aBuf.append( sal_Unicode( '\'')); 766 aBuf.append( cSep); 767 if (bODF) 768 aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "$$'")); 769 aBuf.append( aName); 770 if (bODF) 771 aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "']")); 772 return String( aBuf.makeStringAndClear()); 773 } 774 775 static bool lcl_getLastTabName( String& rTabName2, const String& rTabName1, 776 const vector<String>& rTabNames, const ScComplexRefData& rRef ) 777 { 778 SCsTAB nTabSpan = rRef.Ref2.nTab - rRef.Ref1.nTab; 779 if (nTabSpan > 0) 780 { 781 size_t nCount = rTabNames.size(); 782 vector<String>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end(); 783 vector<String>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1); 784 if (itr == rTabNames.end()) 785 { 786 rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE); 787 return false; 788 } 789 790 size_t nDist = ::std::distance(itrBeg, itr); 791 if (nDist + static_cast<size_t>(nTabSpan) >= nCount) 792 { 793 rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE); 794 return false; 795 } 796 797 rTabName2 = rTabNames[nDist+nTabSpan]; 798 } 799 else 800 rTabName2 = rTabName1; 801 802 return true; 803 } 804 805 struct Convention_A1 : public ScCompiler::Convention 806 { 807 Convention_A1( FormulaGrammar::AddressConvention eConv ) : ScCompiler::Convention( eConv ) { } 808 static void MakeColStr( rtl::OUStringBuffer& rBuffer, SCCOL nCol ); 809 static void MakeRowStr( rtl::OUStringBuffer& rBuffer, SCROW nRow ); 810 811 ParseResult parseAnyToken( const String& rFormula, 812 xub_StrLen nSrcPos, 813 const CharClass* pCharClass) const 814 { 815 ParseResult aRet; 816 if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) 817 return aRet; 818 819 static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | 820 KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR; 821 static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT; 822 // '?' allowed in range names because of Xcl :-/ 823 static const String aAddAllowed(String::CreateFromAscii("?#")); 824 return pCharClass->parseAnyToken( rFormula, 825 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed ); 826 } 827 }; 828 829 void Convention_A1::MakeColStr( rtl::OUStringBuffer& rBuffer, SCCOL nCol ) 830 { 831 if ( !ValidCol( nCol) ) 832 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 833 else 834 ::ScColToAlpha( rBuffer, nCol); 835 } 836 837 void Convention_A1::MakeRowStr( rtl::OUStringBuffer& rBuffer, SCROW nRow ) 838 { 839 if ( !ValidRow(nRow) ) 840 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 841 else 842 rBuffer.append(sal_Int32(nRow + 1)); 843 } 844 845 //----------------------------------------------------------------------------- 846 847 struct ConventionOOO_A1 : public Convention_A1 848 { 849 ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO) { } 850 ConventionOOO_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1 (eConv) { } 851 static String MakeTabStr( const ScCompiler& rComp, SCTAB nTab, String& aDoc ) 852 { 853 String aString; 854 if (!rComp.GetDoc()->GetName( nTab, aString )) 855 aString = ScGlobal::GetRscString(STR_NO_REF_TABLE); 856 else 857 { 858 // "'Doc'#Tab" 859 xub_StrLen nPos = ScCompiler::GetDocTabPos( aString); 860 if (nPos != STRING_NOTFOUND) 861 { 862 aDoc = aString.Copy( 0, nPos + 1 ); 863 aString.Erase( 0, nPos + 1 ); 864 aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE, 865 INetURLObject::DECODE_UNAMBIGUOUS ); 866 } 867 else 868 aDoc.Erase(); 869 ScCompiler::CheckTabQuotes( aString, FormulaGrammar::CONV_OOO ); 870 } 871 aString += '.'; 872 return aString; 873 } 874 875 void MakeRefStrImpl( rtl::OUStringBuffer& rBuffer, 876 const ScCompiler& rComp, 877 const ScComplexRefData& rRef, 878 bool bSingleRef, 879 bool bODF ) const 880 { 881 if (bODF) 882 rBuffer.append(sal_Unicode('[')); 883 ScComplexRefData aRef( rRef ); 884 // In case absolute/relative positions weren't separately available: 885 // transform relative to absolute! 886 // AdjustReference( aRef.Ref1 ); 887 // if( !bSingleRef ) 888 // AdjustReference( aRef.Ref2 ); 889 aRef.Ref1.CalcAbsIfRel( rComp.GetPos() ); 890 if( !bSingleRef ) 891 aRef.Ref2.CalcAbsIfRel( rComp.GetPos() ); 892 if( aRef.Ref1.IsFlag3D() ) 893 { 894 if (aRef.Ref1.IsTabDeleted()) 895 { 896 if (!aRef.Ref1.IsTabRel()) 897 rBuffer.append(sal_Unicode('$')); 898 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 899 rBuffer.append(sal_Unicode('.')); 900 } 901 else 902 { 903 String aDoc; 904 String aRefStr( MakeTabStr( rComp, aRef.Ref1.nTab, aDoc ) ); 905 rBuffer.append(aDoc); 906 if (!aRef.Ref1.IsTabRel()) rBuffer.append(sal_Unicode('$')); 907 rBuffer.append(aRefStr); 908 } 909 } 910 else if (bODF) 911 rBuffer.append(sal_Unicode('.')); 912 if (!aRef.Ref1.IsColRel()) 913 rBuffer.append(sal_Unicode('$')); 914 if ( aRef.Ref1.IsColDeleted() ) 915 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 916 else 917 MakeColStr(rBuffer, aRef.Ref1.nCol ); 918 if (!aRef.Ref1.IsRowRel()) 919 rBuffer.append(sal_Unicode('$')); 920 if ( aRef.Ref1.IsRowDeleted() ) 921 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 922 else 923 MakeRowStr( rBuffer, aRef.Ref1.nRow ); 924 if (!bSingleRef) 925 { 926 rBuffer.append(sal_Unicode(':')); 927 if (aRef.Ref2.IsFlag3D() || aRef.Ref2.nTab != aRef.Ref1.nTab) 928 { 929 if (aRef.Ref2.IsTabDeleted()) 930 { 931 if (!aRef.Ref2.IsTabRel()) 932 rBuffer.append(sal_Unicode('$')); 933 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 934 rBuffer.append(sal_Unicode('.')); 935 } 936 else 937 { 938 String aDoc; 939 String aRefStr( MakeTabStr( rComp, aRef.Ref2.nTab, aDoc ) ); 940 rBuffer.append(aDoc); 941 if (!aRef.Ref2.IsTabRel()) rBuffer.append(sal_Unicode('$')); 942 rBuffer.append(aRefStr); 943 } 944 } 945 else if (bODF) 946 rBuffer.append(sal_Unicode('.')); 947 if (!aRef.Ref2.IsColRel()) 948 rBuffer.append(sal_Unicode('$')); 949 if ( aRef.Ref2.IsColDeleted() ) 950 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 951 else 952 MakeColStr( rBuffer, aRef.Ref2.nCol ); 953 if (!aRef.Ref2.IsRowRel()) 954 rBuffer.append(sal_Unicode('$')); 955 if ( aRef.Ref2.IsRowDeleted() ) 956 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 957 else 958 MakeRowStr( rBuffer, aRef.Ref2.nRow ); 959 } 960 if (bODF) 961 rBuffer.append(sal_Unicode(']')); 962 } 963 964 void MakeRefStr( rtl::OUStringBuffer& rBuffer, 965 const ScCompiler& rComp, 966 const ScComplexRefData& rRef, 967 sal_Bool bSingleRef ) const 968 { 969 MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, false); 970 } 971 972 virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const 973 { 974 switch (eSymType) 975 { 976 case ScCompiler::Convention::ABS_SHEET_PREFIX: 977 return '$'; 978 case ScCompiler::Convention::SHEET_SEPARATOR: 979 return '.'; 980 } 981 982 return sal_Unicode(0); 983 } 984 985 virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, 986 const ScDocument* pDoc, 987 const ::com::sun::star::uno::Sequence< 988 const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const 989 { 990 return lcl_parseExternalName(rSymbol, rFile, rName, sal_Unicode('#'), pDoc, pExternalLinks); 991 } 992 993 virtual String makeExternalNameStr( const String& rFile, const String& rName ) const 994 { 995 return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), false); 996 } 997 998 bool makeExternalSingleRefStr( ::rtl::OUStringBuffer& rBuffer, sal_uInt16 nFileId, 999 const String& rTabName, const ScSingleRefData& rRef, 1000 ScExternalRefManager* pRefMgr, bool bDisplayTabName, bool bEncodeUrl ) const 1001 { 1002 if (bDisplayTabName) 1003 { 1004 String aFile; 1005 const String* p = pRefMgr->getExternalFileName(nFileId); 1006 if (p) 1007 { 1008 if (bEncodeUrl) 1009 aFile = *p; 1010 else 1011 aFile = INetURLObject::decode(*p, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS); 1012 } 1013 aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''")); 1014 1015 rBuffer.append(sal_Unicode('\'')); 1016 rBuffer.append(aFile); 1017 rBuffer.append(sal_Unicode('\'')); 1018 rBuffer.append(sal_Unicode('#')); 1019 1020 if (!rRef.IsTabRel()) 1021 rBuffer.append(sal_Unicode('$')); 1022 ScRangeStringConverter::AppendTableName(rBuffer, rTabName); 1023 1024 rBuffer.append(sal_Unicode('.')); 1025 } 1026 1027 if (!rRef.IsColRel()) 1028 rBuffer.append(sal_Unicode('$')); 1029 MakeColStr( rBuffer, rRef.nCol); 1030 if (!rRef.IsRowRel()) 1031 rBuffer.append(sal_Unicode('$')); 1032 MakeRowStr( rBuffer, rRef.nRow); 1033 1034 return true; 1035 } 1036 1037 void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1038 sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef, 1039 ScExternalRefManager* pRefMgr, bool bODF ) const 1040 { 1041 ScSingleRefData aRef(rRef); 1042 aRef.CalcAbsIfRel(rCompiler.GetPos()); 1043 1044 if (bODF) 1045 rBuffer.append( sal_Unicode('[')); 1046 1047 bool bEncodeUrl = true; 1048 switch (rCompiler.GetEncodeUrlMode()) 1049 { 1050 case ScCompiler::ENCODE_BY_GRAMMAR: 1051 bEncodeUrl = bODF; 1052 break; 1053 case ScCompiler::ENCODE_ALWAYS: 1054 bEncodeUrl = true; 1055 break; 1056 case ScCompiler::ENCODE_NEVER: 1057 bEncodeUrl = false; 1058 break; 1059 default: 1060 ; 1061 } 1062 makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true, bEncodeUrl); 1063 if (bODF) 1064 rBuffer.append( sal_Unicode(']')); 1065 } 1066 1067 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1068 sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef, 1069 ScExternalRefManager* pRefMgr ) const 1070 { 1071 makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false); 1072 } 1073 1074 void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1075 sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef, 1076 ScExternalRefManager* pRefMgr, bool bODF ) const 1077 { 1078 ScComplexRefData aRef(rRef); 1079 aRef.CalcAbsIfRel(rCompiler.GetPos()); 1080 1081 if (bODF) 1082 rBuffer.append( sal_Unicode('[')); 1083 // Ensure that there's always a closing bracket, no premature returns. 1084 bool bEncodeUrl = true; 1085 switch (rCompiler.GetEncodeUrlMode()) 1086 { 1087 case ScCompiler::ENCODE_BY_GRAMMAR: 1088 bEncodeUrl = bODF; 1089 break; 1090 case ScCompiler::ENCODE_ALWAYS: 1091 bEncodeUrl = true; 1092 break; 1093 case ScCompiler::ENCODE_NEVER: 1094 bEncodeUrl = false; 1095 break; 1096 default: 1097 ; 1098 } 1099 1100 do 1101 { 1102 if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true, bEncodeUrl)) 1103 break; 1104 1105 rBuffer.append(sal_Unicode(':')); 1106 1107 String aLastTabName; 1108 bool bDisplayTabName = (aRef.Ref1.nTab != aRef.Ref2.nTab); 1109 if (bDisplayTabName) 1110 { 1111 // Get the name of the last table. 1112 vector<String> aTabNames; 1113 pRefMgr->getAllCachedTableNames(nFileId, aTabNames); 1114 if (aTabNames.empty()) 1115 { 1116 DBG_ERROR1( "ConventionOOO_A1::makeExternalRefStrImpl: no sheet names for document ID %s", nFileId); 1117 } 1118 1119 if (!lcl_getLastTabName(aLastTabName, rTabName, aTabNames, aRef)) 1120 { 1121 DBG_ERROR( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found"); 1122 // aLastTabName contains #REF!, proceed. 1123 } 1124 } 1125 else if (bODF) 1126 rBuffer.append( sal_Unicode('.')); // need at least the sheet separator in ODF 1127 makeExternalSingleRefStr( rBuffer, nFileId, aLastTabName, 1128 aRef.Ref2, pRefMgr, bDisplayTabName, bEncodeUrl); 1129 } while (0); 1130 if (bODF) 1131 rBuffer.append( sal_Unicode(']')); 1132 } 1133 1134 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1135 sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef, 1136 ScExternalRefManager* pRefMgr ) const 1137 { 1138 makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false); 1139 } 1140 }; 1141 1142 1143 static const ConventionOOO_A1 ConvOOO_A1; 1144 const ScCompiler::Convention * const ScCompiler::pConvOOO_A1 = &ConvOOO_A1; 1145 1146 //----------------------------------------------------------------------------- 1147 1148 struct ConventionOOO_A1_ODF : public ConventionOOO_A1 1149 { 1150 ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF) { } 1151 void MakeRefStr( rtl::OUStringBuffer& rBuffer, 1152 const ScCompiler& rComp, 1153 const ScComplexRefData& rRef, 1154 sal_Bool bSingleRef ) const 1155 { 1156 MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, true); 1157 } 1158 1159 virtual String makeExternalNameStr( const String& rFile, const String& rName ) const 1160 { 1161 return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), true); 1162 } 1163 1164 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1165 sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef, 1166 ScExternalRefManager* pRefMgr ) const 1167 { 1168 makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true); 1169 } 1170 1171 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1172 sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef, 1173 ScExternalRefManager* pRefMgr ) const 1174 { 1175 makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true); 1176 } 1177 }; 1178 1179 static const ConventionOOO_A1_ODF ConvOOO_A1_ODF; 1180 const ScCompiler::Convention * const ScCompiler::pConvOOO_A1_ODF = &ConvOOO_A1_ODF; 1181 1182 //----------------------------------------------------------------------------- 1183 1184 struct ConventionXL 1185 { 1186 static bool GetDocAndTab( const ScCompiler& rComp, 1187 const ScSingleRefData& rRef, 1188 String& rDocName, 1189 String& rTabName ) 1190 { 1191 bool bHasDoc = false; 1192 1193 rDocName.Erase(); 1194 if (rRef.IsTabDeleted() || 1195 !rComp.GetDoc()->GetName( rRef.nTab, rTabName )) 1196 { 1197 rTabName = ScGlobal::GetRscString( STR_NO_REF_TABLE ); 1198 return false; 1199 } 1200 1201 // Cheesy hack to unparse the OOO style "'Doc'#Tab" 1202 xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); 1203 if (nPos != STRING_NOTFOUND) 1204 { 1205 rDocName = rTabName.Copy( 0, nPos ); 1206 // TODO : More research into how XL escapes the doc path 1207 rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE, 1208 INetURLObject::DECODE_UNAMBIGUOUS ); 1209 rTabName.Erase( 0, nPos + 1 ); 1210 bHasDoc = true; 1211 } 1212 1213 // XL uses the same sheet name quoting conventions in both modes 1214 // it is safe to use A1 here 1215 ScCompiler::CheckTabQuotes( rTabName, FormulaGrammar::CONV_XL_A1 ); 1216 return bHasDoc; 1217 } 1218 1219 static void MakeDocStr( rtl::OUStringBuffer& rBuf, 1220 const ScCompiler& rComp, 1221 const ScComplexRefData& rRef, 1222 bool bSingleRef ) 1223 { 1224 if( rRef.Ref1.IsFlag3D() ) 1225 { 1226 String aStartTabName, aStartDocName, aEndTabName, aEndDocName; 1227 bool bStartHasDoc = false, bEndHasDoc = false; 1228 1229 bStartHasDoc = GetDocAndTab( rComp, rRef.Ref1, 1230 aStartDocName, aStartTabName); 1231 1232 if( !bSingleRef && rRef.Ref2.IsFlag3D() ) 1233 { 1234 bEndHasDoc = GetDocAndTab( rComp, rRef.Ref2, 1235 aEndDocName, aEndTabName); 1236 } 1237 else 1238 bEndHasDoc = bStartHasDoc; 1239 1240 if( bStartHasDoc ) 1241 { 1242 // A ref across multipled workbooks ? 1243 if( !bEndHasDoc ) 1244 return; 1245 1246 rBuf.append( sal_Unicode( '[' ) ); 1247 rBuf.append( aStartDocName ); 1248 rBuf.append( sal_Unicode( ']' ) ); 1249 } 1250 1251 rBuf.append( aStartTabName ); 1252 if( !bSingleRef && rRef.Ref2.IsFlag3D() && aStartTabName != aEndTabName ) 1253 { 1254 rBuf.append( sal_Unicode( ':' ) ); 1255 rBuf.append( aEndTabName ); 1256 } 1257 1258 rBuf.append( sal_Unicode( '!' ) ); 1259 } 1260 } 1261 1262 static sal_Unicode getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType ) 1263 { 1264 switch (eSymType) 1265 { 1266 case ScCompiler::Convention::ABS_SHEET_PREFIX: 1267 return sal_Unicode(0); 1268 case ScCompiler::Convention::SHEET_SEPARATOR: 1269 return '!'; 1270 } 1271 return sal_Unicode(0); 1272 } 1273 1274 static bool parseExternalName( const String& rSymbol, String& rFile, String& rName, 1275 const ScDocument* pDoc, 1276 const ::com::sun::star::uno::Sequence< 1277 const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) 1278 { 1279 return lcl_parseExternalName( rSymbol, rFile, rName, sal_Unicode('!'), pDoc, pExternalLinks); 1280 } 1281 1282 static String makeExternalNameStr( const String& rFile, const String& rName ) 1283 { 1284 return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('!'), false); 1285 } 1286 1287 static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName, bool bEncodeUrl ) 1288 { 1289 // Format that is easier to deal with inside OOo, because we use file 1290 // URL, and all characetrs are allowed. Check if it makes sense to do 1291 // it the way Gnumeric does it. Gnumeric doesn't use the URL form 1292 // and allows relative file path. 1293 // 1294 // ['file:///path/to/source/filename.xls'] 1295 1296 rBuffer.append(sal_Unicode('[')); 1297 rBuffer.append(sal_Unicode('\'')); 1298 String aFullName; 1299 if (bEncodeUrl) 1300 aFullName = rFullName; 1301 else 1302 aFullName = INetURLObject::decode(rFullName, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS); 1303 1304 const sal_Unicode* pBuf = aFullName.GetBuffer(); 1305 xub_StrLen nLen = aFullName.Len(); 1306 for (xub_StrLen i = 0; i < nLen; ++i) 1307 { 1308 const sal_Unicode c = pBuf[i]; 1309 if (c == sal_Unicode('\'')) 1310 rBuffer.append(c); 1311 rBuffer.append(c); 1312 } 1313 rBuffer.append(sal_Unicode('\'')); 1314 rBuffer.append(sal_Unicode(']')); 1315 } 1316 1317 static void makeExternalTabNameRange( ::rtl::OUStringBuffer& rBuf, const String& rTabName, 1318 const vector<String>& rTabNames, 1319 const ScComplexRefData& rRef ) 1320 { 1321 String aLastTabName; 1322 if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef)) 1323 { 1324 ScRangeStringConverter::AppendTableName(rBuf, aLastTabName); 1325 return; 1326 } 1327 1328 ScRangeStringConverter::AppendTableName(rBuf, rTabName); 1329 if (rTabName != aLastTabName) 1330 { 1331 rBuf.append(sal_Unicode(':')); 1332 ScRangeStringConverter::AppendTableName(rBuf, rTabName); 1333 } 1334 } 1335 1336 static void parseExternalDocName( const String& rFormula, xub_StrLen& rSrcPos ) 1337 { 1338 xub_StrLen nLen = rFormula.Len(); 1339 const sal_Unicode* p = rFormula.GetBuffer(); 1340 sal_Unicode cPrev = 0; 1341 for (xub_StrLen i = rSrcPos; i < nLen; ++i) 1342 { 1343 sal_Unicode c = p[i]; 1344 if (i == rSrcPos) 1345 { 1346 // first character must be '['. 1347 if (c != '[') 1348 return; 1349 } 1350 else if (i == rSrcPos + 1) 1351 { 1352 // second character must be a single quote. 1353 if (c != '\'') 1354 return; 1355 } 1356 else if (c == '\'') 1357 { 1358 if (cPrev == '\'') 1359 // two successive single quote is treated as a single 1360 // valid character. 1361 c = 'a'; 1362 } 1363 else if (c == ']') 1364 { 1365 if (cPrev == '\'') 1366 { 1367 // valid source document path found. Increment the 1368 // current position to skip the source path. 1369 rSrcPos = i + 1; 1370 if (rSrcPos >= nLen) 1371 rSrcPos = nLen - 1; 1372 return; 1373 } 1374 else 1375 return; 1376 } 1377 else 1378 { 1379 // any other character 1380 if (i > rSrcPos + 2 && cPrev == '\'') 1381 // unless it's the 3rd character, a normal character 1382 // following immediately a single quote is invalid. 1383 return; 1384 } 1385 cPrev = c; 1386 } 1387 } 1388 }; 1389 1390 struct ConventionXL_A1 : public Convention_A1, public ConventionXL 1391 { 1392 ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1 ) { } 1393 ConventionXL_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1( eConv ) { } 1394 1395 void makeSingleCellStr( ::rtl::OUStringBuffer& rBuf, const ScSingleRefData& rRef ) const 1396 { 1397 if (!rRef.IsColRel()) 1398 rBuf.append(sal_Unicode('$')); 1399 MakeColStr(rBuf, rRef.nCol); 1400 if (!rRef.IsRowRel()) 1401 rBuf.append(sal_Unicode('$')); 1402 MakeRowStr(rBuf, rRef.nRow); 1403 } 1404 1405 void MakeRefStr( rtl::OUStringBuffer& rBuf, 1406 const ScCompiler& rComp, 1407 const ScComplexRefData& rRef, 1408 sal_Bool bSingleRef ) const 1409 { 1410 ScComplexRefData aRef( rRef ); 1411 1412 // Play fast and loose with invalid refs. There is not much point in producing 1413 // Foo!A1:#REF! versus #REF! at this point 1414 aRef.Ref1.CalcAbsIfRel( rComp.GetPos() ); 1415 1416 MakeDocStr( rBuf, rComp, aRef, bSingleRef ); 1417 1418 if( aRef.Ref1.IsColDeleted() || aRef.Ref1.IsRowDeleted() ) 1419 { 1420 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 1421 return; 1422 } 1423 1424 if( !bSingleRef ) 1425 { 1426 aRef.Ref2.CalcAbsIfRel( rComp.GetPos() ); 1427 if( aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted() ) 1428 { 1429 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 1430 return; 1431 } 1432 1433 if( aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL ) 1434 { 1435 if (!aRef.Ref1.IsRowRel()) 1436 rBuf.append(sal_Unicode( '$' )); 1437 MakeRowStr( rBuf, aRef.Ref1.nRow ); 1438 rBuf.append(sal_Unicode( ':' )); 1439 if (!aRef.Ref2.IsRowRel()) 1440 rBuf.append(sal_Unicode( '$' )); 1441 MakeRowStr( rBuf, aRef.Ref2.nRow ); 1442 return; 1443 } 1444 1445 if( aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW ) 1446 { 1447 if (!aRef.Ref1.IsColRel()) 1448 rBuf.append(sal_Unicode( '$' )); 1449 MakeColStr(rBuf, aRef.Ref1.nCol ); 1450 rBuf.append(sal_Unicode( ':' )); 1451 if (!aRef.Ref2.IsColRel()) 1452 rBuf.append(sal_Unicode( '$' )); 1453 MakeColStr(rBuf, aRef.Ref2.nCol ); 1454 return; 1455 } 1456 } 1457 1458 makeSingleCellStr(rBuf, aRef.Ref1); 1459 if (!bSingleRef) 1460 { 1461 rBuf.append(sal_Unicode( ':' )); 1462 makeSingleCellStr(rBuf, aRef.Ref2); 1463 } 1464 } 1465 1466 virtual ParseResult parseAnyToken( const String& rFormula, 1467 xub_StrLen nSrcPos, 1468 const CharClass* pCharClass) const 1469 { 1470 ParseResult aRet; 1471 if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) 1472 return aRet; 1473 1474 static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | 1475 KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR; 1476 static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT; 1477 // '?' allowed in range names 1478 static const String aAddAllowed = String::CreateFromAscii("?!"); 1479 return pCharClass->parseAnyToken( rFormula, 1480 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed ); 1481 } 1482 1483 virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const 1484 { 1485 return ConventionXL::getSpecialSymbol(eSymType); 1486 } 1487 1488 virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, 1489 const ScDocument* pDoc, 1490 const ::com::sun::star::uno::Sequence< 1491 const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const 1492 { 1493 return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks); 1494 } 1495 1496 virtual String makeExternalNameStr( const String& rFile, const String& rName ) const 1497 { 1498 return ConventionXL::makeExternalNameStr(rFile, rName); 1499 } 1500 1501 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1502 sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef, 1503 ScExternalRefManager* pRefMgr ) const 1504 { 1505 // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1 1506 // This is a little different from the format Excel uses, as Excel 1507 // puts [] only around the file name. But we need to enclose the 1508 // whole file path with [] because the file name can contain any 1509 // characters. 1510 1511 const String* pFullName = pRefMgr->getExternalFileName(nFileId); 1512 if (!pFullName) 1513 return; 1514 1515 ScSingleRefData aRef(rRef); 1516 aRef.CalcAbsIfRel(rCompiler.GetPos()); 1517 1518 ConventionXL::makeExternalDocStr( 1519 rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); 1520 ScRangeStringConverter::AppendTableName(rBuffer, rTabName); 1521 rBuffer.append(sal_Unicode('!')); 1522 1523 makeSingleCellStr(rBuffer, aRef); 1524 } 1525 1526 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1527 sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef, 1528 ScExternalRefManager* pRefMgr ) const 1529 { 1530 const String* pFullName = pRefMgr->getExternalFileName(nFileId); 1531 if (!pFullName) 1532 return; 1533 1534 vector<String> aTabNames; 1535 pRefMgr->getAllCachedTableNames(nFileId, aTabNames); 1536 if (aTabNames.empty()) 1537 return; 1538 1539 ScComplexRefData aRef(rRef); 1540 aRef.CalcAbsIfRel(rCompiler.GetPos()); 1541 1542 ConventionXL::makeExternalDocStr( 1543 rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); 1544 ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef); 1545 rBuffer.append(sal_Unicode('!')); 1546 1547 makeSingleCellStr(rBuffer, aRef.Ref1); 1548 if (aRef.Ref1 != aRef.Ref2) 1549 { 1550 rBuffer.append(sal_Unicode(':')); 1551 makeSingleCellStr(rBuffer, aRef.Ref2); 1552 } 1553 } 1554 }; 1555 1556 static const ConventionXL_A1 ConvXL_A1; 1557 const ScCompiler::Convention * const ScCompiler::pConvXL_A1 = &ConvXL_A1; 1558 1559 1560 struct ConventionXL_OOX : public ConventionXL_A1 1561 { 1562 ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { } 1563 }; 1564 1565 static const ConventionXL_OOX ConvXL_OOX; 1566 const ScCompiler::Convention * const ScCompiler::pConvXL_OOX = &ConvXL_OOX; 1567 1568 1569 //----------------------------------------------------------------------------- 1570 1571 static void 1572 r1c1_add_col( rtl::OUStringBuffer &rBuf, const ScSingleRefData& rRef ) 1573 { 1574 rBuf.append( sal_Unicode( 'C' ) ); 1575 if( rRef.IsColRel() ) 1576 { 1577 if (rRef.nRelCol != 0) 1578 { 1579 rBuf.append( sal_Unicode( '[' ) ); 1580 rBuf.append( String::CreateFromInt32( rRef.nRelCol ) ); 1581 rBuf.append( sal_Unicode( ']' ) ); 1582 } 1583 } 1584 else 1585 rBuf.append( String::CreateFromInt32( rRef.nCol + 1 ) ); 1586 } 1587 static void 1588 r1c1_add_row( rtl::OUStringBuffer &rBuf, const ScSingleRefData& rRef ) 1589 { 1590 rBuf.append( sal_Unicode( 'R' ) ); 1591 if( rRef.IsRowRel() ) 1592 { 1593 if (rRef.nRelRow != 0) 1594 { 1595 rBuf.append( sal_Unicode( '[' ) ); 1596 rBuf.append( String::CreateFromInt32( rRef.nRelRow ) ); 1597 rBuf.append( sal_Unicode( ']' ) ); 1598 } 1599 } 1600 else 1601 rBuf.append( String::CreateFromInt32( rRef.nRow + 1 ) ); 1602 } 1603 1604 struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL 1605 { 1606 ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1 ) { } 1607 void MakeRefStr( rtl::OUStringBuffer& rBuf, 1608 const ScCompiler& rComp, 1609 const ScComplexRefData& rRef, 1610 sal_Bool bSingleRef ) const 1611 { 1612 ScComplexRefData aRef( rRef ); 1613 1614 MakeDocStr( rBuf, rComp, aRef, bSingleRef ); 1615 1616 // Play fast and loose with invalid refs. There is not much point in producing 1617 // Foo!A1:#REF! versus #REF! at this point 1618 aRef.Ref1.CalcAbsIfRel( rComp.GetPos() ); 1619 if( aRef.Ref1.IsColDeleted() || aRef.Ref1.IsRowDeleted() ) 1620 { 1621 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 1622 return; 1623 } 1624 1625 if( !bSingleRef ) 1626 { 1627 aRef.Ref2.CalcAbsIfRel( rComp.GetPos() ); 1628 if( aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted() ) 1629 { 1630 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 1631 return; 1632 } 1633 1634 if( aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL ) 1635 { 1636 r1c1_add_row( rBuf, rRef.Ref1 ); 1637 if( rRef.Ref1.nRow != rRef.Ref2.nRow || 1638 rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel() ) { 1639 rBuf.append (sal_Unicode ( ':' ) ); 1640 r1c1_add_row( rBuf, rRef.Ref2 ); 1641 } 1642 return; 1643 1644 } 1645 1646 if( aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW ) 1647 { 1648 r1c1_add_col( rBuf, rRef.Ref1 ); 1649 if( rRef.Ref1.nCol != rRef.Ref2.nCol || 1650 rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel() ) 1651 { 1652 rBuf.append (sal_Unicode ( ':' ) ); 1653 r1c1_add_col( rBuf, rRef.Ref2 ); 1654 } 1655 return; 1656 } 1657 } 1658 1659 r1c1_add_row( rBuf, rRef.Ref1 ); 1660 r1c1_add_col( rBuf, rRef.Ref1 ); 1661 if (!bSingleRef) 1662 { 1663 rBuf.append (sal_Unicode ( ':' ) ); 1664 r1c1_add_row( rBuf, rRef.Ref2 ); 1665 r1c1_add_col( rBuf, rRef.Ref2 ); 1666 } 1667 } 1668 1669 ParseResult parseAnyToken( const String& rFormula, 1670 xub_StrLen nSrcPos, 1671 const CharClass* pCharClass) const 1672 { 1673 ConventionXL::parseExternalDocName(rFormula, nSrcPos); 1674 1675 ParseResult aRet; 1676 if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) 1677 return aRet; 1678 1679 static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | 1680 KParseTokens::ASC_UNDERSCORE ; 1681 static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT; 1682 // '?' allowed in range names 1683 static const String aAddAllowed = String::CreateFromAscii( "?-[]!" ); 1684 1685 return pCharClass->parseAnyToken( rFormula, 1686 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed ); 1687 } 1688 1689 virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const 1690 { 1691 return ConventionXL::getSpecialSymbol(eSymType); 1692 } 1693 1694 virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, 1695 const ScDocument* pDoc, 1696 const ::com::sun::star::uno::Sequence< 1697 const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const 1698 { 1699 return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks); 1700 } 1701 1702 virtual String makeExternalNameStr( const String& rFile, const String& rName ) const 1703 { 1704 return ConventionXL::makeExternalNameStr(rFile, rName); 1705 } 1706 1707 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1708 sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef, 1709 ScExternalRefManager* pRefMgr ) const 1710 { 1711 // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1 1712 // This is a little different from the format Excel uses, as Excel 1713 // puts [] only around the file name. But we need to enclose the 1714 // whole file path with [] because the file name can contain any 1715 // characters. 1716 1717 const String* pFullName = pRefMgr->getExternalFileName(nFileId); 1718 if (!pFullName) 1719 return; 1720 1721 ScSingleRefData aRef(rRef); 1722 aRef.CalcAbsIfRel(rCompiler.GetPos()); 1723 1724 ConventionXL::makeExternalDocStr( 1725 rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); 1726 ScRangeStringConverter::AppendTableName(rBuffer, rTabName); 1727 rBuffer.append(sal_Unicode('!')); 1728 1729 r1c1_add_row(rBuffer, aRef); 1730 r1c1_add_col(rBuffer, aRef); 1731 } 1732 1733 virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, 1734 sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef, 1735 ScExternalRefManager* pRefMgr ) const 1736 { 1737 const String* pFullName = pRefMgr->getExternalFileName(nFileId); 1738 if (!pFullName) 1739 return; 1740 1741 vector<String> aTabNames; 1742 pRefMgr->getAllCachedTableNames(nFileId, aTabNames); 1743 if (aTabNames.empty()) 1744 return; 1745 1746 ScComplexRefData aRef(rRef); 1747 aRef.CalcAbsIfRel(rCompiler.GetPos()); 1748 1749 ConventionXL::makeExternalDocStr( 1750 rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); 1751 ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef); 1752 rBuffer.append(sal_Unicode('!')); 1753 1754 if (aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted()) 1755 { 1756 rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); 1757 return; 1758 } 1759 1760 if (aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL) 1761 { 1762 r1c1_add_row(rBuffer, rRef.Ref1); 1763 if (rRef.Ref1.nRow != rRef.Ref2.nRow || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel()) 1764 { 1765 rBuffer.append (sal_Unicode(':')); 1766 r1c1_add_row(rBuffer, rRef.Ref2); 1767 } 1768 return; 1769 } 1770 1771 if (aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW) 1772 { 1773 r1c1_add_col(rBuffer, aRef.Ref1); 1774 if (aRef.Ref1.nCol != aRef.Ref2.nCol || aRef.Ref1.IsColRel() != aRef.Ref2.IsColRel()) 1775 { 1776 rBuffer.append (sal_Unicode(':')); 1777 r1c1_add_col(rBuffer, aRef.Ref2); 1778 } 1779 return; 1780 } 1781 1782 r1c1_add_row(rBuffer, aRef.Ref1); 1783 r1c1_add_col(rBuffer, aRef.Ref1); 1784 rBuffer.append (sal_Unicode (':')); 1785 r1c1_add_row(rBuffer, aRef.Ref2); 1786 r1c1_add_col(rBuffer, aRef.Ref2); 1787 } 1788 }; 1789 1790 static const ConventionXL_R1C1 ConvXL_R1C1; 1791 const ScCompiler::Convention * const ScCompiler::pConvXL_R1C1 = &ConvXL_R1C1; 1792 1793 //----------------------------------------------------------------------------- 1794 ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArray& rArr) 1795 : FormulaCompiler(rArr), 1796 pDoc( pDocument ), 1797 aPos( rPos ), 1798 pCharClass( ScGlobal::pCharClass ), 1799 mnPredetectedReference(0), 1800 mnRangeOpPosInSymbol(-1), 1801 pConv( pConvOOO_A1 ), 1802 meEncodeUrlMode( ENCODE_BY_GRAMMAR ), 1803 mbCloseBrackets( true ), 1804 mbExtendedErrorDetection( false ), 1805 mbRewind( false ) 1806 { 1807 nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0; 1808 } 1809 1810 ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos) 1811 : 1812 pDoc( pDocument ), 1813 aPos( rPos ), 1814 pCharClass( ScGlobal::pCharClass ), 1815 mnPredetectedReference(0), 1816 mnRangeOpPosInSymbol(-1), 1817 pConv( pConvOOO_A1 ), 1818 meEncodeUrlMode( ENCODE_BY_GRAMMAR ), 1819 mbCloseBrackets( true ), 1820 mbExtendedErrorDetection( false ), 1821 mbRewind( false ) 1822 { 1823 nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0; 1824 } 1825 1826 void ScCompiler::CheckTabQuotes( String& rString, 1827 const FormulaGrammar::AddressConvention eConv ) 1828 { 1829 using namespace ::com::sun::star::i18n; 1830 sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE; 1831 sal_Int32 nContFlags = nStartFlags; 1832 ParseResult aRes = ScGlobal::pCharClass->parsePredefinedToken( 1833 KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_STRING, nContFlags, EMPTY_STRING); 1834 bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.Len()); 1835 1836 switch ( eConv ) 1837 { 1838 default : 1839 case FormulaGrammar::CONV_UNSPECIFIED : 1840 break; 1841 case FormulaGrammar::CONV_OOO : 1842 case FormulaGrammar::CONV_XL_A1 : 1843 case FormulaGrammar::CONV_XL_R1C1 : 1844 case FormulaGrammar::CONV_XL_OOX : 1845 if( bNeedsQuote ) 1846 { 1847 static const String one_quote = static_cast<sal_Unicode>( '\'' ); 1848 static const String two_quote = String::CreateFromAscii( "''" ); 1849 // escape embedded quotes 1850 rString.SearchAndReplaceAll( one_quote, two_quote ); 1851 } 1852 break; 1853 } 1854 1855 if ( !bNeedsQuote && CharClass::isAsciiNumeric( rString ) ) 1856 { 1857 // Prevent any possible confusion resulting from pure numeric sheet names. 1858 bNeedsQuote = true; 1859 } 1860 1861 if( bNeedsQuote ) 1862 { 1863 rString.Insert( '\'', 0 ); 1864 rString += '\''; 1865 } 1866 } 1867 1868 1869 xub_StrLen ScCompiler::GetDocTabPos( const String& rString ) 1870 { 1871 if (rString.GetChar(0) != '\'') 1872 return STRING_NOTFOUND; 1873 xub_StrLen nPos = ScGlobal::FindUnquoted( rString, SC_COMPILER_FILE_TAB_SEP); 1874 // it must be 'Doc'# 1875 if (nPos != STRING_NOTFOUND && rString.GetChar(nPos-1) != '\'') 1876 nPos = STRING_NOTFOUND; 1877 return nPos; 1878 } 1879 1880 //--------------------------------------------------------------------------- 1881 1882 void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv ) 1883 { 1884 switch ( eConv ) { 1885 case FormulaGrammar::CONV_UNSPECIFIED : 1886 break; 1887 default : 1888 case FormulaGrammar::CONV_OOO : SetRefConvention( pConvOOO_A1 ); break; 1889 case FormulaGrammar::CONV_ODF : SetRefConvention( pConvOOO_A1_ODF ); break; 1890 case FormulaGrammar::CONV_XL_A1 : SetRefConvention( pConvXL_A1 ); break; 1891 case FormulaGrammar::CONV_XL_R1C1 : SetRefConvention( pConvXL_R1C1 ); break; 1892 case FormulaGrammar::CONV_XL_OOX : SetRefConvention( pConvXL_OOX ); break; 1893 } 1894 } 1895 1896 void ScCompiler::SetRefConvention( const ScCompiler::Convention *pConvP ) 1897 { 1898 pConv = pConvP; 1899 meGrammar = FormulaGrammar::mergeToGrammar( meGrammar, pConv->meConv); 1900 DBG_ASSERT( FormulaGrammar::isSupported( meGrammar), 1901 "ScCompiler::SetRefConvention: unsupported grammar resulting"); 1902 } 1903 1904 void ScCompiler::SetError(sal_uInt16 nError) 1905 { 1906 if( !pArr->GetCodeError() ) 1907 pArr->SetCodeError( nError); 1908 } 1909 1910 1911 sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub_StrLen nMax ) 1912 { 1913 const sal_Unicode* const pStop = pDst + nMax; 1914 while ( *pSrc && pDst < pStop ) 1915 { 1916 *pDst++ = *pSrc++; 1917 } 1918 *pDst = 0; 1919 return pDst; 1920 } 1921 1922 1923 //--------------------------------------------------------------------------- 1924 // NextSymbol 1925 //--------------------------------------------------------------------------- 1926 // Zerlegt die Formel in einzelne Symbole fuer die weitere 1927 // Verarbeitung (Turing-Maschine). 1928 //--------------------------------------------------------------------------- 1929 // Ausgangs Zustand = GetChar 1930 //---------------+-------------------+-----------------------+--------------- 1931 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand 1932 //---------------+-------------------+-----------------------+--------------- 1933 // GetChar | ;()+-*/^=& | Symbol=Zeichen | Stop 1934 // | <> | Symbol=Zeichen | GetBool 1935 // | $ Buchstabe | Symbol=Zeichen | GetWord 1936 // | Ziffer | Symbol=Zeichen | GetValue 1937 // | " | Keine | GetString 1938 // | Sonst | Keine | GetChar 1939 //---------------+-------------------+-----------------------+--------------- 1940 // GetBool | => | Symbol=Symbol+Zeichen | Stop 1941 // | Sonst | Dec(CharPos) | Stop 1942 //---------------+-------------------+-----------------------+--------------- 1943 // GetWord | SepSymbol | Dec(CharPos) | Stop 1944 // | ()+-*/^=<>&~ | | 1945 // | Leerzeichen | Dec(CharPos) | Stop 1946 // | $_:. | | 1947 // | Buchstabe,Ziffer | Symbol=Symbol+Zeichen | GetWord 1948 // | Sonst | Fehler | Stop 1949 //---------------|-------------------+-----------------------+--------------- 1950 // GetValue | ;()*/^=<>& | | 1951 // | Leerzeichen | Dec(CharPos) | Stop 1952 // | Ziffer E+-%,. | Symbol=Symbol+Zeichen | GetValue 1953 // | Sonst | Fehler | Stop 1954 //---------------+-------------------+-----------------------+--------------- 1955 // GetString | " | Keine | Stop 1956 // | Sonst | Symbol=Symbol+Zeichen | GetString 1957 //---------------+-------------------+-----------------------+--------------- 1958 1959 xub_StrLen ScCompiler::NextSymbol(bool bInArray) 1960 { 1961 cSymbol[MAXSTRLEN-1] = 0; // Stopper 1962 sal_Unicode* pSym = cSymbol; 1963 const sal_Unicode* const pStart = aFormula.GetBuffer(); 1964 const sal_Unicode* pSrc = pStart + nSrcPos; 1965 bool bi18n = false; 1966 sal_Unicode c = *pSrc; 1967 sal_Unicode cLast = 0; 1968 bool bQuote = false; 1969 mnRangeOpPosInSymbol = -1; 1970 ScanState eState = ssGetChar; 1971 xub_StrLen nSpaces = 0; 1972 sal_Unicode cSep = mxSymbols->getSymbol( ocSep).GetChar(0); 1973 sal_Unicode cArrayColSep = mxSymbols->getSymbol( ocArrayColSep).GetChar(0); 1974 sal_Unicode cArrayRowSep = mxSymbols->getSymbol( ocArrayRowSep).GetChar(0); 1975 sal_Unicode cDecSep = (mxSymbols->isEnglish() ? '.' : 1976 ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0)); 1977 1978 // special symbols specific to address convention used 1979 sal_Unicode cSheetPrefix = pConv->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX); 1980 sal_Unicode cSheetSep = pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR); 1981 1982 int nDecSeps = 0; 1983 bool bAutoIntersection = false; 1984 int nRefInName = 0; 1985 mnPredetectedReference = 0; 1986 // try to parse simple tokens before calling i18n parser 1987 while ((c != 0) && (eState != ssStop) ) 1988 { 1989 pSrc++; 1990 sal_uLong nMask = GetCharTableFlags( c ); 1991 // The parameter separator and the array column and row separators end 1992 // things unconditionally if not in string or reference. 1993 if (c == cSep || (bInArray && (c == cArrayColSep || c == cArrayRowSep))) 1994 { 1995 switch (eState) 1996 { 1997 // these are to be continued 1998 case ssGetString: 1999 case ssSkipString: 2000 case ssGetReference: 2001 case ssSkipReference: 2002 break; 2003 default: 2004 if (eState == ssGetChar) 2005 *pSym++ = c; 2006 else 2007 pSrc--; 2008 eState = ssStop; 2009 } 2010 } 2011 Label_MaskStateMachine: 2012 switch (eState) 2013 { 2014 case ssGetChar : 2015 { 2016 // Order is important! 2017 if( nMask & SC_COMPILER_C_ODF_LABEL_OP ) 2018 { 2019 // '!!' automatic intersection 2020 if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_ODF_LABEL_OP) 2021 { 2022 /* TODO: For now the UI "space operator" is used, this 2023 * could be enhanced using a specialized OpCode to get 2024 * rid of the space ambiguity, which would need some 2025 * places to be adapted though. And we would still need 2026 * to support the ambiguous space operator for UI 2027 * purposes anyway. However, we then could check for 2028 * invalid usage of '!!', which currently isn't 2029 * possible. */ 2030 if (!bAutoIntersection) 2031 { 2032 ++pSrc; 2033 nSpaces += 2; // must match the character count 2034 bAutoIntersection = true; 2035 } 2036 else 2037 { 2038 pSrc--; 2039 eState = ssStop; 2040 } 2041 } 2042 else 2043 { 2044 nMask &= ~SC_COMPILER_C_ODF_LABEL_OP; 2045 goto Label_MaskStateMachine; 2046 } 2047 } 2048 else if( nMask & SC_COMPILER_C_ODF_NAME_MARKER ) 2049 { 2050 // '$$' defined name marker 2051 if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_ODF_NAME_MARKER) 2052 { 2053 // both eaten, not added to pSym 2054 ++pSrc; 2055 } 2056 else 2057 { 2058 nMask &= ~SC_COMPILER_C_ODF_NAME_MARKER; 2059 goto Label_MaskStateMachine; 2060 } 2061 } 2062 else if( nMask & SC_COMPILER_C_CHAR ) 2063 { 2064 *pSym++ = c; 2065 eState = ssStop; 2066 } 2067 else if( nMask & SC_COMPILER_C_ODF_LBRACKET ) 2068 { 2069 // eaten, not added to pSym 2070 eState = ssGetReference; 2071 mnPredetectedReference = 1; 2072 } 2073 else if( nMask & SC_COMPILER_C_CHAR_BOOL ) 2074 { 2075 *pSym++ = c; 2076 eState = ssGetBool; 2077 } 2078 else if( nMask & SC_COMPILER_C_CHAR_VALUE ) 2079 { 2080 *pSym++ = c; 2081 eState = ssGetValue; 2082 } 2083 else if( nMask & SC_COMPILER_C_CHAR_STRING ) 2084 { 2085 *pSym++ = c; 2086 eState = ssGetString; 2087 } 2088 else if( nMask & SC_COMPILER_C_CHAR_DONTCARE ) 2089 { 2090 nSpaces++; 2091 } 2092 else if( nMask & SC_COMPILER_C_CHAR_IDENT ) 2093 { // try to get a simple ASCII identifier before calling 2094 // i18n, to gain performance during import 2095 *pSym++ = c; 2096 eState = ssGetIdent; 2097 } 2098 else 2099 { 2100 bi18n = true; 2101 eState = ssStop; 2102 } 2103 } 2104 break; 2105 case ssGetIdent: 2106 { 2107 if ( nMask & SC_COMPILER_C_IDENT ) 2108 { // This catches also $Sheet1.A$1, for example. 2109 if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) 2110 { 2111 SetError(errStringOverflow); 2112 eState = ssStop; 2113 } 2114 else 2115 *pSym++ = c; 2116 } 2117 else if (c == ':' && mnRangeOpPosInSymbol < 0) 2118 { 2119 // One range operator may form Sheet1.A:A, which we need to 2120 // pass as one entity to IsReference(). 2121 mnRangeOpPosInSymbol = pSym - &cSymbol[0]; 2122 if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) 2123 { 2124 SetError(errStringOverflow); 2125 eState = ssStop; 2126 } 2127 else 2128 *pSym++ = c; 2129 } 2130 else if ( 128 <= c || '\'' == c ) 2131 { // High values need reparsing with i18n, 2132 // single quoted $'sheet' names too (otherwise we'd had to 2133 // implement everything twice). 2134 bi18n = true; 2135 eState = ssStop; 2136 } 2137 else 2138 { 2139 pSrc--; 2140 eState = ssStop; 2141 } 2142 } 2143 break; 2144 case ssGetBool : 2145 { 2146 if( nMask & SC_COMPILER_C_BOOL ) 2147 { 2148 *pSym++ = c; 2149 eState = ssStop; 2150 } 2151 else 2152 { 2153 pSrc--; 2154 eState = ssStop; 2155 } 2156 } 2157 break; 2158 case ssGetValue : 2159 { 2160 if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) 2161 { 2162 SetError(errStringOverflow); 2163 eState = ssStop; 2164 } 2165 else if (c == cDecSep) 2166 { 2167 if (++nDecSeps > 1) 2168 { 2169 // reparse with i18n, may be numeric sheet name as well 2170 bi18n = true; 2171 eState = ssStop; 2172 } 2173 else 2174 *pSym++ = c; 2175 } 2176 else if( nMask & SC_COMPILER_C_VALUE ) 2177 *pSym++ = c; 2178 else if( nMask & SC_COMPILER_C_VALUE_SEP ) 2179 { 2180 pSrc--; 2181 eState = ssStop; 2182 } 2183 else if (c == 'E' || c == 'e') 2184 { 2185 if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_VALUE_EXP) 2186 *pSym++ = c; 2187 else 2188 { 2189 // reparse with i18n 2190 bi18n = true; 2191 eState = ssStop; 2192 } 2193 } 2194 else if( nMask & SC_COMPILER_C_VALUE_SIGN ) 2195 { 2196 if (((cLast == 'E') || (cLast == 'e')) && 2197 (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_VALUE_VALUE)) 2198 { 2199 *pSym++ = c; 2200 } 2201 else 2202 { 2203 pSrc--; 2204 eState = ssStop; 2205 } 2206 } 2207 else 2208 { 2209 // reparse with i18n 2210 bi18n = true; 2211 eState = ssStop; 2212 } 2213 } 2214 break; 2215 case ssGetString : 2216 { 2217 if( nMask & SC_COMPILER_C_STRING_SEP ) 2218 { 2219 if ( !bQuote ) 2220 { 2221 if ( *pSrc == '"' ) 2222 bQuote = true; // "" => literal " 2223 else 2224 eState = ssStop; 2225 } 2226 else 2227 bQuote = false; 2228 } 2229 if ( !bQuote ) 2230 { 2231 if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) 2232 { 2233 SetError(errStringOverflow); 2234 eState = ssSkipString; 2235 } 2236 else 2237 *pSym++ = c; 2238 } 2239 } 2240 break; 2241 case ssSkipString: 2242 if( nMask & SC_COMPILER_C_STRING_SEP ) 2243 eState = ssStop; 2244 break; 2245 case ssGetReference: 2246 if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) 2247 { 2248 SetError( errStringOverflow); 2249 eState = ssSkipReference; 2250 } 2251 // fall through and follow logic 2252 case ssSkipReference: 2253 // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being 2254 // mandatory also if no sheet name. 'External'# is optional, 2255 // sheet name is optional, quotes around sheet name are 2256 // optional if no quote contained. 2257 // 2nd usage: ['Sheet'.$$'DefinedName'] 2258 // 3rd usage: ['External'#$$'DefinedName'] 2259 // 4th usage: ['External'#$'Sheet'.$$'DefinedName'] 2260 // Also for all these names quotes are optional if no quote 2261 // contained. 2262 { 2263 2264 // nRefInName: 0 := not in sheet name yet. 'External' 2265 // is parsed as if it was a sheet name and nRefInName 2266 // is reset when # is encountered immediately after closing 2267 // quote. Same with 'DefinedName', nRefInName is cleared 2268 // when : is encountered. 2269 2270 // Encountered leading $ before sheet name. 2271 static const int kDollar = (1 << 1); 2272 // Encountered ' opening quote, which may be after $ or 2273 // not. 2274 static const int kOpen = (1 << 2); 2275 // Somewhere in name. 2276 static const int kName = (1 << 3); 2277 // Encountered ' in name, will be cleared if double or 2278 // transformed to kClose if not, in which case kOpen is 2279 // cleared. 2280 static const int kQuote = (1 << 4); 2281 // Past ' closing quote. 2282 static const int kClose = (1 << 5); 2283 // Encountered # file/sheet separator. 2284 static const int kFileSep = (1 << 6); 2285 // Past . sheet name separator. 2286 static const int kPast = (1 << 7); 2287 // Marked name $$ follows sheet name separator, detected 2288 // while we're still on the separator. Will be cleared when 2289 // entering the name. 2290 static const int kMarkAhead = (1 << 8); 2291 // In marked defined name. 2292 static const int kDefName = (1 << 9); 2293 2294 bool bAddToSymbol = true; 2295 if ((nMask & SC_COMPILER_C_ODF_RBRACKET) && !(nRefInName & kOpen)) 2296 { 2297 DBG_ASSERT( nRefInName & (kPast | kDefName), 2298 "ScCompiler::NextSymbol: reference: " 2299 "closing bracket ']' without prior sheet name separator '.' violates ODF spec"); 2300 // eaten, not added to pSym 2301 bAddToSymbol = false; 2302 eState = ssStop; 2303 } 2304 else if (cSheetSep == c && nRefInName == 0) 2305 { 2306 // eat it, no sheet name [.A1] 2307 bAddToSymbol = false; 2308 nRefInName |= kPast; 2309 if ('$' == pSrc[0] && '$' == pSrc[1]) 2310 nRefInName |= kMarkAhead; 2311 } 2312 else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName))) 2313 { 2314 // Not in col/row yet. 2315 2316 if (SC_COMPILER_FILE_TAB_SEP == c && (nRefInName & kFileSep)) 2317 nRefInName = 0; 2318 else if ('$' == c && '$' == pSrc[0] && !(nRefInName & kOpen)) 2319 { 2320 nRefInName &= ~kMarkAhead; 2321 if (!(nRefInName & kDefName)) 2322 { 2323 // eaten, not added to pSym (2 chars) 2324 bAddToSymbol = false; 2325 ++pSrc; 2326 nRefInName &= kPast; 2327 nRefInName |= kDefName; 2328 } 2329 else 2330 { 2331 // ScAddress::Parse() will recognize this as 2332 // invalid later. 2333 if (eState != ssSkipReference) 2334 { 2335 *pSym++ = c; 2336 *pSym++ = *pSrc++; 2337 } 2338 bAddToSymbol = false; 2339 } 2340 } 2341 else if (cSheetPrefix == c && nRefInName == 0) 2342 nRefInName |= kDollar; 2343 else if ('\'' == c) 2344 { 2345 // TODO: The conventions' parseExternalName() 2346 // should handle quoted names, but as long as they 2347 // don't remove non-embedded quotes here. 2348 if (!(nRefInName & kName)) 2349 { 2350 nRefInName |= (kOpen | kName); 2351 bAddToSymbol = !(nRefInName & kDefName); 2352 } 2353 else if (!(nRefInName & kOpen)) 2354 { 2355 DBG_ERRORFILE("ScCompiler::NextSymbol: reference: " 2356 "a ''' without the name being enclosed in '...' violates ODF spec"); 2357 } 2358 else if (nRefInName & kQuote) 2359 { 2360 // escaped embedded quote 2361 nRefInName &= ~kQuote; 2362 } 2363 else 2364 { 2365 switch (pSrc[0]) 2366 { 2367 case '\'': 2368 // escapes embedded quote 2369 nRefInName |= kQuote; 2370 break; 2371 case SC_COMPILER_FILE_TAB_SEP: 2372 // sheet name should follow 2373 nRefInName |= kFileSep; 2374 // fallthru 2375 default: 2376 // quote not followed by quote => close 2377 nRefInName |= kClose; 2378 nRefInName &= ~kOpen; 2379 } 2380 bAddToSymbol = !(nRefInName & kDefName); 2381 } 2382 } 2383 else if (cSheetSep == c && !(nRefInName & kOpen)) 2384 { 2385 // unquoted sheet name separator 2386 nRefInName |= kPast; 2387 if ('$' == pSrc[0] && '$' == pSrc[1]) 2388 nRefInName |= kMarkAhead; 2389 } 2390 else if (':' == c && !(nRefInName & kOpen)) 2391 { 2392 DBG_ERRORFILE("ScCompiler::NextSymbol: reference: " 2393 "range operator ':' without prior sheet name separator '.' violates ODF spec"); 2394 nRefInName = 0; 2395 ++mnPredetectedReference; 2396 } 2397 else if (!(nRefInName & kName)) 2398 { 2399 // start unquoted name 2400 nRefInName |= kName; 2401 } 2402 } 2403 else if (':' == c) 2404 { 2405 // range operator 2406 nRefInName = 0; 2407 ++mnPredetectedReference; 2408 } 2409 if (bAddToSymbol && eState != ssSkipReference) 2410 *pSym++ = c; // everything is part of reference 2411 } 2412 break; 2413 case ssStop: 2414 ; // nothing, prevent warning 2415 break; 2416 } 2417 cLast = c; 2418 c = *pSrc; 2419 } 2420 if ( bi18n ) 2421 { 2422 nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces ); 2423 String aSymbol; 2424 mnRangeOpPosInSymbol = -1; 2425 sal_uInt16 nErr = 0; 2426 do 2427 { 2428 bi18n = false; 2429 // special case (e.g. $'sheetname' in OOO A1) 2430 if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' ) 2431 aSymbol += pStart[nSrcPos++]; 2432 2433 ParseResult aRes = pConv->parseAnyToken( aFormula, nSrcPos, pCharClass ); 2434 2435 if ( !aRes.TokenType ) 2436 SetError( nErr = errIllegalChar ); // parsed chars as string 2437 if ( aRes.EndPos <= nSrcPos ) 2438 { // ?!? 2439 SetError( nErr = errIllegalChar ); 2440 nSrcPos = aFormula.Len(); 2441 aSymbol.Erase(); 2442 } 2443 else 2444 { 2445 aSymbol.Append( pStart + nSrcPos, (xub_StrLen)aRes.EndPos - nSrcPos ); 2446 nSrcPos = (xub_StrLen) aRes.EndPos; 2447 c = pStart[nSrcPos]; 2448 if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME ) 2449 { // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1) 2450 bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP); 2451 } 2452 // One range operator restarts parsing for second reference. 2453 if (c == ':' && mnRangeOpPosInSymbol < 0) 2454 { 2455 mnRangeOpPosInSymbol = aSymbol.Len(); 2456 bi18n = true; 2457 } 2458 if ( bi18n ) 2459 aSymbol += pStart[nSrcPos++]; 2460 } 2461 } while ( bi18n && !nErr ); 2462 xub_StrLen nLen = aSymbol.Len(); 2463 if ( nLen >= MAXSTRLEN ) 2464 { 2465 SetError( errStringOverflow ); 2466 nLen = MAXSTRLEN-1; 2467 } 2468 lcl_UnicodeStrNCpy( cSymbol, aSymbol.GetBuffer(), nLen ); 2469 } 2470 else 2471 { 2472 nSrcPos = sal::static_int_cast<xub_StrLen>( pSrc - pStart ); 2473 *pSym = 0; 2474 } 2475 if (mnRangeOpPosInSymbol >= 0 && mnRangeOpPosInSymbol == (pSym-1) - &cSymbol[0]) 2476 { 2477 // This is a trailing range operator, which is nonsense. Will be caught 2478 // in next round. 2479 mnRangeOpPosInSymbol = -1; 2480 *--pSym = 0; 2481 --nSrcPos; 2482 } 2483 if ( bAutoCorrect ) 2484 aCorrectedSymbol = cSymbol; 2485 if (bAutoIntersection && nSpaces > 1) 2486 --nSpaces; // replace '!!' with only one space 2487 return nSpaces; 2488 } 2489 2490 //--------------------------------------------------------------------------- 2491 // Convert symbol to token 2492 //--------------------------------------------------------------------------- 2493 2494 sal_Bool ScCompiler::IsOpCode( const String& rName, bool bInArray ) 2495 { 2496 OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName)); 2497 sal_Bool bFound = (iLook != mxSymbols->getHashMap()->end()); 2498 if (bFound) 2499 { 2500 ScRawToken aToken; 2501 OpCode eOp = iLook->second; 2502 if (bInArray) 2503 { 2504 if (rName.Equals(mxSymbols->getSymbol(ocArrayColSep))) 2505 eOp = ocArrayColSep; 2506 else if (rName.Equals(mxSymbols->getSymbol(ocArrayRowSep))) 2507 eOp = ocArrayRowSep; 2508 } 2509 aToken.SetOpCode(eOp); 2510 pRawToken = aToken.Clone(); 2511 } 2512 else if (mxSymbols->isODFF()) 2513 { 2514 // ODFF names that are not written in the current mapping but to be 2515 // recognized. New names will be written in a future relase, then 2516 // exchange (!) with the names in 2517 // formula/source/core/resource/core_resource.src to be able to still 2518 // read the old names as well. 2519 struct FunctionName 2520 { 2521 const sal_Char* pName; 2522 OpCode eOp; 2523 }; 2524 static const FunctionName aOdffAliases[] = { 2525 // Renamed old names: 2526 // XXX none yet. 2527 // Renamed new names: 2528 { "BINOM.DIST.RANGE", ocB }, // B -> BINOM.DIST.RANGE 2529 { "LEGACY.TDIST", ocTDist }, // TDIST -> LEGACY.TDIST 2530 { "ORG.OPENOFFICE.EASTERSUNDAY", ocEasterSunday } // EASTERSUNDAY -> ORG.OPENOFFICE.EASTERSUNDAY 2531 }; 2532 static const size_t nOdffAliases = sizeof(aOdffAliases) / sizeof(aOdffAliases[0]); 2533 for (size_t i=0; i<nOdffAliases; ++i) 2534 { 2535 if (rName.EqualsIgnoreCaseAscii( aOdffAliases[i].pName)) 2536 { 2537 ScRawToken aToken; 2538 aToken.SetOpCode( aOdffAliases[i].eOp); 2539 pRawToken = aToken.Clone(); 2540 bFound = sal_True; 2541 break; // for 2542 } 2543 } 2544 } 2545 if (!bFound) 2546 { 2547 String aIntName; 2548 if (mxSymbols->hasExternals()) 2549 { 2550 // If symbols are set by filters get mapping to exact name. 2551 ExternalHashMap::const_iterator iExt( 2552 mxSymbols->getExternalHashMap()->find( rName)); 2553 if (iExt != mxSymbols->getExternalHashMap()->end()) 2554 { 2555 if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt).second)) 2556 aIntName = (*iExt).second; 2557 } 2558 if (!aIntName.Len()) 2559 { 2560 // If that isn't found we might continue with rName lookup as a 2561 // last resort by just falling through to FindFunction(), but 2562 // it shouldn't happen if the map was setup correctly. Don't 2563 // waste time and bail out. 2564 return sal_False; 2565 } 2566 } 2567 if (!aIntName.Len()) 2568 { 2569 // Old (deprecated) addins first for legacy. 2570 sal_uInt16 nIndex; 2571 bFound = ScGlobal::GetFuncCollection()->SearchFunc( cSymbol, nIndex); 2572 if (bFound) 2573 { 2574 ScRawToken aToken; 2575 aToken.SetExternal( cSymbol ); 2576 pRawToken = aToken.Clone(); 2577 } 2578 else 2579 // bLocalFirst=sal_False for (English) upper full original name 2580 // (service.function) 2581 aIntName = ScGlobal::GetAddInCollection()->FindFunction( 2582 rName, !mxSymbols->isEnglish()); 2583 } 2584 if (aIntName.Len()) 2585 { 2586 ScRawToken aToken; 2587 aToken.SetExternal( aIntName.GetBuffer() ); // international name 2588 pRawToken = aToken.Clone(); 2589 bFound = sal_True; 2590 } 2591 } 2592 OpCode eOp; 2593 if (bFound && ((eOp = pRawToken->GetOpCode()) == ocSub || eOp == ocNegSub)) 2594 { 2595 bool bShouldBeNegSub = 2596 (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub || 2597 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_BIN_OP) || 2598 eLastOp == ocArrayOpen || 2599 eLastOp == ocArrayColSep || eLastOp == ocArrayRowSep); 2600 if (bShouldBeNegSub && eOp == ocSub) 2601 pRawToken->NewOpCode( ocNegSub ); 2602 //! if ocNegSub had ForceArray we'd have to set it here 2603 else if (!bShouldBeNegSub && eOp == ocNegSub) 2604 pRawToken->NewOpCode( ocSub ); 2605 } 2606 return bFound; 2607 } 2608 2609 sal_Bool ScCompiler::IsOpCode2( const String& rName ) 2610 { 2611 sal_Bool bFound = sal_False; 2612 sal_uInt16 i; 2613 2614 for( i = ocInternalBegin; i <= ocInternalEnd && !bFound; i++ ) 2615 bFound = rName.EqualsAscii( pInternal[ i-ocInternalBegin ] ); 2616 2617 if (bFound) 2618 { 2619 ScRawToken aToken; 2620 aToken.SetOpCode( (OpCode) --i ); 2621 pRawToken = aToken.Clone(); 2622 } 2623 return bFound; 2624 } 2625 2626 sal_Bool ScCompiler::IsValue( const String& rSym ) 2627 { 2628 double fVal; 2629 sal_uInt32 nIndex = ( mxSymbols->isEnglish() ? 2630 pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US ) : 0 ); 2631 // sal_uLong nIndex = 0; 2632 //// sal_uLong nIndex = pDoc->GetFormatTable()->GetStandardIndex(ScGlobal::eLnge); 2633 if (pDoc->GetFormatTable()->IsNumberFormat( rSym, nIndex, fVal ) ) 2634 { 2635 sal_uInt16 nType = pDoc->GetFormatTable()->GetType(nIndex); 2636 2637 // Don't accept 3:3 as time, it is a reference to entire row 3 instead. 2638 // Dates should never be entered directly and automatically converted 2639 // to serial, because the serial would be wrong if null-date changed. 2640 // Usually it wouldn't be accepted anyway because the date separator 2641 // clashed with other separators or operators. 2642 if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE)) 2643 return sal_False; 2644 2645 if (nType == NUMBERFORMAT_LOGICAL) 2646 { 2647 const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos; 2648 while( *p == ' ' ) 2649 p++; 2650 if (*p == '(') 2651 return sal_False; // Boolean function instead. 2652 } 2653 2654 if( aFormula.GetChar(nSrcPos) == '.' ) 2655 // numerical sheet name? 2656 return sal_False; 2657 2658 if( nType == NUMBERFORMAT_TEXT ) 2659 // HACK: number too big! 2660 SetError( errIllegalArgument ); 2661 ScRawToken aToken; 2662 aToken.SetDouble( fVal ); 2663 pRawToken = aToken.Clone(); 2664 return sal_True; 2665 } 2666 else 2667 return sal_False; 2668 } 2669 2670 sal_Bool ScCompiler::IsString() 2671 { 2672 register const sal_Unicode* p = cSymbol; 2673 while ( *p ) 2674 p++; 2675 xub_StrLen nLen = sal::static_int_cast<xub_StrLen>( p - cSymbol - 1 ); 2676 sal_Bool bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"')); 2677 if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1) 2678 { 2679 SetError(errStringOverflow); 2680 return sal_False; 2681 } 2682 if ( bQuote ) 2683 { 2684 cSymbol[nLen] = '\0'; 2685 ScRawToken aToken; 2686 aToken.SetString( cSymbol+1 ); 2687 pRawToken = aToken.Clone(); 2688 return sal_True; 2689 } 2690 return sal_False; 2691 } 2692 2693 2694 sal_Bool ScCompiler::IsPredetectedReference( const String& rName ) 2695 { 2696 // Speedup documents with lots of broken references, e.g. sheet deleted. 2697 xub_StrLen nPos = rName.SearchAscii( "#REF!"); 2698 if (nPos != STRING_NOTFOUND) 2699 { 2700 /* TODO: this may be enhanced by reusing scan information from 2701 * NextSymbol(), the positions of quotes and special characters found 2702 * there for $'sheet'.A1:... could be stored in a vector. We don't 2703 * fully rescan here whether found positions are within single quotes 2704 * for performance reasons. This code does not check for possible 2705 * occurrences of insane "valid" sheet names like 2706 * 'haha.#REF!1fooledyou' and will generate an error on such. */ 2707 if (nPos == 0) 2708 return false; // #REF!.AB42 or #REF!42 or #REF!#REF! 2709 sal_Unicode c = rName.GetChar(nPos-1); // before #REF! 2710 if ('$' == c) 2711 { 2712 if (nPos == 1) 2713 return false; // $#REF!.AB42 or $#REF!42 or $#REF!#REF! 2714 c = rName.GetChar(nPos-2); // before $#REF! 2715 } 2716 sal_Unicode c2 = rName.GetChar(nPos+5); // after #REF! 2717 switch (c) 2718 { 2719 case '.': 2720 if ('$' == c2 || '#' == c2 || ('0' <= c2 && c2 <= '9')) 2721 return false; // sheet.#REF!42 or sheet.#REF!#REF! 2722 break; 2723 case ':': 2724 if (mnPredetectedReference > 1 && 2725 ('.' == c2 || '$' == c2 || '#' == c2 || 2726 ('0' <= c2 && c2 <= '9'))) 2727 return false; // :#REF!.AB42 or :#REF!42 or :#REF!#REF! 2728 break; 2729 default: 2730 if ((('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) && 2731 ((mnPredetectedReference > 1 && ':' == c2) || 0 == c2)) 2732 return false; // AB#REF!: or AB#REF! 2733 } 2734 } 2735 switch (mnPredetectedReference) 2736 { 2737 case 1: 2738 return IsSingleReference( rName); 2739 case 2: 2740 return IsDoubleReference( rName); 2741 } 2742 return false; 2743 } 2744 2745 2746 sal_Bool ScCompiler::IsDoubleReference( const String& rName ) 2747 { 2748 ScRange aRange( aPos, aPos ); 2749 const ScAddress::Details aDetails( pConv->meConv, aPos ); 2750 ScAddress::ExternalInfo aExtInfo; 2751 sal_uInt16 nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks ); 2752 if( nFlags & SCA_VALID ) 2753 { 2754 ScRawToken aToken; 2755 ScComplexRefData aRef; 2756 aRef.InitRange( aRange ); 2757 aRef.Ref1.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 ); 2758 aRef.Ref1.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 ); 2759 aRef.Ref1.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 ); 2760 if ( !(nFlags & SCA_VALID_TAB) ) 2761 aRef.Ref1.SetTabDeleted( sal_True ); // #REF! 2762 aRef.Ref1.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 ); 2763 aRef.Ref2.SetColRel( (nFlags & SCA_COL2_ABSOLUTE) == 0 ); 2764 aRef.Ref2.SetRowRel( (nFlags & SCA_ROW2_ABSOLUTE) == 0 ); 2765 aRef.Ref2.SetTabRel( (nFlags & SCA_TAB2_ABSOLUTE) == 0 ); 2766 if ( !(nFlags & SCA_VALID_TAB2) ) 2767 aRef.Ref2.SetTabDeleted( sal_True ); // #REF! 2768 aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 ); 2769 aRef.CalcRelFromAbs( aPos ); 2770 if (aExtInfo.mbExternal) 2771 { 2772 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 2773 const String* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName); 2774 aToken.SetExternalDoubleRef( 2775 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef); 2776 } 2777 else 2778 { 2779 aToken.SetDoubleReference(aRef); 2780 } 2781 pRawToken = aToken.Clone(); 2782 } 2783 2784 return ( nFlags & SCA_VALID ) != 0; 2785 } 2786 2787 2788 sal_Bool ScCompiler::IsSingleReference( const String& rName ) 2789 { 2790 ScAddress aAddr( aPos ); 2791 const ScAddress::Details aDetails( pConv->meConv, aPos ); 2792 ScAddress::ExternalInfo aExtInfo; 2793 sal_uInt16 nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks ); 2794 // Something must be valid in order to recognize Sheet1.blah or blah.a1 2795 // as a (wrong) reference. 2796 if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) ) 2797 { 2798 ScRawToken aToken; 2799 ScSingleRefData aRef; 2800 aRef.InitAddress( aAddr ); 2801 aRef.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 ); 2802 aRef.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 ); 2803 aRef.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 ); 2804 aRef.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 ); 2805 // the reference is really invalid 2806 if( !( nFlags & SCA_VALID ) ) 2807 { 2808 if( !( nFlags & SCA_VALID_COL ) ) 2809 aRef.nCol = MAXCOL+1; 2810 if( !( nFlags & SCA_VALID_ROW ) ) 2811 aRef.nRow = MAXROW+1; 2812 if( !( nFlags & SCA_VALID_TAB ) ) 2813 aRef.nTab = MAXTAB+3; 2814 nFlags |= SCA_VALID; 2815 } 2816 aRef.CalcRelFromAbs( aPos ); 2817 2818 if (aExtInfo.mbExternal) 2819 { 2820 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 2821 const String* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName); 2822 aToken.SetExternalSingleRef( 2823 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef); 2824 } 2825 else 2826 aToken.SetSingleReference(aRef); 2827 pRawToken = aToken.Clone(); 2828 } 2829 2830 return ( nFlags & SCA_VALID ) != 0; 2831 } 2832 2833 2834 sal_Bool ScCompiler::IsReference( const String& rName ) 2835 { 2836 // Has to be called before IsValue 2837 sal_Unicode ch1 = rName.GetChar(0); 2838 sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' : 2839 ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0) ); 2840 if ( ch1 == cDecSep ) 2841 return sal_False; 2842 // Who was that imbecile introducing '.' as the sheet name separator!?! 2843 if ( CharClass::isAsciiNumeric( ch1 ) ) 2844 { 2845 // Numerical sheet name is valid. 2846 // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01 2847 // Don't create a #REF! of values. But also do not bail out on 2848 // something like 3:3, meaning entire row 3. 2849 do 2850 { 2851 const xub_StrLen nPos = ScGlobal::FindUnquoted( rName, '.'); 2852 if ( nPos == STRING_NOTFOUND ) 2853 { 2854 if (ScGlobal::FindUnquoted( rName, ':') != STRING_NOTFOUND) 2855 break; // may be 3:3, continue as usual 2856 return sal_False; 2857 } 2858 sal_Unicode const * const pTabSep = rName.GetBuffer() + nPos; 2859 sal_Unicode ch2 = pTabSep[1]; // maybe a column identifier 2860 if ( !(ch2 == '$' || CharClass::isAsciiAlpha( ch2 )) ) 2861 return sal_False; 2862 if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e') // E + - digit 2863 && (GetCharTableFlags( pTabSep[2] ) & SC_COMPILER_C_VALUE_EXP) ) 2864 { // #91053# 2865 // If it is an 1.E2 expression check if "1" is an existent sheet 2866 // name. If so, a desired value 1.E2 would have to be entered as 2867 // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to 2868 // require numerical sheet names always being entered quoted, which 2869 // is not desirable (too many 1999, 2000, 2001 sheets in use). 2870 // Furthermore, XML files created with versions prior to SRC640e 2871 // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes() 2872 // and would produce wrong formulas if the conditions here are met. 2873 // If you can live with these restrictions you may remove the 2874 // check and return an unconditional FALSE. 2875 String aTabName( rName.Copy( 0, nPos ) ); 2876 SCTAB nTab; 2877 if ( !pDoc->GetTable( aTabName, nTab ) ) 2878 return sal_False; 2879 // If sheet "1" exists and the expression is 1.E+2 continue as 2880 // usual, the ScRange/ScAddress parser will take care of it. 2881 } 2882 } while(0); 2883 } 2884 2885 if (IsSingleReference( rName)) 2886 return true; 2887 2888 // Though the range operator is handled explicitly, when encountering 2889 // something like Sheet1.A:A we will have to treat it as one entity if it 2890 // doesn't pass as single cell reference. 2891 if (mnRangeOpPosInSymbol > 0) // ":foo" would be nonsense 2892 { 2893 if (IsDoubleReference( rName)) 2894 return true; 2895 // Now try with a symbol up to the range operator, rewind source 2896 // position. 2897 sal_Int32 nLen = mnRangeOpPosInSymbol; 2898 while (cSymbol[++nLen]) 2899 ; 2900 cSymbol[mnRangeOpPosInSymbol] = 0; 2901 nSrcPos -= static_cast<xub_StrLen>(nLen - mnRangeOpPosInSymbol); 2902 mnRangeOpPosInSymbol = -1; 2903 mbRewind = true; 2904 return true; // end all checks 2905 } 2906 else 2907 { 2908 // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness, 2909 // mnRangeOpPosInSymbol did not catch the range operator as it is 2910 // within a quoted name. 2911 switch (pConv->meConv) 2912 { 2913 case FormulaGrammar::CONV_XL_A1: 2914 case FormulaGrammar::CONV_XL_R1C1: 2915 case FormulaGrammar::CONV_XL_OOX: 2916 if (rName.GetChar(0) == '\'' && IsDoubleReference( rName)) 2917 return true; 2918 break; 2919 default: 2920 ; // nothing 2921 } 2922 } 2923 return false; 2924 } 2925 2926 sal_Bool ScCompiler::IsMacro( const String& rName ) 2927 { 2928 String aName( rName); 2929 StarBASIC* pObj = 0; 2930 SfxObjectShell* pDocSh = pDoc->GetDocumentShell(); 2931 2932 SfxApplication* pSfxApp = SFX_APP(); 2933 2934 if( pDocSh )//XXX 2935 pObj = pDocSh->GetBasic(); 2936 else 2937 pObj = pSfxApp->GetBasic(); 2938 2939 // ODFF recommends to store user-defined functions prefixed with "USER.", 2940 // use only unprefixed name if encountered. BASIC doesn't allow '.' in a 2941 // function name so a function "USER.FOO" could not exist, and macro check 2942 // is assigned the lowest priority in function name check. 2943 if (FormulaGrammar::isODFF( GetGrammar()) && aName.EqualsIgnoreCaseAscii( "USER.", 0, 5)) 2944 aName.Erase( 0, 5); 2945 2946 SbxMethod* pMeth = (SbxMethod*) pObj->Find( aName, SbxCLASS_METHOD ); 2947 if( !pMeth ) 2948 { 2949 return sal_False; 2950 } 2951 // It really should be a BASIC function! 2952 if( pMeth->GetType() == SbxVOID 2953 || ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY ) 2954 || !pMeth->ISA(SbMethod) ) 2955 { 2956 return sal_False; 2957 } 2958 ScRawToken aToken; 2959 aToken.SetExternal( aName.GetBuffer() ); 2960 aToken.eOp = ocMacro; 2961 pRawToken = aToken.Clone(); 2962 return sal_True; 2963 } 2964 2965 sal_Bool ScCompiler::IsNamedRange( const String& rUpperName ) 2966 { 2967 // IsNamedRange is called only from NextNewToken, with an upper-case string 2968 2969 sal_uInt16 n; 2970 ScRangeName* pRangeName = pDoc->GetRangeName(); 2971 if (pRangeName->SearchNameUpper( rUpperName, n ) ) 2972 { 2973 ScRangeData* pData = (*pRangeName)[n]; 2974 ScRawToken aToken; 2975 aToken.SetName( pData->GetIndex() ); 2976 pRawToken = aToken.Clone(); 2977 return sal_True; 2978 } 2979 else 2980 return sal_False; 2981 } 2982 2983 bool ScCompiler::IsExternalNamedRange( const String& rSymbol ) 2984 { 2985 /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc) 2986 * correctly parses external named references in OOo, as required per RFE 2987 * #i3740#, just that we can't store them in ODF yet. We will need an OASIS 2988 * spec first. Until then don't pretend to support external names that 2989 * wouldn't survive a save and reload cycle, return false instead. */ 2990 2991 #if 0 2992 if (!pConv) 2993 return false; 2994 2995 String aFile, aName; 2996 if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks)) 2997 return false; 2998 2999 ScRawToken aToken; 3000 if (aFile.Len() > MAXSTRLEN || aName.Len() > MAXSTRLEN) 3001 return false; 3002 3003 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 3004 pRefMgr->convertToAbsName(aFile); 3005 sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile); 3006 if (!pRefMgr->getRangeNameTokens(nFileId, aName).get()) 3007 // range name doesn't exist in the source document. 3008 return false; 3009 3010 const String* pRealName = pRefMgr->getRealRangeName(nFileId, aName); 3011 aToken.SetExternalName(nFileId, pRealName ? *pRealName : aName); 3012 pRawToken = aToken.Clone(); 3013 return true; 3014 #else 3015 (void)rSymbol; 3016 return false; 3017 #endif 3018 } 3019 3020 sal_Bool ScCompiler::IsDBRange( const String& rName ) 3021 { 3022 sal_uInt16 n; 3023 ScDBCollection* pDBColl = pDoc->GetDBCollection(); 3024 if (pDBColl->SearchName( rName, n ) ) 3025 { 3026 ScDBData* pData = (*pDBColl)[n]; 3027 ScRawToken aToken; 3028 aToken.SetName( pData->GetIndex() ); 3029 aToken.eOp = ocDBArea; 3030 pRawToken = aToken.Clone(); 3031 return sal_True; 3032 } 3033 else 3034 return sal_False; 3035 } 3036 3037 sal_Bool ScCompiler::IsColRowName( const String& rName ) 3038 { 3039 sal_Bool bInList = sal_False; 3040 sal_Bool bFound = sal_False; 3041 ScSingleRefData aRef; 3042 String aName( rName ); 3043 DeQuote( aName ); 3044 SCTAB nThisTab = aPos.Tab(); 3045 for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- ) 3046 { // #50300# first check ranges on this sheet, in case of duplicated names 3047 for ( short jRow=0; jRow<2 && !bInList; jRow++ ) 3048 { 3049 ScRangePairList* pRL; 3050 if ( !jRow ) 3051 pRL = pDoc->GetColNameRanges(); 3052 else 3053 pRL = pDoc->GetRowNameRanges(); 3054 for ( ScRangePair* pR = pRL->First(); pR && !bInList; pR = pRL->Next() ) 3055 { 3056 const ScRange& rNameRange = pR->GetRange(0); 3057 if ( jThisTab && !(rNameRange.aStart.Tab() <= nThisTab && 3058 nThisTab <= rNameRange.aEnd.Tab()) ) 3059 continue; // for 3060 ScCellIterator aIter( pDoc, rNameRange ); 3061 for ( ScBaseCell* pCell = aIter.GetFirst(); pCell && !bInList; 3062 pCell = aIter.GetNext() ) 3063 { 3064 // Don't crash if cell (via CompileNameFormula) encounters 3065 // a formula cell without code and 3066 // HasStringData/Interpret/Compile is executed and all that 3067 // recursive.. 3068 // Furthermore, *this* cell won't be touched, since no RPN exists yet. 3069 CellType eType = pCell->GetCellType(); 3070 sal_Bool bOk = sal::static_int_cast<sal_Bool>( (eType == CELLTYPE_FORMULA ? 3071 ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0 3072 && ((ScFormulaCell*)pCell)->aPos != aPos // noIter 3073 : sal_True ) ); 3074 if ( bOk && pCell->HasStringData() ) 3075 { 3076 String aStr; 3077 switch ( eType ) 3078 { 3079 case CELLTYPE_STRING: 3080 ((ScStringCell*)pCell)->GetString( aStr ); 3081 break; 3082 case CELLTYPE_FORMULA: 3083 ((ScFormulaCell*)pCell)->GetString( aStr ); 3084 break; 3085 case CELLTYPE_EDIT: 3086 ((ScEditCell*)pCell)->GetString( aStr ); 3087 break; 3088 case CELLTYPE_NONE: 3089 case CELLTYPE_VALUE: 3090 case CELLTYPE_NOTE: 3091 case CELLTYPE_SYMBOLS: 3092 #if DBG_UTIL 3093 case CELLTYPE_DESTROYED: 3094 #endif 3095 ; // nothing, prevent compiler warning 3096 break; 3097 } 3098 if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) ) 3099 { 3100 aRef.InitFlags(); 3101 aRef.nCol = aIter.GetCol(); 3102 aRef.nRow = aIter.GetRow(); 3103 aRef.nTab = aIter.GetTab(); 3104 if ( !jRow ) 3105 aRef.SetColRel( sal_True ); // ColName 3106 else 3107 aRef.SetRowRel( sal_True ); // RowName 3108 aRef.CalcRelFromAbs( aPos ); 3109 bInList = bFound = sal_True; 3110 } 3111 } 3112 } 3113 } 3114 } 3115 } 3116 if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() ) 3117 { // search in current sheet 3118 long nDistance = 0, nMax = 0; 3119 long nMyCol = (long) aPos.Col(); 3120 long nMyRow = (long) aPos.Row(); 3121 sal_Bool bTwo = sal_False; 3122 ScAddress aOne( 0, 0, aPos.Tab() ); 3123 ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() ); 3124 3125 ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache(); 3126 if ( pNameCache ) 3127 { 3128 // #b6355215# use GetNameOccurences to collect all positions of aName on the sheet 3129 // (only once), similar to the outer part of the loop in the "else" branch. 3130 3131 const ScAutoNameAddresses& rAddresses = pNameCache->GetNameOccurences( aName, aPos.Tab() ); 3132 3133 // Loop through the found positions, similar to the inner part of the loop in the "else" branch. 3134 // The order of addresses in the vector is the same as from ScCellIterator. 3135 3136 ScAutoNameAddresses::const_iterator aEnd(rAddresses.end()); 3137 for ( ScAutoNameAddresses::const_iterator aAdrIter(rAddresses.begin()); aAdrIter != aEnd; ++aAdrIter ) 3138 { 3139 ScAddress aAddress( *aAdrIter ); // cell address with an equal string 3140 3141 if ( bFound ) 3142 { // stop if everything else is further away 3143 if ( nMax < (long)aAddress.Col() ) 3144 break; // aIter 3145 } 3146 if ( aAddress != aPos ) 3147 { 3148 // same treatment as in isEqual case below 3149 3150 SCCOL nCol = aAddress.Col(); 3151 SCROW nRow = aAddress.Row(); 3152 long nC = nMyCol - nCol; 3153 long nR = nMyRow - nRow; 3154 if ( bFound ) 3155 { 3156 long nD = nC * nC + nR * nR; 3157 if ( nD < nDistance ) 3158 { 3159 if ( nC < 0 || nR < 0 ) 3160 { // right or below 3161 bTwo = sal_True; 3162 aTwo.Set( nCol, nRow, aAddress.Tab() ); 3163 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3164 nDistance = nD; 3165 } 3166 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) ) 3167 { 3168 // upper left, only if not further up than the 3169 // current entry and nMyRow is below (CellIter 3170 // runs column-wise) 3171 bTwo = sal_False; 3172 aOne.Set( nCol, nRow, aAddress.Tab() ); 3173 nMax = Max( nMyCol + nC, nMyRow + nR ); 3174 nDistance = nD; 3175 } 3176 } 3177 } 3178 else 3179 { 3180 aOne.Set( nCol, nRow, aAddress.Tab() ); 3181 nDistance = nC * nC + nR * nR; 3182 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3183 } 3184 bFound = sal_True; 3185 } 3186 } 3187 } 3188 else 3189 { 3190 ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) ); 3191 for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() ) 3192 { 3193 if ( bFound ) 3194 { // stop if everything else is further away 3195 if ( nMax < (long)aIter.GetCol() ) 3196 break; // aIter 3197 } 3198 CellType eType = pCell->GetCellType(); 3199 sal_Bool bOk = sal::static_int_cast<sal_Bool>( (eType == CELLTYPE_FORMULA ? 3200 ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0 3201 && ((ScFormulaCell*)pCell)->aPos != aPos // noIter 3202 : sal_True ) ); 3203 if ( bOk && pCell->HasStringData() ) 3204 { 3205 String aStr; 3206 switch ( eType ) 3207 { 3208 case CELLTYPE_STRING: 3209 ((ScStringCell*)pCell)->GetString( aStr ); 3210 break; 3211 case CELLTYPE_FORMULA: 3212 ((ScFormulaCell*)pCell)->GetString( aStr ); 3213 break; 3214 case CELLTYPE_EDIT: 3215 ((ScEditCell*)pCell)->GetString( aStr ); 3216 break; 3217 case CELLTYPE_NONE: 3218 case CELLTYPE_VALUE: 3219 case CELLTYPE_NOTE: 3220 case CELLTYPE_SYMBOLS: 3221 #if DBG_UTIL 3222 case CELLTYPE_DESTROYED: 3223 #endif 3224 ; // nothing, prevent compiler warning 3225 break; 3226 } 3227 if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) ) 3228 { 3229 SCCOL nCol = aIter.GetCol(); 3230 SCROW nRow = aIter.GetRow(); 3231 long nC = nMyCol - nCol; 3232 long nR = nMyRow - nRow; 3233 if ( bFound ) 3234 { 3235 long nD = nC * nC + nR * nR; 3236 if ( nD < nDistance ) 3237 { 3238 if ( nC < 0 || nR < 0 ) 3239 { // right or below 3240 bTwo = sal_True; 3241 aTwo.Set( nCol, nRow, aIter.GetTab() ); 3242 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3243 nDistance = nD; 3244 } 3245 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) ) 3246 { 3247 // upper left, only if not further up than the 3248 // current entry and nMyRow is below (CellIter 3249 // runs column-wise) 3250 bTwo = sal_False; 3251 aOne.Set( nCol, nRow, aIter.GetTab() ); 3252 nMax = Max( nMyCol + nC, nMyRow + nR ); 3253 nDistance = nD; 3254 } 3255 } 3256 } 3257 else 3258 { 3259 aOne.Set( nCol, nRow, aIter.GetTab() ); 3260 nDistance = nC * nC + nR * nR; 3261 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3262 } 3263 bFound = sal_True; 3264 } 3265 } 3266 } 3267 } 3268 3269 if ( bFound ) 3270 { 3271 ScAddress aAdr; 3272 if ( bTwo ) 3273 { 3274 if ( nMyCol >= (long)aOne.Col() && nMyRow >= (long)aOne.Row() ) 3275 aAdr = aOne; // upper left takes precedence 3276 else 3277 { 3278 if ( nMyCol < (long)aOne.Col() ) 3279 { // two to the right 3280 if ( nMyRow >= (long)aTwo.Row() ) 3281 aAdr = aTwo; // directly right 3282 else 3283 aAdr = aOne; 3284 } 3285 else 3286 { // two below or below and right, take the nearest 3287 long nC1 = nMyCol - aOne.Col(); 3288 long nR1 = nMyRow - aOne.Row(); 3289 long nC2 = nMyCol - aTwo.Col(); 3290 long nR2 = nMyRow - aTwo.Row(); 3291 if ( nC1 * nC1 + nR1 * nR1 <= nC2 * nC2 + nR2 * nR2 ) 3292 aAdr = aOne; 3293 else 3294 aAdr = aTwo; 3295 } 3296 } 3297 } 3298 else 3299 aAdr = aOne; 3300 aRef.InitAddress( aAdr ); 3301 if ( (aRef.nRow != MAXROW && pDoc->HasStringData( 3302 aRef.nCol, aRef.nRow + 1, aRef.nTab )) 3303 || (aRef.nRow != 0 && pDoc->HasStringData( 3304 aRef.nCol, aRef.nRow - 1, aRef.nTab )) ) 3305 aRef.SetRowRel( sal_True ); // RowName 3306 else 3307 aRef.SetColRel( sal_True ); // ColName 3308 aRef.CalcRelFromAbs( aPos ); 3309 } 3310 } 3311 if ( bFound ) 3312 { 3313 ScRawToken aToken; 3314 aToken.SetSingleReference( aRef ); 3315 aToken.eOp = ocColRowName; 3316 pRawToken = aToken.Clone(); 3317 return sal_True; 3318 } 3319 else 3320 return sal_False; 3321 } 3322 3323 sal_Bool ScCompiler::IsBoolean( const String& rName ) 3324 { 3325 OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) ); 3326 if( iLook != mxSymbols->getHashMap()->end() && 3327 ((*iLook).second == ocTrue || 3328 (*iLook).second == ocFalse) ) 3329 { 3330 ScRawToken aToken; 3331 aToken.SetOpCode( (*iLook).second ); 3332 pRawToken = aToken.Clone(); 3333 return sal_True; 3334 } 3335 else 3336 return sal_False; 3337 } 3338 3339 //--------------------------------------------------------------------------- 3340 3341 void ScCompiler::AutoCorrectParsedSymbol() 3342 { 3343 xub_StrLen nPos = aCorrectedSymbol.Len(); 3344 if ( nPos ) 3345 { 3346 nPos--; 3347 const sal_Unicode cQuote = '\"'; 3348 const sal_Unicode cx = 'x'; 3349 const sal_Unicode cX = 'X'; 3350 sal_Unicode c1 = aCorrectedSymbol.GetChar( 0 ); 3351 sal_Unicode c2 = aCorrectedSymbol.GetChar( nPos ); 3352 if ( c1 == cQuote && c2 != cQuote ) 3353 { // "... 3354 // What's not a word doesn't belong to it. 3355 // Don't be pedantic: c < 128 should be sufficient here. 3356 while ( nPos && ((aCorrectedSymbol.GetChar(nPos) < 128) && 3357 ((GetCharTableFlags( aCorrectedSymbol.GetChar(nPos) ) & 3358 (SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_DONTCARE)) == 0)) ) 3359 nPos--; 3360 if ( nPos == MAXSTRLEN - 2 ) 3361 aCorrectedSymbol.SetChar( nPos, cQuote ); // '"' the 255th character 3362 else 3363 aCorrectedSymbol.Insert( cQuote, nPos + 1 ); 3364 bCorrected = sal_True; 3365 } 3366 else if ( c1 != cQuote && c2 == cQuote ) 3367 { // ..." 3368 aCorrectedSymbol.Insert( cQuote, 0 ); 3369 bCorrected = sal_True; 3370 } 3371 else if ( nPos == 0 && (c1 == cx || c1 == cX) ) 3372 { // x => * 3373 aCorrectedSymbol = mxSymbols->getSymbol(ocMul); 3374 bCorrected = sal_True; 3375 } 3376 else if ( (GetCharTableFlags( c1 ) & SC_COMPILER_C_CHAR_VALUE) 3377 && (GetCharTableFlags( c2 ) & SC_COMPILER_C_CHAR_VALUE) ) 3378 { 3379 xub_StrLen nXcount; 3380 if ( (nXcount = aCorrectedSymbol.GetTokenCount( cx )) > 1 ) 3381 { // x => * 3382 xub_StrLen nIndex = 0; 3383 sal_Unicode c = mxSymbols->getSymbol(ocMul).GetChar(0); 3384 while ( (nIndex = aCorrectedSymbol.SearchAndReplace( 3385 cx, c, nIndex )) != STRING_NOTFOUND ) 3386 nIndex++; 3387 bCorrected = sal_True; 3388 } 3389 if ( (nXcount = aCorrectedSymbol.GetTokenCount( cX )) > 1 ) 3390 { // X => * 3391 xub_StrLen nIndex = 0; 3392 sal_Unicode c = mxSymbols->getSymbol(ocMul).GetChar(0); 3393 while ( (nIndex = aCorrectedSymbol.SearchAndReplace( 3394 cX, c, nIndex )) != STRING_NOTFOUND ) 3395 nIndex++; 3396 bCorrected = sal_True; 3397 } 3398 } 3399 else 3400 { 3401 String aSymbol( aCorrectedSymbol ); 3402 String aDoc; 3403 xub_StrLen nPosition; 3404 if ( aSymbol.GetChar(0) == '\'' 3405 && ((nPosition = aSymbol.SearchAscii( "'#" )) != STRING_NOTFOUND) ) 3406 { // Split off 'Doc'#, may be d:\... or whatever 3407 aDoc = aSymbol.Copy( 0, nPosition + 2 ); 3408 aSymbol.Erase( 0, nPosition + 2 ); 3409 } 3410 xub_StrLen nRefs = aSymbol.GetTokenCount( ':' ); 3411 sal_Bool bColons; 3412 if ( nRefs > 2 ) 3413 { // duplicated or too many ':'? B:2::C10 => B2:C10 3414 bColons = sal_True; 3415 xub_StrLen nIndex = 0; 3416 String aTmp1( aSymbol.GetToken( 0, ':', nIndex ) ); 3417 xub_StrLen nLen1 = aTmp1.Len(); 3418 String aSym, aTmp2; 3419 sal_Bool bLastAlp, bNextNum; 3420 bLastAlp = bNextNum = sal_True; 3421 xub_StrLen nStrip = 0; 3422 xub_StrLen nCount = nRefs; 3423 for ( xub_StrLen j=1; j<nCount; j++ ) 3424 { 3425 aTmp2 = aSymbol.GetToken( 0, ':', nIndex ); 3426 xub_StrLen nLen2 = aTmp2.Len(); 3427 if ( nLen1 || nLen2 ) 3428 { 3429 if ( nLen1 ) 3430 { 3431 aSym += aTmp1; 3432 bLastAlp = CharClass::isAsciiAlpha( aTmp1 ); 3433 } 3434 if ( nLen2 ) 3435 { 3436 bNextNum = CharClass::isAsciiNumeric( aTmp2 ); 3437 if ( bLastAlp == bNextNum && nStrip < 1 ) 3438 { 3439 // Must be alternating number/string, only 3440 // strip within a reference. 3441 nRefs--; 3442 nStrip++; 3443 } 3444 else 3445 { 3446 xub_StrLen nSymLen = aSym.Len(); 3447 if ( nSymLen 3448 && (aSym.GetChar( nSymLen - 1 ) != ':') ) 3449 aSym += ':'; 3450 nStrip = 0; 3451 } 3452 bLastAlp = !bNextNum; 3453 } 3454 else 3455 { // :: 3456 nRefs--; 3457 if ( nLen1 ) 3458 { // B10::C10 ? append ':' on next round 3459 if ( !bLastAlp && !CharClass::isAsciiNumeric( aTmp1 ) ) 3460 nStrip++; 3461 } 3462 bNextNum = !bLastAlp; 3463 } 3464 aTmp1 = aTmp2; 3465 nLen1 = nLen2; 3466 } 3467 else 3468 nRefs--; 3469 } 3470 aSymbol = aSym; 3471 aSymbol += aTmp1; 3472 } 3473 else 3474 bColons = sal_False; 3475 if ( nRefs && nRefs <= 2 ) 3476 { // reference twisted? 4A => A4 etc. 3477 String aTab[2], aRef[2]; 3478 const ScAddress::Details aDetails( pConv->meConv, aPos ); 3479 if ( nRefs == 2 ) 3480 { 3481 aRef[0] = aSymbol.GetToken( 0, ':' ); 3482 aRef[1] = aSymbol.GetToken( 1, ':' ); 3483 } 3484 else 3485 aRef[0] = aSymbol; 3486 3487 sal_Bool bChanged = sal_False; 3488 sal_Bool bOk = sal_True; 3489 sal_uInt16 nMask = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW; 3490 for ( int j=0; j<nRefs; j++ ) 3491 { 3492 xub_StrLen nTmp = 0; 3493 xub_StrLen nDotPos = STRING_NOTFOUND; 3494 while ( (nTmp = aRef[j].Search( '.', nTmp )) != STRING_NOTFOUND ) 3495 nDotPos = nTmp++; // the last one counts 3496 if ( nDotPos != STRING_NOTFOUND ) 3497 { 3498 aTab[j] = aRef[j].Copy( 0, nDotPos + 1 ); // with '.' 3499 aRef[j].Erase( 0, nDotPos + 1 ); 3500 } 3501 String aOld( aRef[j] ); 3502 String aStr2; 3503 const sal_Unicode* p = aRef[j].GetBuffer(); 3504 while ( *p && CharClass::isAsciiNumeric( *p ) ) 3505 aStr2 += *p++; 3506 aRef[j] = String( p ); 3507 aRef[j] += aStr2; 3508 if ( bColons || aRef[j] != aOld ) 3509 { 3510 bChanged = sal_True; 3511 ScAddress aAdr; 3512 bOk &= ((aAdr.Parse( aRef[j], pDoc, aDetails ) & nMask) == nMask); 3513 } 3514 } 3515 if ( bChanged && bOk ) 3516 { 3517 aCorrectedSymbol = aDoc; 3518 aCorrectedSymbol += aTab[0]; 3519 aCorrectedSymbol += aRef[0]; 3520 if ( nRefs == 2 ) 3521 { 3522 aCorrectedSymbol += ':'; 3523 aCorrectedSymbol += aTab[1]; 3524 aCorrectedSymbol += aRef[1]; 3525 } 3526 bCorrected = sal_True; 3527 } 3528 } 3529 } 3530 } 3531 } 3532 3533 inline bool lcl_UpperAsciiOrI18n( String& rUpper, const String& rOrg, FormulaGrammar::Grammar eGrammar ) 3534 { 3535 if (FormulaGrammar::isODFF( eGrammar )) 3536 { 3537 // ODFF has a defined set of English function names, avoid i18n 3538 // overhead. 3539 rUpper = rOrg; 3540 rUpper.ToUpperAscii(); 3541 return true; 3542 } 3543 else 3544 { 3545 rUpper = ScGlobal::pCharClass->upper( rOrg ); 3546 return false; 3547 } 3548 } 3549 3550 sal_Bool ScCompiler::NextNewToken( bool bInArray ) 3551 { 3552 bool bAllowBooleans = bInArray; 3553 xub_StrLen nSpaces = NextSymbol(bInArray); 3554 3555 #if 0 3556 fprintf( stderr, "NextNewToken '%s' (spaces = %d)\n", 3557 rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr(), nSpaces ); 3558 #endif 3559 3560 if (!cSymbol[0]) 3561 return false; 3562 3563 if( nSpaces ) 3564 { 3565 ScRawToken aToken; 3566 aToken.SetOpCode( ocSpaces ); 3567 aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces ); 3568 if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) ) 3569 { 3570 SetError(errCodeOverflow); 3571 return false; 3572 } 3573 } 3574 3575 // Short cut for references when reading ODF to speedup things. 3576 if (mnPredetectedReference) 3577 { 3578 String aStr( cSymbol); 3579 if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr)) 3580 { 3581 /* TODO: it would be nice to generate a #REF! error here, which 3582 * would need an ocBad token with additional error value. 3583 * FormulaErrorToken wouldn't do because we want to preserve the 3584 * original string containing partial valid address 3585 * information. */ 3586 ScRawToken aToken; 3587 aToken.SetString( aStr.GetBuffer() ); 3588 aToken.NewOpCode( ocBad ); 3589 pRawToken = aToken.Clone(); 3590 } 3591 return true; 3592 } 3593 3594 if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 && 3595 !bAutoCorrect ) 3596 { // #101100# special case to speed up broken [$]#REF documents 3597 /* FIXME: ISERROR(#REF!) would be valid and sal_True and the formula to 3598 * be processed as usual. That would need some special treatment, 3599 * also in NextSymbol() because of possible combinations of 3600 * #REF!.#REF!#REF! parts. In case of reading ODF that is all 3601 * handled by IsPredetectedReference(), this case here remains for 3602 * manual/API input. */ 3603 String aBad( aFormula.Copy( nSrcPos-1 ) ); 3604 eLastOp = pArr->AddBad( aBad )->GetOpCode(); 3605 return false; 3606 } 3607 3608 if( IsString() ) 3609 return true; 3610 3611 bool bMayBeFuncName; 3612 bool bAsciiNonAlnum; // operators, separators, ... 3613 if ( cSymbol[0] < 128 ) 3614 { 3615 bMayBeFuncName = CharClass::isAsciiAlpha( cSymbol[0] ); 3616 bAsciiNonAlnum = !bMayBeFuncName && !CharClass::isAsciiDigit( cSymbol[0] ); 3617 } 3618 else 3619 { 3620 String aTmpStr( cSymbol[0] ); 3621 bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 ); 3622 bAsciiNonAlnum = false; 3623 } 3624 if ( bMayBeFuncName ) 3625 { 3626 // a function name must be followed by a parenthesis 3627 const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos; 3628 while( *p == ' ' ) 3629 p++; 3630 bMayBeFuncName = ( *p == '(' ); 3631 } 3632 3633 #if 0 3634 fprintf( stderr, "Token '%s'\n", 3635 rtl::OUStringToOString( aUpper, RTL_TEXTENCODING_UTF8 ).getStr() ); 3636 #endif 3637 3638 // #42016# Italian ARCTAN.2 resulted in #REF! => IsOpcode() before 3639 // IsReference(). 3640 3641 String aUpper; 3642 3643 do 3644 { 3645 mbRewind = false; 3646 const String aOrg( cSymbol ); 3647 3648 if (bAsciiNonAlnum && IsOpCode( aOrg, bInArray )) 3649 return true; 3650 3651 aUpper.Erase(); 3652 bool bAsciiUpper = false; 3653 if (bMayBeFuncName) 3654 { 3655 bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); 3656 if (IsOpCode( aUpper, bInArray )) 3657 return true; 3658 } 3659 3660 // Column 'DM' ("Deutsche Mark", German currency) couldn't be 3661 // referred => IsReference() before IsValue(). 3662 // Preserve case of file names in external references. 3663 if (IsReference( aOrg )) 3664 { 3665 if (mbRewind) // Range operator, but no direct reference. 3666 continue; // do; up to range operator. 3667 return true; 3668 } 3669 3670 if (!aUpper.Len()) 3671 bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); 3672 3673 // IsBoolean() before IsValue() to catch inline bools without the kludge 3674 // for inline arrays. 3675 if (bAllowBooleans && IsBoolean( aUpper )) 3676 return true; 3677 3678 if (IsValue( aUpper )) 3679 return true; 3680 3681 // User defined names and such do need i18n upper also in ODF. 3682 if (bAsciiUpper) 3683 aUpper = ScGlobal::pCharClass->upper( aOrg ); 3684 3685 if (IsNamedRange( aUpper )) 3686 return true; 3687 // Preserve case of file names in external references. 3688 if (IsExternalNamedRange( aOrg )) 3689 return true; 3690 if (IsDBRange( aUpper )) 3691 return true; 3692 if (IsColRowName( aUpper )) 3693 return true; 3694 if (bMayBeFuncName && IsMacro( aUpper )) 3695 return true; 3696 if (bMayBeFuncName && IsOpCode2( aUpper )) 3697 return true; 3698 3699 } while (mbRewind); 3700 3701 if ( mbExtendedErrorDetection ) 3702 { 3703 // set an error and end compilation 3704 SetError( errNoName ); 3705 return false; 3706 } 3707 3708 // Provide single token information and continue. Do not set an error, that 3709 // would prematurely end compilation. Simple unknown names are handled by 3710 // the interpreter. 3711 ScGlobal::pCharClass->toLower( aUpper ); 3712 ScRawToken aToken; 3713 aToken.SetString( aUpper.GetBuffer() ); 3714 aToken.NewOpCode( ocBad ); 3715 pRawToken = aToken.Clone(); 3716 if ( bAutoCorrect ) 3717 AutoCorrectParsedSymbol(); 3718 return true; 3719 } 3720 3721 void ScCompiler::CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp ) 3722 { 3723 bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL; 3724 sal_uInt16 nExpectedCount = bExternal ? 2 : 1; 3725 DBG_ASSERT( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" ); 3726 if( pArr->GetLen() == nExpectedCount ) 3727 { 3728 FormulaToken** ppTokens = pArr->GetArray(); 3729 // string tokens expected, GetString() will assert if token type is wrong 3730 rFormula = ppTokens[ 0 ]->GetString(); 3731 if( bExternal ) 3732 rFormulaNmsp = ppTokens[ 1 ]->GetString(); 3733 } 3734 } 3735 3736 ScTokenArray* ScCompiler::CompileString( const String& rFormula ) 3737 { 3738 #if 0 3739 fprintf( stderr, "CompileString '%s'\n", 3740 rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); 3741 #endif 3742 3743 OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" ); 3744 if( meGrammar == FormulaGrammar::GRAM_EXTERNAL ) 3745 SetGrammar( FormulaGrammar::GRAM_PODF ); 3746 3747 ScTokenArray aArr; 3748 pArr = &aArr; 3749 aFormula = rFormula; 3750 3751 aFormula.EraseLeadingChars(); 3752 aFormula.EraseTrailingChars(); 3753 nSrcPos = 0; 3754 bCorrected = sal_False; 3755 if ( bAutoCorrect ) 3756 { 3757 aCorrectedFormula.Erase(); 3758 aCorrectedSymbol.Erase(); 3759 } 3760 sal_uInt8 nForced = 0; // ==formula forces recalc even if cell is not visible 3761 if( aFormula.GetChar(nSrcPos) == '=' ) 3762 { 3763 nSrcPos++; 3764 nForced++; 3765 if ( bAutoCorrect ) 3766 aCorrectedFormula += '='; 3767 } 3768 if( aFormula.GetChar(nSrcPos) == '=' ) 3769 { 3770 nSrcPos++; 3771 nForced++; 3772 if ( bAutoCorrect ) 3773 aCorrectedFormula += '='; 3774 } 3775 struct FunctionStack 3776 { 3777 OpCode eOp; 3778 short nPar; 3779 }; 3780 // FunctionStack only used if PODF! 3781 bool bPODF = FormulaGrammar::isPODF( meGrammar); 3782 const size_t nAlloc = 512; 3783 FunctionStack aFuncs[ nAlloc ]; 3784 FunctionStack* pFunctionStack = (bPODF && rFormula.Len() > nAlloc ? 3785 new FunctionStack[ rFormula.Len() ] : &aFuncs[0]); 3786 pFunctionStack[0].eOp = ocNone; 3787 pFunctionStack[0].nPar = 0; 3788 size_t nFunction = 0; 3789 short nBrackets = 0; 3790 bool bInArray = false; 3791 eLastOp = ocOpen; 3792 while( NextNewToken( bInArray ) ) 3793 { 3794 const OpCode eOp = pRawToken->GetOpCode(); 3795 switch (eOp) 3796 { 3797 case ocOpen: 3798 { 3799 ++nBrackets; 3800 if (bPODF) 3801 { 3802 ++nFunction; 3803 pFunctionStack[ nFunction ].eOp = eLastOp; 3804 pFunctionStack[ nFunction ].nPar = 0; 3805 } 3806 } 3807 break; 3808 case ocClose: 3809 { 3810 if( !nBrackets ) 3811 { 3812 SetError( errPairExpected ); 3813 if ( bAutoCorrect ) 3814 { 3815 bCorrected = sal_True; 3816 aCorrectedSymbol.Erase(); 3817 } 3818 } 3819 else 3820 nBrackets--; 3821 if (bPODF && nFunction) 3822 --nFunction; 3823 } 3824 break; 3825 case ocSep: 3826 { 3827 if (bPODF) 3828 ++pFunctionStack[ nFunction ].nPar; 3829 } 3830 break; 3831 case ocArrayOpen: 3832 { 3833 if( bInArray ) 3834 SetError( errNestedArray ); 3835 else 3836 bInArray = true; 3837 // Don't count following column separator as parameter separator. 3838 if (bPODF) 3839 { 3840 ++nFunction; 3841 pFunctionStack[ nFunction ].eOp = eOp; 3842 pFunctionStack[ nFunction ].nPar = 0; 3843 } 3844 } 3845 break; 3846 case ocArrayClose: 3847 { 3848 if( bInArray ) 3849 { 3850 bInArray = false; 3851 } 3852 else 3853 { 3854 SetError( errPairExpected ); 3855 if ( bAutoCorrect ) 3856 { 3857 bCorrected = sal_True; 3858 aCorrectedSymbol.Erase(); 3859 } 3860 } 3861 if (bPODF && nFunction) 3862 --nFunction; 3863 } 3864 default: 3865 break; 3866 } 3867 if( (eLastOp == ocSep || 3868 eLastOp == ocArrayRowSep || 3869 eLastOp == ocArrayColSep || 3870 eLastOp == ocArrayOpen) && 3871 (eOp == ocSep || 3872 eOp == ocArrayRowSep || 3873 eOp == ocArrayColSep || 3874 eOp == ocArrayClose) ) 3875 { 3876 // FIXME: should we check for known functions with optional empty 3877 // args so the correction dialog can do better? 3878 if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) ) 3879 { 3880 SetError(errCodeOverflow); break; 3881 } 3882 } 3883 if (bPODF) 3884 { 3885 /* TODO: for now this is the only PODF adapter. If there were more, 3886 * factor this out. */ 3887 // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th. 3888 if (eOp == ocSep && 3889 pFunctionStack[ nFunction ].eOp == ocAddress && 3890 pFunctionStack[ nFunction ].nPar == 3) 3891 { 3892 if (!static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep,ocSep)) || 3893 !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0))) 3894 { 3895 SetError(errCodeOverflow); break; 3896 } 3897 ++pFunctionStack[ nFunction ].nPar; 3898 } 3899 } 3900 FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( pRawToken->CreateToken()); 3901 if (!pNewToken) 3902 { 3903 SetError(errCodeOverflow); break; 3904 } 3905 else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush && 3906 pNewToken->GetType() == svSingleRef) 3907 static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos); 3908 eLastOp = pRawToken->GetOpCode(); 3909 if ( bAutoCorrect ) 3910 aCorrectedFormula += aCorrectedSymbol; 3911 } 3912 if ( mbCloseBrackets ) 3913 { 3914 if( bInArray ) 3915 { 3916 FormulaByteToken aToken( ocArrayClose ); 3917 if( !pArr->AddToken( aToken ) ) 3918 { 3919 SetError(errCodeOverflow); 3920 } 3921 else if ( bAutoCorrect ) 3922 aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose); 3923 } 3924 3925 FormulaByteToken aToken( ocClose ); 3926 while( nBrackets-- ) 3927 { 3928 if( !pArr->AddToken( aToken ) ) 3929 { 3930 SetError(errCodeOverflow); break; 3931 } 3932 if ( bAutoCorrect ) 3933 aCorrectedFormula += mxSymbols->getSymbol(ocClose); 3934 } 3935 } 3936 if ( nForced >= 2 ) 3937 pArr->SetRecalcModeForced(); 3938 3939 if (pFunctionStack != &aFuncs[0]) 3940 delete [] pFunctionStack; 3941 3942 // remember pArr, in case a subsequent CompileTokenArray() is executed. 3943 ScTokenArray* pNew = new ScTokenArray( aArr ); 3944 pArr = pNew; 3945 return pNew; 3946 } 3947 3948 3949 ScTokenArray* ScCompiler::CompileString( const String& rFormula, const String& rFormulaNmsp ) 3950 { 3951 DBG_ASSERT( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || (rFormulaNmsp.Len() == 0), 3952 "ScCompiler::CompileString - unexpected formula namespace for internal grammar" ); 3953 if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try 3954 { 3955 ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool(); 3956 uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW ); 3957 table::CellAddress aReferencePos; 3958 ScUnoConversion::FillApiAddress( aReferencePos, aPos ); 3959 uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos ); 3960 ScTokenArray aTokenArray; 3961 if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) ) 3962 { 3963 // remember pArr, in case a subsequent CompileTokenArray() is executed. 3964 ScTokenArray* pNew = new ScTokenArray( aTokenArray ); 3965 pArr = pNew; 3966 return pNew; 3967 } 3968 } 3969 catch( uno::Exception& ) 3970 { 3971 } 3972 // no success - fallback to some internal grammar and hope the best 3973 return CompileString( rFormula ); 3974 } 3975 3976 3977 sal_Bool ScCompiler::HandleRange() 3978 { 3979 ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() ); 3980 if (pRangeData) 3981 { 3982 sal_uInt16 nErr = pRangeData->GetErrCode(); 3983 if( nErr ) 3984 SetError( errNoName ); 3985 else if ( !bCompileForFAP ) 3986 { 3987 ScTokenArray* pNew; 3988 // #35168# put named formula into parentheses. 3989 // #37680# But only if there aren't any yet, parenthetical 3990 // ocSep doesn't work, e.g. SUM((...;...)) 3991 // or if not directly between ocSep/parenthesis, 3992 // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes, 3993 // in short: if it isn't a self-contained expression. 3994 FormulaToken* p1 = pArr->PeekPrevNoSpaces(); 3995 FormulaToken* p2 = pArr->PeekNextNoSpaces(); 3996 OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) ); 3997 OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) ); 3998 sal_Bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen); 3999 sal_Bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose); 4000 sal_Bool bAddPair = !(bBorder1 && bBorder2); 4001 if ( bAddPair ) 4002 { 4003 pNew = new ScTokenArray(); 4004 pNew->AddOpCode( ocClose ); 4005 PushTokenArray( pNew, sal_True ); 4006 pNew->Reset(); 4007 } 4008 pNew = pRangeData->GetCode()->Clone(); 4009 PushTokenArray( pNew, sal_True ); 4010 if( pRangeData->HasReferences() ) 4011 { 4012 SetRelNameReference(); 4013 MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); 4014 } 4015 pNew->Reset(); 4016 if ( bAddPair ) 4017 { 4018 pNew = new ScTokenArray(); 4019 pNew->AddOpCode( ocOpen ); 4020 PushTokenArray( pNew, sal_True ); 4021 pNew->Reset(); 4022 } 4023 return GetToken(); 4024 } 4025 } 4026 else 4027 SetError(errNoName); 4028 return sal_True; 4029 } 4030 // ----------------------------------------------------------------------------- 4031 sal_Bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken) 4032 { 4033 // Handle external range names. 4034 switch (_aToken.GetType()) 4035 { 4036 case svExternalSingleRef: 4037 case svExternalDoubleRef: 4038 pArr->IncrementRefs(); 4039 break; 4040 case svExternalName: 4041 { 4042 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 4043 const String* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex()); 4044 if (!pFile) 4045 { 4046 SetError(errNoName); 4047 return true; 4048 } 4049 4050 const String& rName = _aToken.GetString(); 4051 ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens( 4052 _aToken.GetIndex(), rName, &aPos); 4053 4054 if (!xNew) 4055 { 4056 SetError(errNoName); 4057 return true; 4058 } 4059 4060 ScTokenArray* pNew = xNew->Clone(); 4061 PushTokenArray( pNew, true); 4062 if (pNew->GetNextReference() != NULL) 4063 { 4064 SetRelNameReference(); 4065 MoveRelWrap(MAXCOL, MAXROW); 4066 } 4067 pNew->Reset(); 4068 return GetToken(); 4069 } 4070 default: 4071 DBG_ERROR("Wrong type for external reference!"); 4072 return sal_False; 4073 } 4074 return sal_True; 4075 } 4076 4077 4078 //--------------------------------------------------------------------------- 4079 4080 4081 //--------------------------------------------------------------------------- 4082 // Append token to RPN code 4083 //--------------------------------------------------------------------------- 4084 4085 4086 //----------------------------------------------------------------------------- 4087 4088 //--------------------------------------------------------------------------- 4089 // RPN creation by recursion 4090 //--------------------------------------------------------------------------- 4091 4092 4093 4094 //----------------------------------------------------------------------------- 4095 4096 sal_Bool ScCompiler::HasModifiedRange() 4097 { 4098 pArr->Reset(); 4099 for ( FormulaToken* t = pArr->Next(); t; t = pArr->Next() ) 4100 { 4101 OpCode eOpCode = t->GetOpCode(); 4102 if ( eOpCode == ocName ) 4103 { 4104 ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4105 4106 if (pRangeData && pRangeData->IsModified()) 4107 return sal_True; 4108 } 4109 else if ( eOpCode == ocDBArea ) 4110 { 4111 ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex()); 4112 4113 if (pDBData && pDBData->IsModified()) 4114 return sal_True; 4115 } 4116 } 4117 return sal_False; 4118 } 4119 4120 4121 //--------------------------------------------------------------------------- 4122 4123 template< typename T, typename S > 4124 S lcl_adjval( S& n, T pos, T max, sal_Bool bRel ) 4125 { 4126 max++; 4127 if( bRel ) 4128 n = sal::static_int_cast<S>( n + pos ); 4129 if( n < 0 ) 4130 n = sal::static_int_cast<S>( n + max ); 4131 else if( n >= max ) 4132 n = sal::static_int_cast<S>( n - max ); 4133 if( bRel ) 4134 n = sal::static_int_cast<S>( n - pos ); 4135 return n; 4136 } 4137 4138 // reference of named range with relative references 4139 4140 void ScCompiler::SetRelNameReference() 4141 { 4142 pArr->Reset(); 4143 for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t; 4144 t = static_cast<ScToken*>(pArr->GetNextReference()) ) 4145 { 4146 ScSingleRefData& rRef1 = t->GetSingleRef(); 4147 if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() ) 4148 rRef1.SetRelName( sal_True ); 4149 if ( t->GetType() == svDoubleRef ) 4150 { 4151 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4152 if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() ) 4153 rRef2.SetRelName( sal_True ); 4154 } 4155 } 4156 } 4157 4158 // Wrap-adjust relative references of a RangeName to current position, 4159 // don't call for other token arrays! 4160 void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow ) 4161 { 4162 pArr->Reset(); 4163 for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t; 4164 t = static_cast<ScToken*>(pArr->GetNextReference()) ) 4165 { 4166 if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) 4167 ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); 4168 else 4169 ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, t->GetDoubleRef() ); 4170 } 4171 } 4172 4173 // static 4174 // Wrap-adjust relative references of a RangeName to current position, 4175 // don't call for other token arrays! 4176 void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos, 4177 SCCOL nMaxCol, SCROW nMaxRow ) 4178 { 4179 rArr.Reset(); 4180 for( ScToken* t = static_cast<ScToken*>(rArr.GetNextReference()); t; 4181 t = static_cast<ScToken*>(rArr.GetNextReference()) ) 4182 { 4183 if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) 4184 ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); 4185 else 4186 ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, t->GetDoubleRef() ); 4187 } 4188 } 4189 4190 ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode, 4191 const ScAddress& rOldPos, const ScRange& r, 4192 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 4193 sal_Bool& rChanged, sal_Bool& rRefSizeChanged ) 4194 { 4195 rChanged = rRefSizeChanged = sal_False; 4196 if ( eUpdateRefMode == URM_COPY ) 4197 { // Normally nothing has to be done here since RelRefs are used, also 4198 // SharedFormulas don't need any special handling, except if they 4199 // wrapped around sheet borders. 4200 // #67383# But ColRowName tokens pointing to a ColRow header which was 4201 // copied along with this formula need to be updated to point to the 4202 // copied header instead of the old position's new intersection. 4203 ScToken* t; 4204 pArr->Reset(); 4205 while( (t = static_cast<ScToken*>(pArr->GetNextColRowName())) != NULL ) 4206 { 4207 ScSingleRefData& rRef = t->GetSingleRef(); 4208 rRef.CalcAbsIfRel( rOldPos ); 4209 ScAddress aNewRef( rRef.nCol + nDx, rRef.nRow + nDy, rRef.nTab + nDz ); 4210 if ( r.In( aNewRef ) ) 4211 { // yes, this is URM_MOVE 4212 if ( ScRefUpdate::Update( pDoc, URM_MOVE, aPos, 4213 r, nDx, nDy, nDz, 4214 SingleDoubleRefModifier( rRef ).Ref() ) 4215 != UR_NOTHING 4216 ) 4217 rChanged = sal_True; 4218 } 4219 } 4220 // Check for SharedFormulas. 4221 ScRangeData* pRangeData = NULL; 4222 pArr->Reset(); 4223 for( FormulaToken* j = pArr->GetNextName(); j && !pRangeData; 4224 j = pArr->GetNextName() ) 4225 { 4226 if( j->GetOpCode() == ocName ) 4227 { 4228 ScRangeData* pName = pDoc->GetRangeName()->FindIndex( j->GetIndex() ); 4229 if (pName && pName->HasType(RT_SHARED)) 4230 pRangeData = pName; 4231 } 4232 } 4233 // Check SharedFormulas for wraps. 4234 if (pRangeData) 4235 { 4236 ScRangeData* pName = pRangeData; 4237 pRangeData = NULL; 4238 pArr->Reset(); 4239 for( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()); t && !pRangeData; 4240 t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) 4241 { 4242 sal_Bool bRelName = (t->GetType() == svSingleRef ? 4243 t->GetSingleRef().IsRelName() : 4244 (t->GetDoubleRef().Ref1.IsRelName() || 4245 t->GetDoubleRef().Ref2.IsRelName())); 4246 if (bRelName) 4247 { 4248 t->CalcAbsIfRel( rOldPos); 4249 sal_Bool bValid = (t->GetType() == svSingleRef ? 4250 t->GetSingleRef().Valid() : 4251 t->GetDoubleRef().Valid()); 4252 // If the reference isn't valid, copying the formula 4253 // wrapped it. Replace SharedFormula. 4254 if (!bValid) 4255 { 4256 pRangeData = pName; 4257 rChanged = sal_True; 4258 } 4259 } 4260 } 4261 } 4262 return pRangeData; 4263 } 4264 else 4265 { 4266 /* 4267 * Set SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE to 1 if we wanted to preserve as 4268 * many shared formulas as possible instead of replacing them with direct code. 4269 * Note that this may produce shared formula usage Excel doesn't understand, 4270 * which would have to be adapted for in the export filter. Advisable as a long 4271 * term goal, since it could decrease memory footprint. 4272 */ 4273 #define SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 0 4274 ScRangeData* pRangeData = NULL; 4275 ScToken* t; 4276 pArr->Reset(); 4277 while( (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL ) 4278 { 4279 if( t->GetOpCode() == ocName ) 4280 { 4281 ScRangeData* pName = pDoc->GetRangeName()->FindIndex( t->GetIndex() ); 4282 if (pName && pName->HasType(RT_SHAREDMOD)) 4283 { 4284 pRangeData = pName; // maybe need a replacement of shared with own code 4285 #if ! SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4286 rChanged = sal_True; 4287 #endif 4288 } 4289 } 4290 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4291 { 4292 t->CalcAbsIfRel( rOldPos ); 4293 switch (t->GetType()) 4294 { 4295 case svExternalSingleRef: 4296 case svExternalDoubleRef: 4297 // External references never change their positioning 4298 // nor point to parts that will be removed or expanded. 4299 // In fact, calling ScRefUpdate::Update() for URM_MOVE 4300 // may have negative side effects. Simply adapt 4301 // relative references to the new position. 4302 t->CalcRelFromAbs( aPos); 4303 break; 4304 case svSingleRef: 4305 { 4306 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, 4307 aPos, r, nDx, nDy, nDz, 4308 SingleDoubleRefModifier( 4309 t->GetSingleRef()).Ref()) 4310 != UR_NOTHING) 4311 rChanged = sal_True; 4312 } 4313 break; 4314 default: 4315 { 4316 ScComplexRefData& rRef = t->GetDoubleRef(); 4317 SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol; 4318 SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow; 4319 SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab; 4320 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, 4321 aPos, r, nDx, nDy, nDz, 4322 t->GetDoubleRef()) != UR_NOTHING) 4323 { 4324 rChanged = sal_True; 4325 if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols || 4326 rRef.Ref2.nRow - rRef.Ref1.nRow != nRows || 4327 rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs) 4328 rRefSizeChanged = sal_True; 4329 } 4330 } 4331 } 4332 } 4333 } 4334 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4335 sal_Bool bEasyShared, bPosInRange; 4336 if ( !pRangeData ) 4337 bEasyShared = bPosInRange = sal_False; 4338 else 4339 { 4340 bEasyShared = sal_True; 4341 bPosInRange = r.In( eUpdateRefMode == URM_MOVE ? aPos : rOldPos ); 4342 } 4343 #endif 4344 pArr->Reset(); 4345 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4346 { 4347 if ( t->GetRef() != 1 ) 4348 { 4349 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4350 bEasyShared = sal_False; 4351 #endif 4352 } 4353 else 4354 { // if nRefCnt>1 it's already updated in token code 4355 if ( t->GetType() == svSingleRef ) 4356 { 4357 ScSingleRefData& rRef = t->GetSingleRef(); 4358 SingleDoubleRefModifier aMod( rRef ); 4359 if ( rRef.IsRelName() ) 4360 { 4361 ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, aMod.Ref() ); 4362 rChanged = sal_True; 4363 } 4364 else 4365 { 4366 aMod.Ref().CalcAbsIfRel( rOldPos ); 4367 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, 4368 r, nDx, nDy, nDz, aMod.Ref() ) 4369 != UR_NOTHING 4370 ) 4371 rChanged = sal_True; 4372 } 4373 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4374 if ( bEasyShared ) 4375 { 4376 const ScSingleRefData& rSRD = aMod.Ref().Ref1; 4377 ScAddress aRef( rSRD.nCol, rSRD.nRow, rSRD.nTab ); 4378 if ( r.In( aRef ) != bPosInRange ) 4379 bEasyShared = sal_False; 4380 } 4381 #endif 4382 } 4383 else 4384 { 4385 ScComplexRefData& rRef = t->GetDoubleRef(); 4386 SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol; 4387 SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow; 4388 SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab; 4389 if ( rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName() ) 4390 { 4391 ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, rRef ); 4392 rChanged = sal_True; 4393 } 4394 else 4395 { 4396 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, 4397 r, nDx, nDy, nDz, rRef ) 4398 != UR_NOTHING 4399 ) 4400 { 4401 rChanged = sal_True; 4402 if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols || 4403 rRef.Ref2.nRow - rRef.Ref1.nRow != nRows || 4404 rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs) 4405 { 4406 rRefSizeChanged = sal_True; 4407 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4408 bEasyShared = sal_False; 4409 #endif 4410 } 4411 } 4412 } 4413 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4414 if ( bEasyShared ) 4415 { 4416 ScRange aRef( rRef.Ref1.nCol, rRef.Ref1.nRow, 4417 rRef.Ref1.nTab, rRef.Ref2.nCol, rRef.Ref2.nRow, 4418 rRef.Ref2.nTab ); 4419 if ( r.In( aRef ) != bPosInRange ) 4420 bEasyShared = sal_False; 4421 } 4422 #endif 4423 } 4424 } 4425 } 4426 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4427 if ( pRangeData ) 4428 { 4429 if ( bEasyShared ) 4430 pRangeData = 0; 4431 else 4432 rChanged = sal_True; 4433 } 4434 #endif 4435 #undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4436 return pRangeData; 4437 } 4438 } 4439 4440 sal_Bool ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode, 4441 const ScRange& r, 4442 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 4443 sal_Bool& rChanged, sal_Bool bSharedFormula) 4444 { 4445 sal_Bool bRelRef = sal_False; // set if relative reference 4446 rChanged = sal_False; 4447 pArr->Reset(); 4448 ScToken* t; 4449 while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL ) 4450 { 4451 SingleDoubleRefModifier aMod( *t ); 4452 ScComplexRefData& rRef = aMod.Ref(); 4453 bRelRef = rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || 4454 rRef.Ref1.IsTabRel(); 4455 if (!bRelRef && t->GetType() == svDoubleRef) 4456 bRelRef = rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || 4457 rRef.Ref2.IsTabRel(); 4458 bool bUpdate = !rRef.Ref1.IsColRel() || !rRef.Ref1.IsRowRel() || 4459 !rRef.Ref1.IsTabRel(); 4460 if (!bUpdate && t->GetType() == svDoubleRef) 4461 bUpdate = !rRef.Ref2.IsColRel() || !rRef.Ref2.IsRowRel() || 4462 !rRef.Ref2.IsTabRel(); 4463 if (!bSharedFormula) 4464 { 4465 // We cannot update names with sheet-relative references, they may 4466 // be used on other sheets as well and the resulting reference 4467 // would be wrong. This is a dilemma if col/row would need to be 4468 // updated for the current usage. 4469 // TODO: seems the only way out of this would be to not allow 4470 // relative sheet references and have sheet-local names that can be 4471 // copied along with sheets. 4472 bUpdate = bUpdate && !rRef.Ref1.IsTabRel() && !rRef.Ref2.IsTabRel(); 4473 } 4474 if (bUpdate) 4475 { 4476 rRef.CalcAbsIfRel( aPos); 4477 if (ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, r, 4478 nDx, nDy, nDz, rRef, ScRefUpdate::ABSOLUTE) 4479 != UR_NOTHING ) 4480 rChanged = sal_True; 4481 } 4482 } 4483 return bRelRef; 4484 } 4485 4486 4487 void ScCompiler::UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode, 4488 const ScAddress& rOldPos, const ScRange& r, 4489 SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 4490 { 4491 if ( eUpdateRefMode == URM_COPY ) 4492 return ; 4493 else 4494 { 4495 ScToken* t; 4496 pArr->Reset(); 4497 while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL ) 4498 { 4499 if( t->GetType() != svIndex ) // it may be a DB area!!! 4500 { 4501 t->CalcAbsIfRel( rOldPos ); 4502 // Absolute references have been already adjusted in the named 4503 // shared formula itself prior to breaking the shared formula 4504 // and calling this function. Don't readjust them again. 4505 SingleDoubleRefModifier aMod( *t ); 4506 ScComplexRefData& rRef = aMod.Ref(); 4507 ScComplexRefData aBkp = rRef; 4508 ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, 4509 r, nDx, nDy, nDz, rRef ); 4510 // restore absolute parts 4511 if ( !aBkp.Ref1.IsColRel() ) 4512 { 4513 rRef.Ref1.nCol = aBkp.Ref1.nCol; 4514 rRef.Ref1.nRelCol = aBkp.Ref1.nRelCol; 4515 rRef.Ref1.SetColDeleted( aBkp.Ref1.IsColDeleted() ); 4516 } 4517 if ( !aBkp.Ref1.IsRowRel() ) 4518 { 4519 rRef.Ref1.nRow = aBkp.Ref1.nRow; 4520 rRef.Ref1.nRelRow = aBkp.Ref1.nRelRow; 4521 rRef.Ref1.SetRowDeleted( aBkp.Ref1.IsRowDeleted() ); 4522 } 4523 if ( !aBkp.Ref1.IsTabRel() ) 4524 { 4525 rRef.Ref1.nTab = aBkp.Ref1.nTab; 4526 rRef.Ref1.nRelTab = aBkp.Ref1.nRelTab; 4527 rRef.Ref1.SetTabDeleted( aBkp.Ref1.IsTabDeleted() ); 4528 } 4529 if ( t->GetType() == svDoubleRef ) 4530 { 4531 if ( !aBkp.Ref2.IsColRel() ) 4532 { 4533 rRef.Ref2.nCol = aBkp.Ref2.nCol; 4534 rRef.Ref2.nRelCol = aBkp.Ref2.nRelCol; 4535 rRef.Ref2.SetColDeleted( aBkp.Ref2.IsColDeleted() ); 4536 } 4537 if ( !aBkp.Ref2.IsRowRel() ) 4538 { 4539 rRef.Ref2.nRow = aBkp.Ref2.nRow; 4540 rRef.Ref2.nRelRow = aBkp.Ref2.nRelRow; 4541 rRef.Ref2.SetRowDeleted( aBkp.Ref2.IsRowDeleted() ); 4542 } 4543 if ( !aBkp.Ref2.IsTabRel() ) 4544 { 4545 rRef.Ref2.nTab = aBkp.Ref2.nTab; 4546 rRef.Ref2.nRelTab = aBkp.Ref2.nRelTab; 4547 rRef.Ref2.SetTabDeleted( aBkp.Ref2.IsTabDeleted() ); 4548 } 4549 } 4550 } 4551 } 4552 } 4553 } 4554 4555 4556 ScRangeData* ScCompiler::UpdateInsertTab( SCTAB nTable, sal_Bool bIsName ) 4557 { 4558 ScRangeData* pRangeData = NULL; 4559 SCTAB nPosTab = aPos.Tab(); // _after_ incremented! 4560 SCTAB nOldPosTab = ((nPosTab > nTable) ? (nPosTab - 1) : nPosTab); 4561 sal_Bool bIsRel = sal_False; 4562 ScToken* t; 4563 pArr->Reset(); 4564 if (bIsName) 4565 t = static_cast<ScToken*>(pArr->GetNextReference()); 4566 else 4567 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4568 while( t ) 4569 { 4570 if( t->GetOpCode() == ocName ) 4571 { 4572 if (!bIsName) 4573 { 4574 ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4575 if (pName && pName->HasType(RT_SHAREDMOD)) 4576 pRangeData = pName; 4577 } 4578 } 4579 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4580 { 4581 if ( !(bIsName && t->GetSingleRef().IsTabRel()) ) 4582 { // of names only adjust absolute references 4583 ScSingleRefData& rRef = t->GetSingleRef(); 4584 if ( rRef.IsTabRel() ) 4585 { 4586 rRef.nTab = rRef.nRelTab + nOldPosTab; 4587 if ( rRef.nTab < 0 ) 4588 rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap 4589 } 4590 if (nTable <= rRef.nTab) 4591 ++rRef.nTab; 4592 rRef.nRelTab = rRef.nTab - nPosTab; 4593 } 4594 else 4595 bIsRel = sal_True; 4596 if ( t->GetType() == svDoubleRef ) 4597 { 4598 if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) ) 4599 { // of names only adjust absolute references 4600 ScSingleRefData& rRef = t->GetDoubleRef().Ref2; 4601 if ( rRef.IsTabRel() ) 4602 { 4603 rRef.nTab = rRef.nRelTab + nOldPosTab; 4604 if ( rRef.nTab < 0 ) 4605 rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap 4606 } 4607 if (nTable <= rRef.nTab) 4608 ++rRef.nTab; 4609 rRef.nRelTab = rRef.nTab - nPosTab; 4610 } 4611 else 4612 bIsRel = sal_True; 4613 } 4614 if ( bIsName && bIsRel ) 4615 pRangeData = (ScRangeData*) this; // not dereferenced in rangenam 4616 } 4617 if (bIsName) 4618 t = static_cast<ScToken*>(pArr->GetNextReference()); 4619 else 4620 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4621 } 4622 if ( !bIsName ) 4623 { 4624 pArr->Reset(); 4625 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4626 { 4627 if ( t->GetRef() == 1 ) 4628 { 4629 ScSingleRefData& rRef1 = t->GetSingleRef(); 4630 if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) ) 4631 { // of names only adjust absolute references 4632 if ( rRef1.IsTabRel() ) 4633 { 4634 rRef1.nTab = rRef1.nRelTab + nOldPosTab; 4635 if ( rRef1.nTab < 0 ) 4636 rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + pDoc->GetTableCount() ); // was a wrap 4637 } 4638 if (nTable <= rRef1.nTab) 4639 ++rRef1.nTab; 4640 rRef1.nRelTab = rRef1.nTab - nPosTab; 4641 } 4642 if ( t->GetType() == svDoubleRef ) 4643 { 4644 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4645 if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) ) 4646 { // of names only adjust absolute references 4647 if ( rRef2.IsTabRel() ) 4648 { 4649 rRef2.nTab = rRef2.nRelTab + nOldPosTab; 4650 if ( rRef2.nTab < 0 ) 4651 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + pDoc->GetTableCount() ); // was a wrap 4652 } 4653 if (nTable <= rRef2.nTab) 4654 ++rRef2.nTab; 4655 rRef2.nRelTab = rRef2.nTab - nPosTab; 4656 } 4657 } 4658 } 4659 } 4660 } 4661 return pRangeData; 4662 } 4663 4664 ScRangeData* ScCompiler::UpdateDeleteTab(SCTAB nTable, sal_Bool /* bIsMove */, sal_Bool bIsName, 4665 sal_Bool& rChanged) 4666 { 4667 ScRangeData* pRangeData = NULL; 4668 SCTAB nTab, nTab2; 4669 SCTAB nPosTab = aPos.Tab(); // _after_ decremented! 4670 SCTAB nOldPosTab = ((nPosTab >= nTable) ? (nPosTab + 1) : nPosTab); 4671 rChanged = sal_False; 4672 sal_Bool bIsRel = sal_False; 4673 ScToken* t; 4674 pArr->Reset(); 4675 if (bIsName) 4676 t = static_cast<ScToken*>(pArr->GetNextReference()); 4677 else 4678 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4679 while( t ) 4680 { 4681 if( t->GetOpCode() == ocName ) 4682 { 4683 if (!bIsName) 4684 { 4685 ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4686 if (pName && pName->HasType(RT_SHAREDMOD)) 4687 pRangeData = pName; 4688 } 4689 rChanged = sal_True; 4690 } 4691 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4692 { 4693 if ( !(bIsName && t->GetSingleRef().IsTabRel()) ) 4694 { // of names only adjust absolute references 4695 ScSingleRefData& rRef = t->GetSingleRef(); 4696 if ( rRef.IsTabRel() ) 4697 nTab = rRef.nTab = rRef.nRelTab + nOldPosTab; 4698 else 4699 nTab = rRef.nTab; 4700 if ( nTable < nTab ) 4701 { 4702 rRef.nTab = nTab - 1; 4703 rChanged = sal_True; 4704 } 4705 else if ( nTable == nTab ) 4706 { 4707 if ( t->GetType() == svDoubleRef ) 4708 { 4709 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4710 if ( rRef2.IsTabRel() ) 4711 nTab2 = rRef2.nRelTab + nOldPosTab; 4712 else 4713 nTab2 = rRef2.nTab; 4714 if ( nTab == nTab2 4715 || (nTab+1) >= pDoc->GetTableCount() ) 4716 { 4717 rRef.nTab = MAXTAB+1; 4718 rRef.SetTabDeleted( sal_True ); 4719 } 4720 // else: nTab later points to what's nTable+1 now 4721 // => area shrunk 4722 } 4723 else 4724 { 4725 rRef.nTab = MAXTAB+1; 4726 rRef.SetTabDeleted( sal_True ); 4727 } 4728 rChanged = sal_True; 4729 } 4730 rRef.nRelTab = rRef.nTab - nPosTab; 4731 } 4732 else 4733 bIsRel = sal_True; 4734 if ( t->GetType() == svDoubleRef ) 4735 { 4736 if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) ) 4737 { // of names only adjust absolute references 4738 ScSingleRefData& rRef = t->GetDoubleRef().Ref2; 4739 if ( rRef.IsTabRel() ) 4740 nTab = rRef.nTab = rRef.nRelTab + nOldPosTab; 4741 else 4742 nTab = rRef.nTab; 4743 if ( nTable < nTab ) 4744 { 4745 rRef.nTab = nTab - 1; 4746 rChanged = sal_True; 4747 } 4748 else if ( nTable == nTab ) 4749 { 4750 if ( !t->GetDoubleRef().Ref1.IsTabDeleted() ) 4751 rRef.nTab = nTab - 1; // shrink area 4752 else 4753 { 4754 rRef.nTab = MAXTAB+1; 4755 rRef.SetTabDeleted( sal_True ); 4756 } 4757 rChanged = sal_True; 4758 } 4759 rRef.nRelTab = rRef.nTab - nPosTab; 4760 } 4761 else 4762 bIsRel = sal_True; 4763 } 4764 if ( bIsName && bIsRel ) 4765 pRangeData = (ScRangeData*) this; // not dereferenced in rangenam 4766 } 4767 if (bIsName) 4768 t = static_cast<ScToken*>(pArr->GetNextReference()); 4769 else 4770 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4771 } 4772 if ( !bIsName ) 4773 { 4774 pArr->Reset(); 4775 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4776 { 4777 if ( t->GetRef() == 1 ) 4778 { 4779 ScSingleRefData& rRef1 = t->GetSingleRef(); 4780 if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) ) 4781 { // of names only adjust absolute references 4782 if ( rRef1.IsTabRel() ) 4783 nTab = rRef1.nTab = rRef1.nRelTab + nOldPosTab; 4784 else 4785 nTab = rRef1.nTab; 4786 if ( nTable < nTab ) 4787 { 4788 rRef1.nTab = nTab - 1; 4789 rChanged = sal_True; 4790 } 4791 else if ( nTable == nTab ) 4792 { 4793 if ( t->GetType() == svDoubleRef ) 4794 { 4795 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4796 if ( rRef2.IsTabRel() ) 4797 nTab2 = rRef2.nRelTab + nOldPosTab; 4798 else 4799 nTab2 = rRef2.nTab; 4800 if ( nTab == nTab2 4801 || (nTab+1) >= pDoc->GetTableCount() ) 4802 { 4803 rRef1.nTab = MAXTAB+1; 4804 rRef1.SetTabDeleted( sal_True ); 4805 } 4806 // else: nTab later points to what's nTable+1 now 4807 // => area shrunk 4808 } 4809 else 4810 { 4811 rRef1.nTab = MAXTAB+1; 4812 rRef1.SetTabDeleted( sal_True ); 4813 } 4814 rChanged = sal_True; 4815 } 4816 rRef1.nRelTab = rRef1.nTab - nPosTab; 4817 } 4818 if ( t->GetType() == svDoubleRef ) 4819 { 4820 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4821 if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) ) 4822 { // of names only adjust absolute references 4823 if ( rRef2.IsTabRel() ) 4824 nTab = rRef2.nTab = rRef2.nRelTab + nOldPosTab; 4825 else 4826 nTab = rRef2.nTab; 4827 if ( nTable < nTab ) 4828 { 4829 rRef2.nTab = nTab - 1; 4830 rChanged = sal_True; 4831 } 4832 else if ( nTable == nTab ) 4833 { 4834 if ( !rRef1.IsTabDeleted() ) 4835 rRef2.nTab = nTab - 1; // shrink area 4836 else 4837 { 4838 rRef2.nTab = MAXTAB+1; 4839 rRef2.SetTabDeleted( sal_True ); 4840 } 4841 rChanged = sal_True; 4842 } 4843 rRef2.nRelTab = rRef2.nTab - nPosTab; 4844 } 4845 } 4846 } 4847 } 4848 } 4849 return pRangeData; 4850 } 4851 4852 // aPos.Tab() must be already adjusted! 4853 ScRangeData* ScCompiler::UpdateMoveTab( SCTAB nOldTab, SCTAB nNewTab, 4854 sal_Bool bIsName ) 4855 { 4856 ScRangeData* pRangeData = NULL; 4857 SCsTAB nTab; 4858 4859 SCTAB nStart, nEnd; 4860 short nDir; // direction in which others move 4861 if ( nOldTab < nNewTab ) 4862 { 4863 nDir = -1; 4864 nStart = nOldTab; 4865 nEnd = nNewTab; 4866 } 4867 else 4868 { 4869 nDir = 1; 4870 nStart = nNewTab; 4871 nEnd = nOldTab; 4872 } 4873 SCTAB nPosTab = aPos.Tab(); // current sheet 4874 SCTAB nOldPosTab; // previously it was this one 4875 if ( nPosTab == nNewTab ) 4876 nOldPosTab = nOldTab; // look, it's me! 4877 else if ( nPosTab < nStart || nEnd < nPosTab ) 4878 nOldPosTab = nPosTab; // wasn't moved 4879 else 4880 nOldPosTab = nPosTab - nDir; // moved by one 4881 4882 sal_Bool bIsRel = sal_False; 4883 ScToken* t; 4884 pArr->Reset(); 4885 if (bIsName) 4886 t = static_cast<ScToken*>(pArr->GetNextReference()); 4887 else 4888 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4889 while( t ) 4890 { 4891 if( t->GetOpCode() == ocName ) 4892 { 4893 if (!bIsName) 4894 { 4895 ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4896 if (pName && pName->HasType(RT_SHAREDMOD)) 4897 pRangeData = pName; 4898 } 4899 } 4900 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4901 { 4902 ScSingleRefData& rRef1 = t->GetSingleRef(); 4903 if ( !(bIsName && rRef1.IsTabRel()) ) 4904 { // of names only adjust absolute references 4905 if ( rRef1.IsTabRel() ) 4906 nTab = rRef1.nRelTab + nOldPosTab; 4907 else 4908 nTab = rRef1.nTab; 4909 if ( nTab == nOldTab ) 4910 rRef1.nTab = nNewTab; 4911 else if ( nStart <= nTab && nTab <= nEnd ) 4912 rRef1.nTab = nTab + nDir; 4913 rRef1.nRelTab = rRef1.nTab - nPosTab; 4914 } 4915 else 4916 bIsRel = sal_True; 4917 if ( t->GetType() == svDoubleRef ) 4918 { 4919 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4920 if ( !(bIsName && rRef2.IsTabRel()) ) 4921 { // of names only adjust absolute references 4922 if ( rRef2.IsTabRel() ) 4923 nTab = rRef2.nRelTab + nOldPosTab; 4924 else 4925 nTab = rRef2.nTab; 4926 if ( nTab == nOldTab ) 4927 rRef2.nTab = nNewTab; 4928 else if ( nStart <= nTab && nTab <= nEnd ) 4929 rRef2.nTab = nTab + nDir; 4930 rRef2.nRelTab = rRef2.nTab - nPosTab; 4931 } 4932 else 4933 bIsRel = sal_True; 4934 SCsTAB nTab1, nTab2; 4935 if ( rRef1.IsTabRel() ) 4936 nTab1 = rRef1.nRelTab + nPosTab; 4937 else 4938 nTab1 = rRef1.nTab; 4939 if ( rRef2.IsTabRel() ) 4940 nTab2 = rRef2.nRelTab + nPosTab; 4941 else 4942 nTab2 = rRef1.nTab; 4943 if ( nTab2 < nTab1 ) 4944 { // PutInOrder 4945 rRef1.nTab = nTab2; 4946 rRef2.nTab = nTab1; 4947 rRef1.nRelTab = rRef1.nTab - nPosTab; 4948 rRef2.nRelTab = rRef2.nTab - nPosTab; 4949 } 4950 } 4951 if ( bIsName && bIsRel ) 4952 pRangeData = (ScRangeData*) this; // not dereferenced in rangenam 4953 } 4954 if (bIsName) 4955 t = static_cast<ScToken*>(pArr->GetNextReference()); 4956 else 4957 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4958 } 4959 if ( !bIsName ) 4960 { 4961 SCsTAB nMaxTabMod = (SCsTAB) pDoc->GetTableCount(); 4962 pArr->Reset(); 4963 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4964 { 4965 if ( t->GetRef() == 1 ) 4966 { 4967 ScSingleRefData& rRef1 = t->GetSingleRef(); 4968 if ( rRef1.IsRelName() && rRef1.IsTabRel() ) 4969 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx 4970 nTab = rRef1.nRelTab + nPosTab; 4971 if ( nTab < 0 ) 4972 nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod ); 4973 else if ( nTab > nMaxTab ) 4974 nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod ); 4975 rRef1.nRelTab = nTab - nPosTab; 4976 } 4977 else 4978 { 4979 if ( rRef1.IsTabRel() ) 4980 nTab = rRef1.nRelTab + nOldPosTab; 4981 else 4982 nTab = rRef1.nTab; 4983 if ( nTab == nOldTab ) 4984 rRef1.nTab = nNewTab; 4985 else if ( nStart <= nTab && nTab <= nEnd ) 4986 rRef1.nTab = nTab + nDir; 4987 rRef1.nRelTab = rRef1.nTab - nPosTab; 4988 } 4989 if( t->GetType() == svDoubleRef ) 4990 { 4991 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4992 if ( rRef2.IsRelName() && rRef2.IsTabRel() ) 4993 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx 4994 nTab = rRef2.nRelTab + nPosTab; 4995 if ( nTab < 0 ) 4996 nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod ); 4997 else if ( nTab > nMaxTab ) 4998 nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod ); 4999 rRef2.nRelTab = nTab - nPosTab; 5000 } 5001 else 5002 { 5003 if ( rRef2.IsTabRel() ) 5004 nTab = rRef2.nRelTab + nOldPosTab; 5005 else 5006 nTab = rRef2.nTab; 5007 if ( nTab == nOldTab ) 5008 rRef2.nTab = nNewTab; 5009 else if ( nStart <= nTab && nTab <= nEnd ) 5010 rRef2.nTab = nTab + nDir; 5011 rRef2.nRelTab = rRef2.nTab - nPosTab; 5012 } 5013 SCsTAB nTab1, nTab2; 5014 if ( rRef1.IsTabRel() ) 5015 nTab1 = rRef1.nRelTab + nPosTab; 5016 else 5017 nTab1 = rRef1.nTab; 5018 if ( rRef2.IsTabRel() ) 5019 nTab2 = rRef2.nRelTab + nPosTab; 5020 else 5021 nTab2 = rRef1.nTab; 5022 if ( nTab2 < nTab1 ) 5023 { // PutInOrder 5024 rRef1.nTab = nTab2; 5025 rRef2.nTab = nTab1; 5026 rRef1.nRelTab = rRef1.nTab - nPosTab; 5027 rRef2.nRelTab = rRef2.nTab - nPosTab; 5028 } 5029 } 5030 } 5031 } 5032 } 5033 return pRangeData; 5034 } 5035 5036 5037 void ScCompiler::CreateStringFromExternal(rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP) 5038 { 5039 FormulaToken* t = pTokenP; 5040 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 5041 switch (t->GetType()) 5042 { 5043 case svExternalName: 5044 { 5045 const String *pStr = pRefMgr->getExternalFileName(t->GetIndex()); 5046 String aFileName = pStr ? *pStr : ScGlobal::GetRscString(STR_NO_NAME_REF); 5047 rBuffer.append(pConv->makeExternalNameStr( aFileName, t->GetString())); 5048 } 5049 break; 5050 case svExternalSingleRef: 5051 pConv->makeExternalRefStr( 5052 rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetSingleRef(), pRefMgr); 5053 break; 5054 case svExternalDoubleRef: 5055 pConv->makeExternalRefStr( 5056 rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetDoubleRef(), pRefMgr); 5057 break; 5058 default: 5059 // warning, not error, otherwise we may end up with a never 5060 // ending message box loop if this was the cursor cell to be redrawn. 5061 DBG_WARNING("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef"); 5062 } 5063 } 5064 5065 void ScCompiler::CreateStringFromMatrix( rtl::OUStringBuffer& rBuffer, 5066 FormulaToken* pTokenP) 5067 { 5068 const ScMatrix* pMatrix = static_cast<ScToken*>(pTokenP)->GetMatrix(); 5069 SCSIZE nC, nMaxC, nR, nMaxR; 5070 5071 pMatrix->GetDimensions( nMaxC, nMaxR); 5072 5073 rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) ); 5074 for( nR = 0 ; nR < nMaxR ; nR++) 5075 { 5076 if( nR > 0) 5077 { 5078 rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) ); 5079 } 5080 5081 for( nC = 0 ; nC < nMaxC ; nC++) 5082 { 5083 if( nC > 0) 5084 { 5085 rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) ); 5086 } 5087 5088 if( pMatrix->IsValue( nC, nR ) ) 5089 { 5090 ScMatValType nType; 5091 const ScMatrixValue* pVal = pMatrix->Get( nC, nR, nType); 5092 5093 if( nType == SC_MATVAL_BOOLEAN ) 5094 AppendBoolean( rBuffer, pVal->GetBoolean() ); 5095 else 5096 { 5097 sal_uInt16 nErr = pVal->GetError(); 5098 if( nErr ) 5099 rBuffer.append( ScGlobal::GetErrorString( nErr ) ); 5100 else 5101 AppendDouble( rBuffer, pVal->fVal ); 5102 } 5103 } 5104 else if( pMatrix->IsEmpty( nC, nR ) ) 5105 ; 5106 else if( pMatrix->IsString( nC, nR ) ) 5107 AppendString( rBuffer, pMatrix->GetString( nC, nR ) ); 5108 } 5109 } 5110 rBuffer.append( mxSymbols->getSymbol(ocArrayClose) ); 5111 } 5112 5113 void ScCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP) 5114 { 5115 const OpCode eOp = _pTokenP->GetOpCode(); 5116 ScSingleRefData& rRef = static_cast<ScToken*>(_pTokenP)->GetSingleRef(); 5117 ScComplexRefData aRef; 5118 aRef.Ref1 = aRef.Ref2 = rRef; 5119 if ( eOp == ocColRowName ) 5120 { 5121 rRef.CalcAbsIfRel( aPos ); 5122 if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) ) 5123 { 5124 String aStr; 5125 pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr ); 5126 EnQuote( aStr ); 5127 rBuffer.append(aStr); 5128 } 5129 else 5130 { 5131 rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); 5132 pConv->MakeRefStr (rBuffer, *this, aRef, sal_True ); 5133 } 5134 } 5135 else 5136 pConv->MakeRefStr( rBuffer, *this, aRef, sal_True ); 5137 } 5138 // ----------------------------------------------------------------------------- 5139 void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP) 5140 { 5141 pConv->MakeRefStr( rBuffer, *this, static_cast<ScToken*>(_pTokenP)->GetDoubleRef(), sal_False ); 5142 } 5143 // ----------------------------------------------------------------------------- 5144 void ScCompiler::CreateStringFromIndex(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP) 5145 { 5146 const OpCode eOp = _pTokenP->GetOpCode(); 5147 rtl::OUStringBuffer aBuffer; 5148 switch ( eOp ) 5149 { 5150 case ocName: 5151 { 5152 ScRangeData* pData = pDoc->GetRangeName()->FindIndex(_pTokenP->GetIndex()); 5153 if (pData) 5154 { 5155 if (pData->HasType(RT_SHARED)) 5156 pData->UpdateSymbol( aBuffer, aPos, GetGrammar()); 5157 else 5158 aBuffer.append(pData->GetName()); 5159 } 5160 } 5161 break; 5162 case ocDBArea: 5163 { 5164 ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(_pTokenP->GetIndex()); 5165 if (pDBData) 5166 aBuffer.append(pDBData->GetName()); 5167 } 5168 break; 5169 default: 5170 ; // nothing 5171 } 5172 if ( aBuffer.getLength() ) 5173 rBuffer.append(aBuffer); 5174 else 5175 rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); 5176 } 5177 // ----------------------------------------------------------------------------- 5178 void ScCompiler::LocalizeString( String& rName ) 5179 { 5180 ScGlobal::GetAddInCollection()->LocalizeString( rName ); 5181 } 5182 // ----------------------------------------------------------------------------- 5183 sal_Bool ScCompiler::IsImportingXML() const 5184 { 5185 return pDoc->IsImportingXML(); 5186 } 5187 5188 // Put quotes around string if non-alphanumeric characters are contained, 5189 // quote characters contained within are escaped by '\\'. 5190 sal_Bool ScCompiler::EnQuote( String& rStr ) 5191 { 5192 sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.Len() ); 5193 if ( !CharClass::isNumericType( nType ) 5194 && CharClass::isAlphaNumericType( nType ) ) 5195 return sal_False; 5196 5197 xub_StrLen nPos = 0; 5198 while ( (nPos = rStr.Search( '\'', nPos)) != STRING_NOTFOUND ) 5199 { 5200 rStr.Insert( '\\', nPos ); 5201 nPos += 2; 5202 } 5203 rStr.Insert( '\'', 0 ); 5204 rStr += '\''; 5205 return sal_True; 5206 } 5207 5208 sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const 5209 { 5210 return pConv->getSpecialSymbol(eType); 5211 } 5212 5213 void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const 5214 { 5215 // All known AddIn functions. 5216 sheet::FormulaOpCodeMapEntry aEntry; 5217 aEntry.Token.OpCode = ocExternal; 5218 5219 ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection(); 5220 const long nCount = pColl->GetFuncCount(); 5221 for (long i=0; i < nCount; ++i) 5222 { 5223 const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i); 5224 if (pFuncData) 5225 { 5226 if ( _bIsEnglish ) 5227 { 5228 String aName; 5229 if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName)) 5230 aEntry.Name = aName; 5231 else 5232 aEntry.Name = pFuncData->GetUpperName(); 5233 } 5234 else 5235 aEntry.Name = pFuncData->GetUpperLocal(); 5236 aEntry.Token.Data <<= ::rtl::OUString( pFuncData->GetOriginalName()); 5237 _rVec.push_back( aEntry); 5238 } 5239 } 5240 // FIXME: what about those old non-UNO AddIns? 5241 } 5242 // ----------------------------------------------------------------------------- 5243 sal_Bool ScCompiler::HandleSingleRef() 5244 { 5245 ScSingleRefData& rRef = static_cast<ScToken*>((FormulaToken*)pToken)->GetSingleRef(); 5246 rRef.CalcAbsIfRel( aPos ); 5247 if ( !rRef.Valid() ) 5248 { 5249 SetError( errNoRef ); 5250 return sal_True; 5251 } 5252 SCCOL nCol = rRef.nCol; 5253 SCROW nRow = rRef.nRow; 5254 SCTAB nTab = rRef.nTab; 5255 ScAddress aLook( nCol, nRow, nTab ); 5256 sal_Bool bColName = rRef.IsColRel(); 5257 SCCOL nMyCol = aPos.Col(); 5258 SCROW nMyRow = aPos.Row(); 5259 sal_Bool bInList = sal_False; 5260 sal_Bool bValidName = sal_False; 5261 ScRangePairList* pRL = (bColName ? 5262 pDoc->GetColNameRanges() : pDoc->GetRowNameRanges()); 5263 ScRange aRange; 5264 for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() ) 5265 { 5266 if ( pR->GetRange(0).In( aLook ) ) 5267 { 5268 bInList = bValidName = sal_True; 5269 aRange = pR->GetRange(1); 5270 if ( bColName ) 5271 { 5272 aRange.aStart.SetCol( nCol ); 5273 aRange.aEnd.SetCol( nCol ); 5274 } 5275 else 5276 { 5277 aRange.aStart.SetRow( nRow ); 5278 aRange.aEnd.SetRow( nRow ); 5279 } 5280 break; // for 5281 } 5282 } 5283 if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() ) 5284 { // automagically or created by copying and NamePos isn't in list 5285 sal_Bool bString = pDoc->HasStringData( nCol, nRow, nTab ); 5286 if ( !bString && !pDoc->GetCell( aLook ) ) 5287 bString = sal_True; // empty cell is ok 5288 if ( bString ) 5289 { //! coresponds with ScInterpreter::ScColRowNameAuto() 5290 bValidName = sal_True; 5291 if ( bColName ) 5292 { // ColName 5293 SCROW nStartRow = nRow + 1; 5294 if ( nStartRow > MAXROW ) 5295 nStartRow = MAXROW; 5296 SCROW nMaxRow = MAXROW; 5297 if ( nMyCol == nCol ) 5298 { // formula cell in same column 5299 if ( nMyRow == nStartRow ) 5300 { // take remainder under name cell 5301 nStartRow++; 5302 if ( nStartRow > MAXROW ) 5303 nStartRow = MAXROW; 5304 } 5305 else if ( nMyRow > nStartRow ) 5306 { // from name cell down to formula cell 5307 nMaxRow = nMyRow - 1; 5308 } 5309 } 5310 for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() ) 5311 { // next defined ColNameRange below limits row 5312 const ScRange& rRange = pR->GetRange(1); 5313 if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() ) 5314 { // identical column range 5315 SCROW nTmp = rRange.aStart.Row(); 5316 if ( nStartRow < nTmp && nTmp <= nMaxRow ) 5317 nMaxRow = nTmp - 1; 5318 } 5319 } 5320 aRange.aStart.Set( nCol, nStartRow, nTab ); 5321 aRange.aEnd.Set( nCol, nMaxRow, nTab ); 5322 } 5323 else 5324 { // RowName 5325 SCCOL nStartCol = nCol + 1; 5326 if ( nStartCol > MAXCOL ) 5327 nStartCol = MAXCOL; 5328 SCCOL nMaxCol = MAXCOL; 5329 if ( nMyRow == nRow ) 5330 { // formula cell in same row 5331 if ( nMyCol == nStartCol ) 5332 { // take remainder right from name cell 5333 nStartCol++; 5334 if ( nStartCol > MAXCOL ) 5335 nStartCol = MAXCOL; 5336 } 5337 else if ( nMyCol > nStartCol ) 5338 { // from name cell right to formula cell 5339 nMaxCol = nMyCol - 1; 5340 } 5341 } 5342 for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() ) 5343 { // next defined RowNameRange to the right limits column 5344 const ScRange& rRange = pR->GetRange(1); 5345 if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() ) 5346 { // identical row range 5347 SCCOL nTmp = rRange.aStart.Col(); 5348 if ( nStartCol < nTmp && nTmp <= nMaxCol ) 5349 nMaxCol = nTmp - 1; 5350 } 5351 } 5352 aRange.aStart.Set( nStartCol, nRow, nTab ); 5353 aRange.aEnd.Set( nMaxCol, nRow, nTab ); 5354 } 5355 } 5356 } 5357 if ( bValidName ) 5358 { 5359 // And now the magic to distinguish between a range and a single 5360 // cell thereof, which is picked position-dependent of the formula 5361 // cell. If a direct neighbor is a binary operator (ocAdd, ...) a 5362 // SingleRef matching the column/row of the formula cell is 5363 // generated. A ocColRowName or ocIntersect as a neighbor results 5364 // in a range. Special case: if label is valid for a single cell, a 5365 // position independent SingleRef is generated. 5366 sal_Bool bSingle = (aRange.aStart == aRange.aEnd); 5367 sal_Bool bFound; 5368 if ( bSingle ) 5369 bFound = sal_True; 5370 else 5371 { 5372 FormulaToken* p1 = pArr->PeekPrevNoSpaces(); 5373 FormulaToken* p2 = pArr->PeekNextNoSpaces(); 5374 // begin/end of a formula => single 5375 OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd ); 5376 OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd ); 5377 if ( eOp1 != ocColRowName && eOp1 != ocIntersect 5378 && eOp2 != ocColRowName && eOp2 != ocIntersect ) 5379 { 5380 if ( (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) || 5381 (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP)) 5382 bSingle = sal_True; 5383 } 5384 if ( bSingle ) 5385 { // column and/or row must match range 5386 if ( bColName ) 5387 { 5388 bFound = (aRange.aStart.Row() <= nMyRow 5389 && nMyRow <= aRange.aEnd.Row()); 5390 if ( bFound ) 5391 aRange.aStart.SetRow( nMyRow ); 5392 } 5393 else 5394 { 5395 bFound = (aRange.aStart.Col() <= nMyCol 5396 && nMyCol <= aRange.aEnd.Col()); 5397 if ( bFound ) 5398 aRange.aStart.SetCol( nMyCol ); 5399 } 5400 } 5401 else 5402 bFound = sal_True; 5403 } 5404 if ( !bFound ) 5405 SetError(errNoRef); 5406 else if ( !bCompileForFAP ) 5407 { 5408 ScTokenArray* pNew = new ScTokenArray(); 5409 if ( bSingle ) 5410 { 5411 ScSingleRefData aRefData; 5412 aRefData.InitAddress( aRange.aStart ); 5413 if ( bColName ) 5414 aRefData.SetColRel( sal_True ); 5415 else 5416 aRefData.SetRowRel( sal_True ); 5417 aRefData.CalcRelFromAbs( aPos ); 5418 pNew->AddSingleReference( aRefData ); 5419 } 5420 else 5421 { 5422 ScComplexRefData aRefData; 5423 aRefData.InitRange( aRange ); 5424 if ( bColName ) 5425 { 5426 aRefData.Ref1.SetColRel( sal_True ); 5427 aRefData.Ref2.SetColRel( sal_True ); 5428 } 5429 else 5430 { 5431 aRefData.Ref1.SetRowRel( sal_True ); 5432 aRefData.Ref2.SetRowRel( sal_True ); 5433 } 5434 aRefData.CalcRelFromAbs( aPos ); 5435 if ( bInList ) 5436 pNew->AddDoubleReference( aRefData ); 5437 else 5438 { // automagically 5439 pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) ); 5440 } 5441 } 5442 PushTokenArray( pNew, sal_True ); 5443 pNew->Reset(); 5444 return GetToken(); 5445 } 5446 } 5447 else 5448 SetError(errNoName); 5449 return sal_True; 5450 } 5451 // ----------------------------------------------------------------------------- 5452 sal_Bool ScCompiler::HandleDbData() 5453 { 5454 ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex( pToken->GetIndex() ); 5455 if ( !pDBData ) 5456 SetError(errNoName); 5457 else if ( !bCompileForFAP ) 5458 { 5459 ScComplexRefData aRefData; 5460 aRefData.InitFlags(); 5461 pDBData->GetArea( (SCTAB&) aRefData.Ref1.nTab, 5462 (SCCOL&) aRefData.Ref1.nCol, 5463 (SCROW&) aRefData.Ref1.nRow, 5464 (SCCOL&) aRefData.Ref2.nCol, 5465 (SCROW&) aRefData.Ref2.nRow); 5466 aRefData.Ref2.nTab = aRefData.Ref1.nTab; 5467 aRefData.CalcRelFromAbs( aPos ); 5468 ScTokenArray* pNew = new ScTokenArray(); 5469 pNew->AddDoubleReference( aRefData ); 5470 PushTokenArray( pNew, sal_True ); 5471 pNew->Reset(); 5472 return GetToken(); 5473 } 5474 return sal_True; 5475 } 5476 5477 String GetScCompilerNativeSymbol( OpCode eOp ) 5478 { 5479 return ScCompiler::GetNativeSymbol( eOp ); 5480 } 5481 // ----------------------------------------------------------------------------- 5482 FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef ) 5483 { 5484 return ScToken::ExtendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef ); 5485 } 5486