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