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 ) ) 2968 { 2969 ScRangeData* pData = (*pRangeName)[n]; 2970 ScRawToken aToken; 2971 aToken.SetName( pData->GetIndex() ); 2972 pRawToken = aToken.Clone(); 2973 return sal_True; 2974 } 2975 else 2976 return sal_False; 2977 } 2978 2979 bool ScCompiler::IsExternalNamedRange( const String& rSymbol ) 2980 { 2981 /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc) 2982 * correctly parses external named references in OOo, as required per RFE 2983 * #i3740#, just that we can't store them in ODF yet. We will need an OASIS 2984 * spec first. Until then don't pretend to support external names that 2985 * wouldn't survive a save and reload cycle, return false instead. */ 2986 2987 #if 0 2988 if (!pConv) 2989 return false; 2990 2991 String aFile, aName; 2992 if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks)) 2993 return false; 2994 2995 ScRawToken aToken; 2996 if (aFile.Len() > MAXSTRLEN || aName.Len() > MAXSTRLEN) 2997 return false; 2998 2999 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 3000 pRefMgr->convertToAbsName(aFile); 3001 sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile); 3002 if (!pRefMgr->getRangeNameTokens(nFileId, aName).get()) 3003 // range name doesn't exist in the source document. 3004 return false; 3005 3006 const String* pRealName = pRefMgr->getRealRangeName(nFileId, aName); 3007 aToken.SetExternalName(nFileId, pRealName ? *pRealName : aName); 3008 pRawToken = aToken.Clone(); 3009 return true; 3010 #else 3011 (void)rSymbol; 3012 return false; 3013 #endif 3014 } 3015 3016 sal_Bool ScCompiler::IsDBRange( const String& rName ) 3017 { 3018 sal_uInt16 n; 3019 ScDBCollection* pDBColl = pDoc->GetDBCollection(); 3020 if (pDBColl->SearchName( rName, n ) ) 3021 { 3022 ScDBData* pData = (*pDBColl)[n]; 3023 ScRawToken aToken; 3024 aToken.SetName( pData->GetIndex() ); 3025 aToken.eOp = ocDBArea; 3026 pRawToken = aToken.Clone(); 3027 return sal_True; 3028 } 3029 else 3030 return sal_False; 3031 } 3032 3033 sal_Bool ScCompiler::IsColRowName( const String& rName ) 3034 { 3035 sal_Bool bInList = sal_False; 3036 sal_Bool bFound = sal_False; 3037 ScSingleRefData aRef; 3038 String aName( rName ); 3039 DeQuote( aName ); 3040 SCTAB nThisTab = aPos.Tab(); 3041 for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- ) 3042 { // #50300# first check ranges on this sheet, in case of duplicated names 3043 for ( short jRow=0; jRow<2 && !bInList; jRow++ ) 3044 { 3045 ScRangePairList* pRL; 3046 if ( !jRow ) 3047 pRL = pDoc->GetColNameRanges(); 3048 else 3049 pRL = pDoc->GetRowNameRanges(); 3050 for ( ScRangePair* pR = pRL->First(); pR && !bInList; pR = pRL->Next() ) 3051 { 3052 const ScRange& rNameRange = pR->GetRange(0); 3053 if ( jThisTab && !(rNameRange.aStart.Tab() <= nThisTab && 3054 nThisTab <= rNameRange.aEnd.Tab()) ) 3055 continue; // for 3056 ScCellIterator aIter( pDoc, rNameRange ); 3057 for ( ScBaseCell* pCell = aIter.GetFirst(); pCell && !bInList; 3058 pCell = aIter.GetNext() ) 3059 { 3060 // Don't crash if cell (via CompileNameFormula) encounters 3061 // a formula cell without code and 3062 // HasStringData/Interpret/Compile is executed and all that 3063 // recursive.. 3064 // Furthermore, *this* cell won't be touched, since no RPN exists yet. 3065 CellType eType = pCell->GetCellType(); 3066 sal_Bool bOk = sal::static_int_cast<sal_Bool>( (eType == CELLTYPE_FORMULA ? 3067 ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0 3068 && ((ScFormulaCell*)pCell)->aPos != aPos // noIter 3069 : sal_True ) ); 3070 if ( bOk && pCell->HasStringData() ) 3071 { 3072 String aStr; 3073 switch ( eType ) 3074 { 3075 case CELLTYPE_STRING: 3076 ((ScStringCell*)pCell)->GetString( aStr ); 3077 break; 3078 case CELLTYPE_FORMULA: 3079 ((ScFormulaCell*)pCell)->GetString( aStr ); 3080 break; 3081 case CELLTYPE_EDIT: 3082 ((ScEditCell*)pCell)->GetString( aStr ); 3083 break; 3084 case CELLTYPE_NONE: 3085 case CELLTYPE_VALUE: 3086 case CELLTYPE_NOTE: 3087 case CELLTYPE_SYMBOLS: 3088 #if DBG_UTIL 3089 case CELLTYPE_DESTROYED: 3090 #endif 3091 ; // nothing, prevent compiler warning 3092 break; 3093 } 3094 if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) ) 3095 { 3096 aRef.InitFlags(); 3097 aRef.nCol = aIter.GetCol(); 3098 aRef.nRow = aIter.GetRow(); 3099 aRef.nTab = aIter.GetTab(); 3100 if ( !jRow ) 3101 aRef.SetColRel( sal_True ); // ColName 3102 else 3103 aRef.SetRowRel( sal_True ); // RowName 3104 aRef.CalcRelFromAbs( aPos ); 3105 bInList = bFound = sal_True; 3106 } 3107 } 3108 } 3109 } 3110 } 3111 } 3112 if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() ) 3113 { // search in current sheet 3114 long nDistance = 0, nMax = 0; 3115 long nMyCol = (long) aPos.Col(); 3116 long nMyRow = (long) aPos.Row(); 3117 sal_Bool bTwo = sal_False; 3118 ScAddress aOne( 0, 0, aPos.Tab() ); 3119 ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() ); 3120 3121 ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache(); 3122 if ( pNameCache ) 3123 { 3124 // #b6355215# use GetNameOccurences to collect all positions of aName on the sheet 3125 // (only once), similar to the outer part of the loop in the "else" branch. 3126 3127 const ScAutoNameAddresses& rAddresses = pNameCache->GetNameOccurences( aName, aPos.Tab() ); 3128 3129 // Loop through the found positions, similar to the inner part of the loop in the "else" branch. 3130 // The order of addresses in the vector is the same as from ScCellIterator. 3131 3132 ScAutoNameAddresses::const_iterator aEnd(rAddresses.end()); 3133 for ( ScAutoNameAddresses::const_iterator aAdrIter(rAddresses.begin()); aAdrIter != aEnd; ++aAdrIter ) 3134 { 3135 ScAddress aAddress( *aAdrIter ); // cell address with an equal string 3136 3137 if ( bFound ) 3138 { // stop if everything else is further away 3139 if ( nMax < (long)aAddress.Col() ) 3140 break; // aIter 3141 } 3142 if ( aAddress != aPos ) 3143 { 3144 // same treatment as in isEqual case below 3145 3146 SCCOL nCol = aAddress.Col(); 3147 SCROW nRow = aAddress.Row(); 3148 long nC = nMyCol - nCol; 3149 long nR = nMyRow - nRow; 3150 if ( bFound ) 3151 { 3152 long nD = nC * nC + nR * nR; 3153 if ( nD < nDistance ) 3154 { 3155 if ( nC < 0 || nR < 0 ) 3156 { // right or below 3157 bTwo = sal_True; 3158 aTwo.Set( nCol, nRow, aAddress.Tab() ); 3159 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3160 nDistance = nD; 3161 } 3162 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) ) 3163 { 3164 // upper left, only if not further up than the 3165 // current entry and nMyRow is below (CellIter 3166 // runs column-wise) 3167 bTwo = sal_False; 3168 aOne.Set( nCol, nRow, aAddress.Tab() ); 3169 nMax = Max( nMyCol + nC, nMyRow + nR ); 3170 nDistance = nD; 3171 } 3172 } 3173 } 3174 else 3175 { 3176 aOne.Set( nCol, nRow, aAddress.Tab() ); 3177 nDistance = nC * nC + nR * nR; 3178 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3179 } 3180 bFound = sal_True; 3181 } 3182 } 3183 } 3184 else 3185 { 3186 ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) ); 3187 for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() ) 3188 { 3189 if ( bFound ) 3190 { // stop if everything else is further away 3191 if ( nMax < (long)aIter.GetCol() ) 3192 break; // aIter 3193 } 3194 CellType eType = pCell->GetCellType(); 3195 sal_Bool bOk = sal::static_int_cast<sal_Bool>( (eType == CELLTYPE_FORMULA ? 3196 ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0 3197 && ((ScFormulaCell*)pCell)->aPos != aPos // noIter 3198 : sal_True ) ); 3199 if ( bOk && pCell->HasStringData() ) 3200 { 3201 String aStr; 3202 switch ( eType ) 3203 { 3204 case CELLTYPE_STRING: 3205 ((ScStringCell*)pCell)->GetString( aStr ); 3206 break; 3207 case CELLTYPE_FORMULA: 3208 ((ScFormulaCell*)pCell)->GetString( aStr ); 3209 break; 3210 case CELLTYPE_EDIT: 3211 ((ScEditCell*)pCell)->GetString( aStr ); 3212 break; 3213 case CELLTYPE_NONE: 3214 case CELLTYPE_VALUE: 3215 case CELLTYPE_NOTE: 3216 case CELLTYPE_SYMBOLS: 3217 #if DBG_UTIL 3218 case CELLTYPE_DESTROYED: 3219 #endif 3220 ; // nothing, prevent compiler warning 3221 break; 3222 } 3223 if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) ) 3224 { 3225 SCCOL nCol = aIter.GetCol(); 3226 SCROW nRow = aIter.GetRow(); 3227 long nC = nMyCol - nCol; 3228 long nR = nMyRow - nRow; 3229 if ( bFound ) 3230 { 3231 long nD = nC * nC + nR * nR; 3232 if ( nD < nDistance ) 3233 { 3234 if ( nC < 0 || nR < 0 ) 3235 { // right or below 3236 bTwo = sal_True; 3237 aTwo.Set( nCol, nRow, aIter.GetTab() ); 3238 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3239 nDistance = nD; 3240 } 3241 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) ) 3242 { 3243 // upper left, only if not further up than the 3244 // current entry and nMyRow is below (CellIter 3245 // runs column-wise) 3246 bTwo = sal_False; 3247 aOne.Set( nCol, nRow, aIter.GetTab() ); 3248 nMax = Max( nMyCol + nC, nMyRow + nR ); 3249 nDistance = nD; 3250 } 3251 } 3252 } 3253 else 3254 { 3255 aOne.Set( nCol, nRow, aIter.GetTab() ); 3256 nDistance = nC * nC + nR * nR; 3257 nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) ); 3258 } 3259 bFound = sal_True; 3260 } 3261 } 3262 } 3263 } 3264 3265 if ( bFound ) 3266 { 3267 ScAddress aAdr; 3268 if ( bTwo ) 3269 { 3270 if ( nMyCol >= (long)aOne.Col() && nMyRow >= (long)aOne.Row() ) 3271 aAdr = aOne; // upper left takes precedence 3272 else 3273 { 3274 if ( nMyCol < (long)aOne.Col() ) 3275 { // two to the right 3276 if ( nMyRow >= (long)aTwo.Row() ) 3277 aAdr = aTwo; // directly right 3278 else 3279 aAdr = aOne; 3280 } 3281 else 3282 { // two below or below and right, take the nearest 3283 long nC1 = nMyCol - aOne.Col(); 3284 long nR1 = nMyRow - aOne.Row(); 3285 long nC2 = nMyCol - aTwo.Col(); 3286 long nR2 = nMyRow - aTwo.Row(); 3287 if ( nC1 * nC1 + nR1 * nR1 <= nC2 * nC2 + nR2 * nR2 ) 3288 aAdr = aOne; 3289 else 3290 aAdr = aTwo; 3291 } 3292 } 3293 } 3294 else 3295 aAdr = aOne; 3296 aRef.InitAddress( aAdr ); 3297 if ( (aRef.nRow != MAXROW && pDoc->HasStringData( 3298 aRef.nCol, aRef.nRow + 1, aRef.nTab )) 3299 || (aRef.nRow != 0 && pDoc->HasStringData( 3300 aRef.nCol, aRef.nRow - 1, aRef.nTab )) ) 3301 aRef.SetRowRel( sal_True ); // RowName 3302 else 3303 aRef.SetColRel( sal_True ); // ColName 3304 aRef.CalcRelFromAbs( aPos ); 3305 } 3306 } 3307 if ( bFound ) 3308 { 3309 ScRawToken aToken; 3310 aToken.SetSingleReference( aRef ); 3311 aToken.eOp = ocColRowName; 3312 pRawToken = aToken.Clone(); 3313 return sal_True; 3314 } 3315 else 3316 return sal_False; 3317 } 3318 3319 sal_Bool ScCompiler::IsBoolean( const String& rName ) 3320 { 3321 OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) ); 3322 if( iLook != mxSymbols->getHashMap()->end() && 3323 ((*iLook).second == ocTrue || 3324 (*iLook).second == ocFalse) ) 3325 { 3326 ScRawToken aToken; 3327 aToken.SetOpCode( (*iLook).second ); 3328 pRawToken = aToken.Clone(); 3329 return sal_True; 3330 } 3331 else 3332 return sal_False; 3333 } 3334 3335 //--------------------------------------------------------------------------- 3336 3337 void ScCompiler::AutoCorrectParsedSymbol() 3338 { 3339 xub_StrLen nPos = aCorrectedSymbol.Len(); 3340 if ( nPos ) 3341 { 3342 nPos--; 3343 const sal_Unicode cQuote = '\"'; 3344 const sal_Unicode cx = 'x'; 3345 const sal_Unicode cX = 'X'; 3346 sal_Unicode c1 = aCorrectedSymbol.GetChar( 0 ); 3347 sal_Unicode c2 = aCorrectedSymbol.GetChar( nPos ); 3348 if ( c1 == cQuote && c2 != cQuote ) 3349 { // "... 3350 // What's not a word doesn't belong to it. 3351 // Don't be pedantic: c < 128 should be sufficient here. 3352 while ( nPos && ((aCorrectedSymbol.GetChar(nPos) < 128) && 3353 ((GetCharTableFlags( aCorrectedSymbol.GetChar(nPos) ) & 3354 (SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_DONTCARE)) == 0)) ) 3355 nPos--; 3356 if ( nPos == MAXSTRLEN - 2 ) 3357 aCorrectedSymbol.SetChar( nPos, cQuote ); // '"' the 255th character 3358 else 3359 aCorrectedSymbol.Insert( cQuote, nPos + 1 ); 3360 bCorrected = sal_True; 3361 } 3362 else if ( c1 != cQuote && c2 == cQuote ) 3363 { // ..." 3364 aCorrectedSymbol.Insert( cQuote, 0 ); 3365 bCorrected = sal_True; 3366 } 3367 else if ( nPos == 0 && (c1 == cx || c1 == cX) ) 3368 { // x => * 3369 aCorrectedSymbol = mxSymbols->getSymbol(ocMul); 3370 bCorrected = sal_True; 3371 } 3372 else if ( (GetCharTableFlags( c1 ) & SC_COMPILER_C_CHAR_VALUE) 3373 && (GetCharTableFlags( c2 ) & SC_COMPILER_C_CHAR_VALUE) ) 3374 { 3375 xub_StrLen nXcount; 3376 if ( (nXcount = aCorrectedSymbol.GetTokenCount( cx )) > 1 ) 3377 { // x => * 3378 xub_StrLen nIndex = 0; 3379 sal_Unicode c = mxSymbols->getSymbol(ocMul).GetChar(0); 3380 while ( (nIndex = aCorrectedSymbol.SearchAndReplace( 3381 cx, c, nIndex )) != STRING_NOTFOUND ) 3382 nIndex++; 3383 bCorrected = sal_True; 3384 } 3385 if ( (nXcount = aCorrectedSymbol.GetTokenCount( cX )) > 1 ) 3386 { // X => * 3387 xub_StrLen nIndex = 0; 3388 sal_Unicode c = mxSymbols->getSymbol(ocMul).GetChar(0); 3389 while ( (nIndex = aCorrectedSymbol.SearchAndReplace( 3390 cX, c, nIndex )) != STRING_NOTFOUND ) 3391 nIndex++; 3392 bCorrected = sal_True; 3393 } 3394 } 3395 else 3396 { 3397 String aSymbol( aCorrectedSymbol ); 3398 String aDoc; 3399 xub_StrLen nPosition; 3400 if ( aSymbol.GetChar(0) == '\'' 3401 && ((nPosition = aSymbol.SearchAscii( "'#" )) != STRING_NOTFOUND) ) 3402 { // Split off 'Doc'#, may be d:\... or whatever 3403 aDoc = aSymbol.Copy( 0, nPosition + 2 ); 3404 aSymbol.Erase( 0, nPosition + 2 ); 3405 } 3406 xub_StrLen nRefs = aSymbol.GetTokenCount( ':' ); 3407 sal_Bool bColons; 3408 if ( nRefs > 2 ) 3409 { // duplicated or too many ':'? B:2::C10 => B2:C10 3410 bColons = sal_True; 3411 xub_StrLen nIndex = 0; 3412 String aTmp1( aSymbol.GetToken( 0, ':', nIndex ) ); 3413 xub_StrLen nLen1 = aTmp1.Len(); 3414 String aSym, aTmp2; 3415 sal_Bool bLastAlp, bNextNum; 3416 bLastAlp = bNextNum = sal_True; 3417 xub_StrLen nStrip = 0; 3418 xub_StrLen nCount = nRefs; 3419 for ( xub_StrLen j=1; j<nCount; j++ ) 3420 { 3421 aTmp2 = aSymbol.GetToken( 0, ':', nIndex ); 3422 xub_StrLen nLen2 = aTmp2.Len(); 3423 if ( nLen1 || nLen2 ) 3424 { 3425 if ( nLen1 ) 3426 { 3427 aSym += aTmp1; 3428 bLastAlp = CharClass::isAsciiAlpha( aTmp1 ); 3429 } 3430 if ( nLen2 ) 3431 { 3432 bNextNum = CharClass::isAsciiNumeric( aTmp2 ); 3433 if ( bLastAlp == bNextNum && nStrip < 1 ) 3434 { 3435 // Must be alternating number/string, only 3436 // strip within a reference. 3437 nRefs--; 3438 nStrip++; 3439 } 3440 else 3441 { 3442 xub_StrLen nSymLen = aSym.Len(); 3443 if ( nSymLen 3444 && (aSym.GetChar( nSymLen - 1 ) != ':') ) 3445 aSym += ':'; 3446 nStrip = 0; 3447 } 3448 bLastAlp = !bNextNum; 3449 } 3450 else 3451 { // :: 3452 nRefs--; 3453 if ( nLen1 ) 3454 { // B10::C10 ? append ':' on next round 3455 if ( !bLastAlp && !CharClass::isAsciiNumeric( aTmp1 ) ) 3456 nStrip++; 3457 } 3458 bNextNum = !bLastAlp; 3459 } 3460 aTmp1 = aTmp2; 3461 nLen1 = nLen2; 3462 } 3463 else 3464 nRefs--; 3465 } 3466 aSymbol = aSym; 3467 aSymbol += aTmp1; 3468 } 3469 else 3470 bColons = sal_False; 3471 if ( nRefs && nRefs <= 2 ) 3472 { // reference twisted? 4A => A4 etc. 3473 String aTab[2], aRef[2]; 3474 const ScAddress::Details aDetails( pConv->meConv, aPos ); 3475 if ( nRefs == 2 ) 3476 { 3477 aRef[0] = aSymbol.GetToken( 0, ':' ); 3478 aRef[1] = aSymbol.GetToken( 1, ':' ); 3479 } 3480 else 3481 aRef[0] = aSymbol; 3482 3483 sal_Bool bChanged = sal_False; 3484 sal_Bool bOk = sal_True; 3485 sal_uInt16 nMask = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW; 3486 for ( int j=0; j<nRefs; j++ ) 3487 { 3488 xub_StrLen nTmp = 0; 3489 xub_StrLen nDotPos = STRING_NOTFOUND; 3490 while ( (nTmp = aRef[j].Search( '.', nTmp )) != STRING_NOTFOUND ) 3491 nDotPos = nTmp++; // the last one counts 3492 if ( nDotPos != STRING_NOTFOUND ) 3493 { 3494 aTab[j] = aRef[j].Copy( 0, nDotPos + 1 ); // with '.' 3495 aRef[j].Erase( 0, nDotPos + 1 ); 3496 } 3497 String aOld( aRef[j] ); 3498 String aStr2; 3499 const sal_Unicode* p = aRef[j].GetBuffer(); 3500 while ( *p && CharClass::isAsciiNumeric( *p ) ) 3501 aStr2 += *p++; 3502 aRef[j] = String( p ); 3503 aRef[j] += aStr2; 3504 if ( bColons || aRef[j] != aOld ) 3505 { 3506 bChanged = sal_True; 3507 ScAddress aAdr; 3508 bOk &= ((aAdr.Parse( aRef[j], pDoc, aDetails ) & nMask) == nMask); 3509 } 3510 } 3511 if ( bChanged && bOk ) 3512 { 3513 aCorrectedSymbol = aDoc; 3514 aCorrectedSymbol += aTab[0]; 3515 aCorrectedSymbol += aRef[0]; 3516 if ( nRefs == 2 ) 3517 { 3518 aCorrectedSymbol += ':'; 3519 aCorrectedSymbol += aTab[1]; 3520 aCorrectedSymbol += aRef[1]; 3521 } 3522 bCorrected = sal_True; 3523 } 3524 } 3525 } 3526 } 3527 } 3528 3529 inline bool lcl_UpperAsciiOrI18n( String& rUpper, const String& rOrg, FormulaGrammar::Grammar eGrammar ) 3530 { 3531 if (FormulaGrammar::isODFF( eGrammar )) 3532 { 3533 // ODFF has a defined set of English function names, avoid i18n 3534 // overhead. 3535 rUpper = rOrg; 3536 rUpper.ToUpperAscii(); 3537 return true; 3538 } 3539 else 3540 { 3541 rUpper = ScGlobal::pCharClass->upper( rOrg ); 3542 return false; 3543 } 3544 } 3545 3546 sal_Bool ScCompiler::NextNewToken( bool bInArray ) 3547 { 3548 bool bAllowBooleans = bInArray; 3549 xub_StrLen nSpaces = NextSymbol(bInArray); 3550 3551 #if 0 3552 fprintf( stderr, "NextNewToken '%s' (spaces = %d)\n", 3553 rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr(), nSpaces ); 3554 #endif 3555 3556 if (!cSymbol[0]) 3557 return false; 3558 3559 if( nSpaces ) 3560 { 3561 ScRawToken aToken; 3562 aToken.SetOpCode( ocSpaces ); 3563 aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces ); 3564 if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) ) 3565 { 3566 SetError(errCodeOverflow); 3567 return false; 3568 } 3569 } 3570 3571 // Short cut for references when reading ODF to speedup things. 3572 if (mnPredetectedReference) 3573 { 3574 String aStr( cSymbol); 3575 if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr)) 3576 { 3577 /* TODO: it would be nice to generate a #REF! error here, which 3578 * would need an ocBad token with additional error value. 3579 * FormulaErrorToken wouldn't do because we want to preserve the 3580 * original string containing partial valid address 3581 * information. */ 3582 ScRawToken aToken; 3583 aToken.SetString( aStr.GetBuffer() ); 3584 aToken.NewOpCode( ocBad ); 3585 pRawToken = aToken.Clone(); 3586 } 3587 return true; 3588 } 3589 3590 if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 && 3591 !bAutoCorrect ) 3592 { // #101100# special case to speed up broken [$]#REF documents 3593 /* FIXME: ISERROR(#REF!) would be valid and sal_True and the formula to 3594 * be processed as usual. That would need some special treatment, 3595 * also in NextSymbol() because of possible combinations of 3596 * #REF!.#REF!#REF! parts. In case of reading ODF that is all 3597 * handled by IsPredetectedReference(), this case here remains for 3598 * manual/API input. */ 3599 String aBad( aFormula.Copy( nSrcPos-1 ) ); 3600 eLastOp = pArr->AddBad( aBad )->GetOpCode(); 3601 return false; 3602 } 3603 3604 if( IsString() ) 3605 return true; 3606 3607 bool bMayBeFuncName; 3608 bool bAsciiNonAlnum; // operators, separators, ... 3609 if ( cSymbol[0] < 128 ) 3610 { 3611 bMayBeFuncName = CharClass::isAsciiAlpha( cSymbol[0] ); 3612 bAsciiNonAlnum = !bMayBeFuncName && !CharClass::isAsciiDigit( cSymbol[0] ); 3613 } 3614 else 3615 { 3616 String aTmpStr( cSymbol[0] ); 3617 bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 ); 3618 bAsciiNonAlnum = false; 3619 } 3620 if ( bMayBeFuncName ) 3621 { 3622 // a function name must be followed by a parenthesis 3623 const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos; 3624 while( *p == ' ' ) 3625 p++; 3626 bMayBeFuncName = ( *p == '(' ); 3627 } 3628 3629 #if 0 3630 fprintf( stderr, "Token '%s'\n", 3631 rtl::OUStringToOString( aUpper, RTL_TEXTENCODING_UTF8 ).getStr() ); 3632 #endif 3633 3634 // #42016# Italian ARCTAN.2 resulted in #REF! => IsOpcode() before 3635 // IsReference(). 3636 3637 String aUpper; 3638 3639 do 3640 { 3641 mbRewind = false; 3642 const String aOrg( cSymbol ); 3643 3644 if (bAsciiNonAlnum && IsOpCode( aOrg, bInArray )) 3645 return true; 3646 3647 aUpper.Erase(); 3648 bool bAsciiUpper = false; 3649 if (bMayBeFuncName) 3650 { 3651 bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); 3652 if (IsOpCode( aUpper, bInArray )) 3653 return true; 3654 } 3655 3656 // Column 'DM' ("Deutsche Mark", German currency) couldn't be 3657 // referred => IsReference() before IsValue(). 3658 // Preserve case of file names in external references. 3659 if (IsReference( aOrg )) 3660 { 3661 if (mbRewind) // Range operator, but no direct reference. 3662 continue; // do; up to range operator. 3663 return true; 3664 } 3665 3666 if (!aUpper.Len()) 3667 bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); 3668 3669 // IsBoolean() before IsValue() to catch inline bools without the kludge 3670 // for inline arrays. 3671 if (bAllowBooleans && IsBoolean( aUpper )) 3672 return true; 3673 3674 if (IsValue( aUpper )) 3675 return true; 3676 3677 // User defined names and such do need i18n upper also in ODF. 3678 if (bAsciiUpper) 3679 aUpper = ScGlobal::pCharClass->upper( aOrg ); 3680 3681 if (IsNamedRange( aUpper )) 3682 return true; 3683 // Preserve case of file names in external references. 3684 if (IsExternalNamedRange( aOrg )) 3685 return true; 3686 if (IsDBRange( aUpper )) 3687 return true; 3688 if (IsColRowName( aUpper )) 3689 return true; 3690 if (bMayBeFuncName && IsMacro( aUpper )) 3691 return true; 3692 if (bMayBeFuncName && IsOpCode2( aUpper )) 3693 return true; 3694 3695 } while (mbRewind); 3696 3697 if ( mbExtendedErrorDetection ) 3698 { 3699 // set an error and end compilation 3700 SetError( errNoName ); 3701 return false; 3702 } 3703 3704 // Provide single token information and continue. Do not set an error, that 3705 // would prematurely end compilation. Simple unknown names are handled by 3706 // the interpreter. 3707 ScGlobal::pCharClass->toLower( aUpper ); 3708 ScRawToken aToken; 3709 aToken.SetString( aUpper.GetBuffer() ); 3710 aToken.NewOpCode( ocBad ); 3711 pRawToken = aToken.Clone(); 3712 if ( bAutoCorrect ) 3713 AutoCorrectParsedSymbol(); 3714 return true; 3715 } 3716 3717 void ScCompiler::CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp ) 3718 { 3719 bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL; 3720 sal_uInt16 nExpectedCount = bExternal ? 2 : 1; 3721 DBG_ASSERT( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" ); 3722 if( pArr->GetLen() == nExpectedCount ) 3723 { 3724 FormulaToken** ppTokens = pArr->GetArray(); 3725 // string tokens expected, GetString() will assert if token type is wrong 3726 rFormula = ppTokens[ 0 ]->GetString(); 3727 if( bExternal ) 3728 rFormulaNmsp = ppTokens[ 1 ]->GetString(); 3729 } 3730 } 3731 3732 ScTokenArray* ScCompiler::CompileString( const String& rFormula ) 3733 { 3734 #if 0 3735 fprintf( stderr, "CompileString '%s'\n", 3736 rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); 3737 #endif 3738 3739 OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" ); 3740 if( meGrammar == FormulaGrammar::GRAM_EXTERNAL ) 3741 SetGrammar( FormulaGrammar::GRAM_PODF ); 3742 3743 ScTokenArray aArr; 3744 pArr = &aArr; 3745 aFormula = rFormula; 3746 3747 aFormula.EraseLeadingChars(); 3748 aFormula.EraseTrailingChars(); 3749 nSrcPos = 0; 3750 bCorrected = sal_False; 3751 if ( bAutoCorrect ) 3752 { 3753 aCorrectedFormula.Erase(); 3754 aCorrectedSymbol.Erase(); 3755 } 3756 sal_uInt8 nForced = 0; // ==formula forces recalc even if cell is not visible 3757 if( aFormula.GetChar(nSrcPos) == '=' ) 3758 { 3759 nSrcPos++; 3760 nForced++; 3761 if ( bAutoCorrect ) 3762 aCorrectedFormula += '='; 3763 } 3764 if( aFormula.GetChar(nSrcPos) == '=' ) 3765 { 3766 nSrcPos++; 3767 nForced++; 3768 if ( bAutoCorrect ) 3769 aCorrectedFormula += '='; 3770 } 3771 struct FunctionStack 3772 { 3773 OpCode eOp; 3774 short nPar; 3775 }; 3776 // FunctionStack only used if PODF! 3777 bool bPODF = FormulaGrammar::isPODF( meGrammar); 3778 const size_t nAlloc = 512; 3779 FunctionStack aFuncs[ nAlloc ]; 3780 FunctionStack* pFunctionStack = (bPODF && rFormula.Len() > nAlloc ? 3781 new FunctionStack[ rFormula.Len() ] : &aFuncs[0]); 3782 pFunctionStack[0].eOp = ocNone; 3783 pFunctionStack[0].nPar = 0; 3784 size_t nFunction = 0; 3785 short nBrackets = 0; 3786 bool bInArray = false; 3787 eLastOp = ocOpen; 3788 while( NextNewToken( bInArray ) ) 3789 { 3790 const OpCode eOp = pRawToken->GetOpCode(); 3791 switch (eOp) 3792 { 3793 case ocOpen: 3794 { 3795 ++nBrackets; 3796 if (bPODF) 3797 { 3798 ++nFunction; 3799 pFunctionStack[ nFunction ].eOp = eLastOp; 3800 pFunctionStack[ nFunction ].nPar = 0; 3801 } 3802 } 3803 break; 3804 case ocClose: 3805 { 3806 if( !nBrackets ) 3807 { 3808 SetError( errPairExpected ); 3809 if ( bAutoCorrect ) 3810 { 3811 bCorrected = sal_True; 3812 aCorrectedSymbol.Erase(); 3813 } 3814 } 3815 else 3816 nBrackets--; 3817 if (bPODF && nFunction) 3818 --nFunction; 3819 } 3820 break; 3821 case ocSep: 3822 { 3823 if (bPODF) 3824 ++pFunctionStack[ nFunction ].nPar; 3825 } 3826 break; 3827 case ocArrayOpen: 3828 { 3829 if( bInArray ) 3830 SetError( errNestedArray ); 3831 else 3832 bInArray = true; 3833 // Don't count following column separator as parameter separator. 3834 if (bPODF) 3835 { 3836 ++nFunction; 3837 pFunctionStack[ nFunction ].eOp = eOp; 3838 pFunctionStack[ nFunction ].nPar = 0; 3839 } 3840 } 3841 break; 3842 case ocArrayClose: 3843 { 3844 if( bInArray ) 3845 { 3846 bInArray = false; 3847 } 3848 else 3849 { 3850 SetError( errPairExpected ); 3851 if ( bAutoCorrect ) 3852 { 3853 bCorrected = sal_True; 3854 aCorrectedSymbol.Erase(); 3855 } 3856 } 3857 if (bPODF && nFunction) 3858 --nFunction; 3859 } 3860 default: 3861 break; 3862 } 3863 if( (eLastOp == ocSep || 3864 eLastOp == ocArrayRowSep || 3865 eLastOp == ocArrayColSep || 3866 eLastOp == ocArrayOpen) && 3867 (eOp == ocSep || 3868 eOp == ocArrayRowSep || 3869 eOp == ocArrayColSep || 3870 eOp == ocArrayClose) ) 3871 { 3872 // FIXME: should we check for known functions with optional empty 3873 // args so the correction dialog can do better? 3874 if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) ) 3875 { 3876 SetError(errCodeOverflow); break; 3877 } 3878 } 3879 if (bPODF) 3880 { 3881 /* TODO: for now this is the only PODF adapter. If there were more, 3882 * factor this out. */ 3883 // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th. 3884 if (eOp == ocSep && 3885 pFunctionStack[ nFunction ].eOp == ocAddress && 3886 pFunctionStack[ nFunction ].nPar == 3) 3887 { 3888 if (!static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep,ocSep)) || 3889 !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0))) 3890 { 3891 SetError(errCodeOverflow); break; 3892 } 3893 ++pFunctionStack[ nFunction ].nPar; 3894 } 3895 } 3896 FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( pRawToken->CreateToken()); 3897 if (!pNewToken) 3898 { 3899 SetError(errCodeOverflow); break; 3900 } 3901 else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush && 3902 pNewToken->GetType() == svSingleRef) 3903 static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos); 3904 eLastOp = pRawToken->GetOpCode(); 3905 if ( bAutoCorrect ) 3906 aCorrectedFormula += aCorrectedSymbol; 3907 } 3908 if ( mbCloseBrackets ) 3909 { 3910 if( bInArray ) 3911 { 3912 FormulaByteToken aToken( ocArrayClose ); 3913 if( !pArr->AddToken( aToken ) ) 3914 { 3915 SetError(errCodeOverflow); 3916 } 3917 else if ( bAutoCorrect ) 3918 aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose); 3919 } 3920 3921 FormulaByteToken aToken( ocClose ); 3922 while( nBrackets-- ) 3923 { 3924 if( !pArr->AddToken( aToken ) ) 3925 { 3926 SetError(errCodeOverflow); break; 3927 } 3928 if ( bAutoCorrect ) 3929 aCorrectedFormula += mxSymbols->getSymbol(ocClose); 3930 } 3931 } 3932 if ( nForced >= 2 ) 3933 pArr->SetRecalcModeForced(); 3934 3935 if (pFunctionStack != &aFuncs[0]) 3936 delete [] pFunctionStack; 3937 3938 // remember pArr, in case a subsequent CompileTokenArray() is executed. 3939 ScTokenArray* pNew = new ScTokenArray( aArr ); 3940 pArr = pNew; 3941 return pNew; 3942 } 3943 3944 3945 ScTokenArray* ScCompiler::CompileString( const String& rFormula, const String& rFormulaNmsp ) 3946 { 3947 DBG_ASSERT( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || (rFormulaNmsp.Len() == 0), 3948 "ScCompiler::CompileString - unexpected formula namespace for internal grammar" ); 3949 if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try 3950 { 3951 ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool(); 3952 uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW ); 3953 table::CellAddress aReferencePos; 3954 ScUnoConversion::FillApiAddress( aReferencePos, aPos ); 3955 uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos ); 3956 ScTokenArray aTokenArray; 3957 if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) ) 3958 { 3959 // remember pArr, in case a subsequent CompileTokenArray() is executed. 3960 ScTokenArray* pNew = new ScTokenArray( aTokenArray ); 3961 pArr = pNew; 3962 return pNew; 3963 } 3964 } 3965 catch( uno::Exception& ) 3966 { 3967 } 3968 // no success - fallback to some internal grammar and hope the best 3969 return CompileString( rFormula ); 3970 } 3971 3972 3973 sal_Bool ScCompiler::HandleRange() 3974 { 3975 ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() ); 3976 if (pRangeData) 3977 { 3978 sal_uInt16 nErr = pRangeData->GetErrCode(); 3979 if( nErr ) 3980 SetError( errNoName ); 3981 else if ( !bCompileForFAP ) 3982 { 3983 ScTokenArray* pNew; 3984 // #35168# put named formula into parentheses. 3985 // #37680# But only if there aren't any yet, parenthetical 3986 // ocSep doesn't work, e.g. SUM((...;...)) 3987 // or if not directly between ocSep/parenthesis, 3988 // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes, 3989 // in short: if it isn't a self-contained expression. 3990 FormulaToken* p1 = pArr->PeekPrevNoSpaces(); 3991 FormulaToken* p2 = pArr->PeekNextNoSpaces(); 3992 OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) ); 3993 OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) ); 3994 sal_Bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen); 3995 sal_Bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose); 3996 sal_Bool bAddPair = !(bBorder1 && bBorder2); 3997 if ( bAddPair ) 3998 { 3999 pNew = new ScTokenArray(); 4000 pNew->AddOpCode( ocClose ); 4001 PushTokenArray( pNew, sal_True ); 4002 pNew->Reset(); 4003 } 4004 pNew = pRangeData->GetCode()->Clone(); 4005 PushTokenArray( pNew, sal_True ); 4006 if( pRangeData->HasReferences() ) 4007 { 4008 SetRelNameReference(); 4009 MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); 4010 } 4011 pNew->Reset(); 4012 if ( bAddPair ) 4013 { 4014 pNew = new ScTokenArray(); 4015 pNew->AddOpCode( ocOpen ); 4016 PushTokenArray( pNew, sal_True ); 4017 pNew->Reset(); 4018 } 4019 return GetToken(); 4020 } 4021 } 4022 else 4023 SetError(errNoName); 4024 return sal_True; 4025 } 4026 // ----------------------------------------------------------------------------- 4027 sal_Bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken) 4028 { 4029 // Handle external range names. 4030 switch (_aToken.GetType()) 4031 { 4032 case svExternalSingleRef: 4033 case svExternalDoubleRef: 4034 pArr->IncrementRefs(); 4035 break; 4036 case svExternalName: 4037 { 4038 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 4039 const String* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex()); 4040 if (!pFile) 4041 { 4042 SetError(errNoName); 4043 return true; 4044 } 4045 4046 const String& rName = _aToken.GetString(); 4047 ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens( 4048 _aToken.GetIndex(), rName, &aPos); 4049 4050 if (!xNew) 4051 { 4052 SetError(errNoName); 4053 return true; 4054 } 4055 4056 ScTokenArray* pNew = xNew->Clone(); 4057 PushTokenArray( pNew, true); 4058 if (pNew->GetNextReference() != NULL) 4059 { 4060 SetRelNameReference(); 4061 MoveRelWrap(MAXCOL, MAXROW); 4062 } 4063 pNew->Reset(); 4064 return GetToken(); 4065 } 4066 default: 4067 DBG_ERROR("Wrong type for external reference!"); 4068 return sal_False; 4069 } 4070 return sal_True; 4071 } 4072 4073 4074 //--------------------------------------------------------------------------- 4075 4076 4077 //--------------------------------------------------------------------------- 4078 // Append token to RPN code 4079 //--------------------------------------------------------------------------- 4080 4081 4082 //----------------------------------------------------------------------------- 4083 4084 //--------------------------------------------------------------------------- 4085 // RPN creation by recursion 4086 //--------------------------------------------------------------------------- 4087 4088 4089 4090 //----------------------------------------------------------------------------- 4091 4092 sal_Bool ScCompiler::HasModifiedRange() 4093 { 4094 pArr->Reset(); 4095 for ( FormulaToken* t = pArr->Next(); t; t = pArr->Next() ) 4096 { 4097 OpCode eOpCode = t->GetOpCode(); 4098 if ( eOpCode == ocName ) 4099 { 4100 ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4101 4102 if (pRangeData && pRangeData->IsModified()) 4103 return sal_True; 4104 } 4105 else if ( eOpCode == ocDBArea ) 4106 { 4107 ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex()); 4108 4109 if (pDBData && pDBData->IsModified()) 4110 return sal_True; 4111 } 4112 } 4113 return sal_False; 4114 } 4115 4116 4117 //--------------------------------------------------------------------------- 4118 4119 template< typename T, typename S > 4120 S lcl_adjval( S& n, T pos, T max, sal_Bool bRel ) 4121 { 4122 max++; 4123 if( bRel ) 4124 n = sal::static_int_cast<S>( n + pos ); 4125 if( n < 0 ) 4126 n = sal::static_int_cast<S>( n + max ); 4127 else if( n >= max ) 4128 n = sal::static_int_cast<S>( n - max ); 4129 if( bRel ) 4130 n = sal::static_int_cast<S>( n - pos ); 4131 return n; 4132 } 4133 4134 // reference of named range with relative references 4135 4136 void ScCompiler::SetRelNameReference() 4137 { 4138 pArr->Reset(); 4139 for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t; 4140 t = static_cast<ScToken*>(pArr->GetNextReference()) ) 4141 { 4142 ScSingleRefData& rRef1 = t->GetSingleRef(); 4143 if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() ) 4144 rRef1.SetRelName( sal_True ); 4145 if ( t->GetType() == svDoubleRef ) 4146 { 4147 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4148 if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() ) 4149 rRef2.SetRelName( sal_True ); 4150 } 4151 } 4152 } 4153 4154 // Wrap-adjust relative references of a RangeName to current position, 4155 // don't call for other token arrays! 4156 void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow ) 4157 { 4158 pArr->Reset(); 4159 for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t; 4160 t = static_cast<ScToken*>(pArr->GetNextReference()) ) 4161 { 4162 if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) 4163 ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); 4164 else 4165 ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, t->GetDoubleRef() ); 4166 } 4167 } 4168 4169 // static 4170 // Wrap-adjust relative references of a RangeName to current position, 4171 // don't call for other token arrays! 4172 void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos, 4173 SCCOL nMaxCol, SCROW nMaxRow ) 4174 { 4175 rArr.Reset(); 4176 for( ScToken* t = static_cast<ScToken*>(rArr.GetNextReference()); t; 4177 t = static_cast<ScToken*>(rArr.GetNextReference()) ) 4178 { 4179 if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) 4180 ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); 4181 else 4182 ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, t->GetDoubleRef() ); 4183 } 4184 } 4185 4186 ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode, 4187 const ScAddress& rOldPos, const ScRange& r, 4188 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 4189 sal_Bool& rChanged, sal_Bool& rRefSizeChanged ) 4190 { 4191 rChanged = rRefSizeChanged = sal_False; 4192 if ( eUpdateRefMode == URM_COPY ) 4193 { // Normally nothing has to be done here since RelRefs are used, also 4194 // SharedFormulas don't need any special handling, except if they 4195 // wrapped around sheet borders. 4196 // #67383# But ColRowName tokens pointing to a ColRow header which was 4197 // copied along with this formula need to be updated to point to the 4198 // copied header instead of the old position's new intersection. 4199 ScToken* t; 4200 pArr->Reset(); 4201 while( (t = static_cast<ScToken*>(pArr->GetNextColRowName())) != NULL ) 4202 { 4203 ScSingleRefData& rRef = t->GetSingleRef(); 4204 rRef.CalcAbsIfRel( rOldPos ); 4205 ScAddress aNewRef( rRef.nCol + nDx, rRef.nRow + nDy, rRef.nTab + nDz ); 4206 if ( r.In( aNewRef ) ) 4207 { // yes, this is URM_MOVE 4208 if ( ScRefUpdate::Update( pDoc, URM_MOVE, aPos, 4209 r, nDx, nDy, nDz, 4210 SingleDoubleRefModifier( rRef ).Ref() ) 4211 != UR_NOTHING 4212 ) 4213 rChanged = sal_True; 4214 } 4215 } 4216 // Check for SharedFormulas. 4217 ScRangeData* pRangeData = NULL; 4218 pArr->Reset(); 4219 for( FormulaToken* j = pArr->GetNextName(); j && !pRangeData; 4220 j = pArr->GetNextName() ) 4221 { 4222 if( j->GetOpCode() == ocName ) 4223 { 4224 ScRangeData* pName = pDoc->GetRangeName()->FindIndex( j->GetIndex() ); 4225 if (pName && pName->HasType(RT_SHARED)) 4226 pRangeData = pName; 4227 } 4228 } 4229 // Check SharedFormulas for wraps. 4230 if (pRangeData) 4231 { 4232 ScRangeData* pName = pRangeData; 4233 pRangeData = NULL; 4234 pArr->Reset(); 4235 for( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()); t && !pRangeData; 4236 t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) 4237 { 4238 sal_Bool bRelName = (t->GetType() == svSingleRef ? 4239 t->GetSingleRef().IsRelName() : 4240 (t->GetDoubleRef().Ref1.IsRelName() || 4241 t->GetDoubleRef().Ref2.IsRelName())); 4242 if (bRelName) 4243 { 4244 t->CalcAbsIfRel( rOldPos); 4245 sal_Bool bValid = (t->GetType() == svSingleRef ? 4246 t->GetSingleRef().Valid() : 4247 t->GetDoubleRef().Valid()); 4248 // If the reference isn't valid, copying the formula 4249 // wrapped it. Replace SharedFormula. 4250 if (!bValid) 4251 { 4252 pRangeData = pName; 4253 rChanged = sal_True; 4254 } 4255 } 4256 } 4257 } 4258 return pRangeData; 4259 } 4260 else 4261 { 4262 /* 4263 * Set SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE to 1 if we wanted to preserve as 4264 * many shared formulas as possible instead of replacing them with direct code. 4265 * Note that this may produce shared formula usage Excel doesn't understand, 4266 * which would have to be adapted for in the export filter. Advisable as a long 4267 * term goal, since it could decrease memory footprint. 4268 */ 4269 #define SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 0 4270 ScRangeData* pRangeData = NULL; 4271 ScToken* t; 4272 pArr->Reset(); 4273 while( (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL ) 4274 { 4275 if( t->GetOpCode() == ocName ) 4276 { 4277 ScRangeData* pName = pDoc->GetRangeName()->FindIndex( t->GetIndex() ); 4278 if (pName && pName->HasType(RT_SHAREDMOD)) 4279 { 4280 pRangeData = pName; // maybe need a replacement of shared with own code 4281 #if ! SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4282 rChanged = sal_True; 4283 #endif 4284 } 4285 } 4286 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4287 { 4288 t->CalcAbsIfRel( rOldPos ); 4289 switch (t->GetType()) 4290 { 4291 case svExternalSingleRef: 4292 case svExternalDoubleRef: 4293 // External references never change their positioning 4294 // nor point to parts that will be removed or expanded. 4295 // In fact, calling ScRefUpdate::Update() for URM_MOVE 4296 // may have negative side effects. Simply adapt 4297 // relative references to the new position. 4298 t->CalcRelFromAbs( aPos); 4299 break; 4300 case svSingleRef: 4301 { 4302 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, 4303 aPos, r, nDx, nDy, nDz, 4304 SingleDoubleRefModifier( 4305 t->GetSingleRef()).Ref()) 4306 != UR_NOTHING) 4307 rChanged = sal_True; 4308 } 4309 break; 4310 default: 4311 { 4312 ScComplexRefData& rRef = t->GetDoubleRef(); 4313 SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol; 4314 SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow; 4315 SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab; 4316 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, 4317 aPos, r, nDx, nDy, nDz, 4318 t->GetDoubleRef()) != UR_NOTHING) 4319 { 4320 rChanged = sal_True; 4321 if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols || 4322 rRef.Ref2.nRow - rRef.Ref1.nRow != nRows || 4323 rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs) 4324 rRefSizeChanged = sal_True; 4325 } 4326 } 4327 } 4328 } 4329 } 4330 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4331 sal_Bool bEasyShared, bPosInRange; 4332 if ( !pRangeData ) 4333 bEasyShared = bPosInRange = sal_False; 4334 else 4335 { 4336 bEasyShared = sal_True; 4337 bPosInRange = r.In( eUpdateRefMode == URM_MOVE ? aPos : rOldPos ); 4338 } 4339 #endif 4340 pArr->Reset(); 4341 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4342 { 4343 if ( t->GetRef() != 1 ) 4344 { 4345 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4346 bEasyShared = sal_False; 4347 #endif 4348 } 4349 else 4350 { // if nRefCnt>1 it's already updated in token code 4351 if ( t->GetType() == svSingleRef ) 4352 { 4353 ScSingleRefData& rRef = t->GetSingleRef(); 4354 SingleDoubleRefModifier aMod( rRef ); 4355 if ( rRef.IsRelName() ) 4356 { 4357 ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, aMod.Ref() ); 4358 rChanged = sal_True; 4359 } 4360 else 4361 { 4362 aMod.Ref().CalcAbsIfRel( rOldPos ); 4363 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, 4364 r, nDx, nDy, nDz, aMod.Ref() ) 4365 != UR_NOTHING 4366 ) 4367 rChanged = sal_True; 4368 } 4369 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4370 if ( bEasyShared ) 4371 { 4372 const ScSingleRefData& rSRD = aMod.Ref().Ref1; 4373 ScAddress aRef( rSRD.nCol, rSRD.nRow, rSRD.nTab ); 4374 if ( r.In( aRef ) != bPosInRange ) 4375 bEasyShared = sal_False; 4376 } 4377 #endif 4378 } 4379 else 4380 { 4381 ScComplexRefData& rRef = t->GetDoubleRef(); 4382 SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol; 4383 SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow; 4384 SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab; 4385 if ( rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName() ) 4386 { 4387 ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, rRef ); 4388 rChanged = sal_True; 4389 } 4390 else 4391 { 4392 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, 4393 r, nDx, nDy, nDz, rRef ) 4394 != UR_NOTHING 4395 ) 4396 { 4397 rChanged = sal_True; 4398 if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols || 4399 rRef.Ref2.nRow - rRef.Ref1.nRow != nRows || 4400 rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs) 4401 { 4402 rRefSizeChanged = sal_True; 4403 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4404 bEasyShared = sal_False; 4405 #endif 4406 } 4407 } 4408 } 4409 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4410 if ( bEasyShared ) 4411 { 4412 ScRange aRef( rRef.Ref1.nCol, rRef.Ref1.nRow, 4413 rRef.Ref1.nTab, rRef.Ref2.nCol, rRef.Ref2.nRow, 4414 rRef.Ref2.nTab ); 4415 if ( r.In( aRef ) != bPosInRange ) 4416 bEasyShared = sal_False; 4417 } 4418 #endif 4419 } 4420 } 4421 } 4422 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4423 if ( pRangeData ) 4424 { 4425 if ( bEasyShared ) 4426 pRangeData = 0; 4427 else 4428 rChanged = sal_True; 4429 } 4430 #endif 4431 #undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 4432 return pRangeData; 4433 } 4434 } 4435 4436 sal_Bool ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode, 4437 const ScRange& r, 4438 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 4439 sal_Bool& rChanged, sal_Bool bSharedFormula) 4440 { 4441 sal_Bool bRelRef = sal_False; // set if relative reference 4442 rChanged = sal_False; 4443 pArr->Reset(); 4444 ScToken* t; 4445 while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL ) 4446 { 4447 SingleDoubleRefModifier aMod( *t ); 4448 ScComplexRefData& rRef = aMod.Ref(); 4449 bRelRef = rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || 4450 rRef.Ref1.IsTabRel(); 4451 if (!bRelRef && t->GetType() == svDoubleRef) 4452 bRelRef = rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || 4453 rRef.Ref2.IsTabRel(); 4454 bool bUpdate = !rRef.Ref1.IsColRel() || !rRef.Ref1.IsRowRel() || 4455 !rRef.Ref1.IsTabRel(); 4456 if (!bUpdate && t->GetType() == svDoubleRef) 4457 bUpdate = !rRef.Ref2.IsColRel() || !rRef.Ref2.IsRowRel() || 4458 !rRef.Ref2.IsTabRel(); 4459 if (!bSharedFormula) 4460 { 4461 // We cannot update names with sheet-relative references, they may 4462 // be used on other sheets as well and the resulting reference 4463 // would be wrong. This is a dilemma if col/row would need to be 4464 // updated for the current usage. 4465 // TODO: seems the only way out of this would be to not allow 4466 // relative sheet references and have sheet-local names that can be 4467 // copied along with sheets. 4468 bUpdate = bUpdate && !rRef.Ref1.IsTabRel() && !rRef.Ref2.IsTabRel(); 4469 } 4470 if (bUpdate) 4471 { 4472 rRef.CalcAbsIfRel( aPos); 4473 if (ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, r, 4474 nDx, nDy, nDz, rRef, ScRefUpdate::ABSOLUTE) 4475 != UR_NOTHING ) 4476 rChanged = sal_True; 4477 } 4478 } 4479 return bRelRef; 4480 } 4481 4482 4483 void ScCompiler::UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode, 4484 const ScAddress& rOldPos, const ScRange& r, 4485 SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 4486 { 4487 if ( eUpdateRefMode == URM_COPY ) 4488 return ; 4489 else 4490 { 4491 ScToken* t; 4492 pArr->Reset(); 4493 while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL ) 4494 { 4495 if( t->GetType() != svIndex ) // it may be a DB area!!! 4496 { 4497 t->CalcAbsIfRel( rOldPos ); 4498 // Absolute references have been already adjusted in the named 4499 // shared formula itself prior to breaking the shared formula 4500 // and calling this function. Don't readjust them again. 4501 SingleDoubleRefModifier aMod( *t ); 4502 ScComplexRefData& rRef = aMod.Ref(); 4503 ScComplexRefData aBkp = rRef; 4504 ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, 4505 r, nDx, nDy, nDz, rRef ); 4506 // restore absolute parts 4507 if ( !aBkp.Ref1.IsColRel() ) 4508 { 4509 rRef.Ref1.nCol = aBkp.Ref1.nCol; 4510 rRef.Ref1.nRelCol = aBkp.Ref1.nRelCol; 4511 rRef.Ref1.SetColDeleted( aBkp.Ref1.IsColDeleted() ); 4512 } 4513 if ( !aBkp.Ref1.IsRowRel() ) 4514 { 4515 rRef.Ref1.nRow = aBkp.Ref1.nRow; 4516 rRef.Ref1.nRelRow = aBkp.Ref1.nRelRow; 4517 rRef.Ref1.SetRowDeleted( aBkp.Ref1.IsRowDeleted() ); 4518 } 4519 if ( !aBkp.Ref1.IsTabRel() ) 4520 { 4521 rRef.Ref1.nTab = aBkp.Ref1.nTab; 4522 rRef.Ref1.nRelTab = aBkp.Ref1.nRelTab; 4523 rRef.Ref1.SetTabDeleted( aBkp.Ref1.IsTabDeleted() ); 4524 } 4525 if ( t->GetType() == svDoubleRef ) 4526 { 4527 if ( !aBkp.Ref2.IsColRel() ) 4528 { 4529 rRef.Ref2.nCol = aBkp.Ref2.nCol; 4530 rRef.Ref2.nRelCol = aBkp.Ref2.nRelCol; 4531 rRef.Ref2.SetColDeleted( aBkp.Ref2.IsColDeleted() ); 4532 } 4533 if ( !aBkp.Ref2.IsRowRel() ) 4534 { 4535 rRef.Ref2.nRow = aBkp.Ref2.nRow; 4536 rRef.Ref2.nRelRow = aBkp.Ref2.nRelRow; 4537 rRef.Ref2.SetRowDeleted( aBkp.Ref2.IsRowDeleted() ); 4538 } 4539 if ( !aBkp.Ref2.IsTabRel() ) 4540 { 4541 rRef.Ref2.nTab = aBkp.Ref2.nTab; 4542 rRef.Ref2.nRelTab = aBkp.Ref2.nRelTab; 4543 rRef.Ref2.SetTabDeleted( aBkp.Ref2.IsTabDeleted() ); 4544 } 4545 } 4546 } 4547 } 4548 } 4549 } 4550 4551 4552 ScRangeData* ScCompiler::UpdateInsertTab( SCTAB nTable, sal_Bool bIsName ) 4553 { 4554 ScRangeData* pRangeData = NULL; 4555 SCTAB nPosTab = aPos.Tab(); // _after_ incremented! 4556 SCTAB nOldPosTab = ((nPosTab > nTable) ? (nPosTab - 1) : nPosTab); 4557 sal_Bool bIsRel = sal_False; 4558 ScToken* t; 4559 pArr->Reset(); 4560 if (bIsName) 4561 t = static_cast<ScToken*>(pArr->GetNextReference()); 4562 else 4563 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4564 while( t ) 4565 { 4566 if( t->GetOpCode() == ocName ) 4567 { 4568 if (!bIsName) 4569 { 4570 ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4571 if (pName && pName->HasType(RT_SHAREDMOD)) 4572 pRangeData = pName; 4573 } 4574 } 4575 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4576 { 4577 if ( !(bIsName && t->GetSingleRef().IsTabRel()) ) 4578 { // of names only adjust absolute references 4579 ScSingleRefData& rRef = t->GetSingleRef(); 4580 if ( rRef.IsTabRel() ) 4581 { 4582 rRef.nTab = rRef.nRelTab + nOldPosTab; 4583 if ( rRef.nTab < 0 ) 4584 rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap 4585 } 4586 if (nTable <= rRef.nTab) 4587 ++rRef.nTab; 4588 rRef.nRelTab = rRef.nTab - nPosTab; 4589 } 4590 else 4591 bIsRel = sal_True; 4592 if ( t->GetType() == svDoubleRef ) 4593 { 4594 if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) ) 4595 { // of names only adjust absolute references 4596 ScSingleRefData& rRef = t->GetDoubleRef().Ref2; 4597 if ( rRef.IsTabRel() ) 4598 { 4599 rRef.nTab = rRef.nRelTab + nOldPosTab; 4600 if ( rRef.nTab < 0 ) 4601 rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap 4602 } 4603 if (nTable <= rRef.nTab) 4604 ++rRef.nTab; 4605 rRef.nRelTab = rRef.nTab - nPosTab; 4606 } 4607 else 4608 bIsRel = sal_True; 4609 } 4610 if ( bIsName && bIsRel ) 4611 pRangeData = (ScRangeData*) this; // not dereferenced in rangenam 4612 } 4613 if (bIsName) 4614 t = static_cast<ScToken*>(pArr->GetNextReference()); 4615 else 4616 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4617 } 4618 if ( !bIsName ) 4619 { 4620 pArr->Reset(); 4621 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4622 { 4623 if ( t->GetRef() == 1 ) 4624 { 4625 ScSingleRefData& rRef1 = t->GetSingleRef(); 4626 if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) ) 4627 { // of names only adjust absolute references 4628 if ( rRef1.IsTabRel() ) 4629 { 4630 rRef1.nTab = rRef1.nRelTab + nOldPosTab; 4631 if ( rRef1.nTab < 0 ) 4632 rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + pDoc->GetTableCount() ); // was a wrap 4633 } 4634 if (nTable <= rRef1.nTab) 4635 ++rRef1.nTab; 4636 rRef1.nRelTab = rRef1.nTab - nPosTab; 4637 } 4638 if ( t->GetType() == svDoubleRef ) 4639 { 4640 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4641 if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) ) 4642 { // of names only adjust absolute references 4643 if ( rRef2.IsTabRel() ) 4644 { 4645 rRef2.nTab = rRef2.nRelTab + nOldPosTab; 4646 if ( rRef2.nTab < 0 ) 4647 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + pDoc->GetTableCount() ); // was a wrap 4648 } 4649 if (nTable <= rRef2.nTab) 4650 ++rRef2.nTab; 4651 rRef2.nRelTab = rRef2.nTab - nPosTab; 4652 } 4653 } 4654 } 4655 } 4656 } 4657 return pRangeData; 4658 } 4659 4660 ScRangeData* ScCompiler::UpdateDeleteTab(SCTAB nTable, sal_Bool /* bIsMove */, sal_Bool bIsName, 4661 sal_Bool& rChanged) 4662 { 4663 ScRangeData* pRangeData = NULL; 4664 SCTAB nTab, nTab2; 4665 SCTAB nPosTab = aPos.Tab(); // _after_ decremented! 4666 SCTAB nOldPosTab = ((nPosTab >= nTable) ? (nPosTab + 1) : nPosTab); 4667 rChanged = sal_False; 4668 sal_Bool bIsRel = sal_False; 4669 ScToken* t; 4670 pArr->Reset(); 4671 if (bIsName) 4672 t = static_cast<ScToken*>(pArr->GetNextReference()); 4673 else 4674 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4675 while( t ) 4676 { 4677 if( t->GetOpCode() == ocName ) 4678 { 4679 if (!bIsName) 4680 { 4681 ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4682 if (pName && pName->HasType(RT_SHAREDMOD)) 4683 pRangeData = pName; 4684 } 4685 rChanged = sal_True; 4686 } 4687 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4688 { 4689 if ( !(bIsName && t->GetSingleRef().IsTabRel()) ) 4690 { // of names only adjust absolute references 4691 ScSingleRefData& rRef = t->GetSingleRef(); 4692 if ( rRef.IsTabRel() ) 4693 nTab = rRef.nTab = rRef.nRelTab + nOldPosTab; 4694 else 4695 nTab = rRef.nTab; 4696 if ( nTable < nTab ) 4697 { 4698 rRef.nTab = nTab - 1; 4699 rChanged = sal_True; 4700 } 4701 else if ( nTable == nTab ) 4702 { 4703 if ( t->GetType() == svDoubleRef ) 4704 { 4705 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4706 if ( rRef2.IsTabRel() ) 4707 nTab2 = rRef2.nRelTab + nOldPosTab; 4708 else 4709 nTab2 = rRef2.nTab; 4710 if ( nTab == nTab2 4711 || (nTab+1) >= pDoc->GetTableCount() ) 4712 { 4713 rRef.nTab = MAXTAB+1; 4714 rRef.SetTabDeleted( sal_True ); 4715 } 4716 // else: nTab later points to what's nTable+1 now 4717 // => area shrunk 4718 } 4719 else 4720 { 4721 rRef.nTab = MAXTAB+1; 4722 rRef.SetTabDeleted( sal_True ); 4723 } 4724 rChanged = sal_True; 4725 } 4726 rRef.nRelTab = rRef.nTab - nPosTab; 4727 } 4728 else 4729 bIsRel = sal_True; 4730 if ( t->GetType() == svDoubleRef ) 4731 { 4732 if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) ) 4733 { // of names only adjust absolute references 4734 ScSingleRefData& rRef = t->GetDoubleRef().Ref2; 4735 if ( rRef.IsTabRel() ) 4736 nTab = rRef.nTab = rRef.nRelTab + nOldPosTab; 4737 else 4738 nTab = rRef.nTab; 4739 if ( nTable < nTab ) 4740 { 4741 rRef.nTab = nTab - 1; 4742 rChanged = sal_True; 4743 } 4744 else if ( nTable == nTab ) 4745 { 4746 if ( !t->GetDoubleRef().Ref1.IsTabDeleted() ) 4747 rRef.nTab = nTab - 1; // shrink area 4748 else 4749 { 4750 rRef.nTab = MAXTAB+1; 4751 rRef.SetTabDeleted( sal_True ); 4752 } 4753 rChanged = sal_True; 4754 } 4755 rRef.nRelTab = rRef.nTab - nPosTab; 4756 } 4757 else 4758 bIsRel = sal_True; 4759 } 4760 if ( bIsName && bIsRel ) 4761 pRangeData = (ScRangeData*) this; // not dereferenced in rangenam 4762 } 4763 if (bIsName) 4764 t = static_cast<ScToken*>(pArr->GetNextReference()); 4765 else 4766 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4767 } 4768 if ( !bIsName ) 4769 { 4770 pArr->Reset(); 4771 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4772 { 4773 if ( t->GetRef() == 1 ) 4774 { 4775 ScSingleRefData& rRef1 = t->GetSingleRef(); 4776 if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) ) 4777 { // of names only adjust absolute references 4778 if ( rRef1.IsTabRel() ) 4779 nTab = rRef1.nTab = rRef1.nRelTab + nOldPosTab; 4780 else 4781 nTab = rRef1.nTab; 4782 if ( nTable < nTab ) 4783 { 4784 rRef1.nTab = nTab - 1; 4785 rChanged = sal_True; 4786 } 4787 else if ( nTable == nTab ) 4788 { 4789 if ( t->GetType() == svDoubleRef ) 4790 { 4791 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4792 if ( rRef2.IsTabRel() ) 4793 nTab2 = rRef2.nRelTab + nOldPosTab; 4794 else 4795 nTab2 = rRef2.nTab; 4796 if ( nTab == nTab2 4797 || (nTab+1) >= pDoc->GetTableCount() ) 4798 { 4799 rRef1.nTab = MAXTAB+1; 4800 rRef1.SetTabDeleted( sal_True ); 4801 } 4802 // else: nTab later points to what's nTable+1 now 4803 // => area shrunk 4804 } 4805 else 4806 { 4807 rRef1.nTab = MAXTAB+1; 4808 rRef1.SetTabDeleted( sal_True ); 4809 } 4810 rChanged = sal_True; 4811 } 4812 rRef1.nRelTab = rRef1.nTab - nPosTab; 4813 } 4814 if ( t->GetType() == svDoubleRef ) 4815 { 4816 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4817 if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) ) 4818 { // of names only adjust absolute references 4819 if ( rRef2.IsTabRel() ) 4820 nTab = rRef2.nTab = rRef2.nRelTab + nOldPosTab; 4821 else 4822 nTab = rRef2.nTab; 4823 if ( nTable < nTab ) 4824 { 4825 rRef2.nTab = nTab - 1; 4826 rChanged = sal_True; 4827 } 4828 else if ( nTable == nTab ) 4829 { 4830 if ( !rRef1.IsTabDeleted() ) 4831 rRef2.nTab = nTab - 1; // shrink area 4832 else 4833 { 4834 rRef2.nTab = MAXTAB+1; 4835 rRef2.SetTabDeleted( sal_True ); 4836 } 4837 rChanged = sal_True; 4838 } 4839 rRef2.nRelTab = rRef2.nTab - nPosTab; 4840 } 4841 } 4842 } 4843 } 4844 } 4845 return pRangeData; 4846 } 4847 4848 // aPos.Tab() must be already adjusted! 4849 ScRangeData* ScCompiler::UpdateMoveTab( SCTAB nOldTab, SCTAB nNewTab, 4850 sal_Bool bIsName ) 4851 { 4852 ScRangeData* pRangeData = NULL; 4853 SCsTAB nTab; 4854 4855 SCTAB nStart, nEnd; 4856 short nDir; // direction in which others move 4857 if ( nOldTab < nNewTab ) 4858 { 4859 nDir = -1; 4860 nStart = nOldTab; 4861 nEnd = nNewTab; 4862 } 4863 else 4864 { 4865 nDir = 1; 4866 nStart = nNewTab; 4867 nEnd = nOldTab; 4868 } 4869 SCTAB nPosTab = aPos.Tab(); // current sheet 4870 SCTAB nOldPosTab; // previously it was this one 4871 if ( nPosTab == nNewTab ) 4872 nOldPosTab = nOldTab; // look, it's me! 4873 else if ( nPosTab < nStart || nEnd < nPosTab ) 4874 nOldPosTab = nPosTab; // wasn't moved 4875 else 4876 nOldPosTab = nPosTab - nDir; // moved by one 4877 4878 sal_Bool bIsRel = sal_False; 4879 ScToken* t; 4880 pArr->Reset(); 4881 if (bIsName) 4882 t = static_cast<ScToken*>(pArr->GetNextReference()); 4883 else 4884 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4885 while( t ) 4886 { 4887 if( t->GetOpCode() == ocName ) 4888 { 4889 if (!bIsName) 4890 { 4891 ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex()); 4892 if (pName && pName->HasType(RT_SHAREDMOD)) 4893 pRangeData = pName; 4894 } 4895 } 4896 else if( t->GetType() != svIndex ) // it may be a DB area!!! 4897 { 4898 ScSingleRefData& rRef1 = t->GetSingleRef(); 4899 if ( !(bIsName && rRef1.IsTabRel()) ) 4900 { // of names only adjust absolute references 4901 if ( rRef1.IsTabRel() ) 4902 nTab = rRef1.nRelTab + nOldPosTab; 4903 else 4904 nTab = rRef1.nTab; 4905 if ( nTab == nOldTab ) 4906 rRef1.nTab = nNewTab; 4907 else if ( nStart <= nTab && nTab <= nEnd ) 4908 rRef1.nTab = nTab + nDir; 4909 rRef1.nRelTab = rRef1.nTab - nPosTab; 4910 } 4911 else 4912 bIsRel = sal_True; 4913 if ( t->GetType() == svDoubleRef ) 4914 { 4915 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4916 if ( !(bIsName && rRef2.IsTabRel()) ) 4917 { // of names only adjust absolute references 4918 if ( rRef2.IsTabRel() ) 4919 nTab = rRef2.nRelTab + nOldPosTab; 4920 else 4921 nTab = rRef2.nTab; 4922 if ( nTab == nOldTab ) 4923 rRef2.nTab = nNewTab; 4924 else if ( nStart <= nTab && nTab <= nEnd ) 4925 rRef2.nTab = nTab + nDir; 4926 rRef2.nRelTab = rRef2.nTab - nPosTab; 4927 } 4928 else 4929 bIsRel = sal_True; 4930 SCsTAB nTab1, nTab2; 4931 if ( rRef1.IsTabRel() ) 4932 nTab1 = rRef1.nRelTab + nPosTab; 4933 else 4934 nTab1 = rRef1.nTab; 4935 if ( rRef2.IsTabRel() ) 4936 nTab2 = rRef2.nRelTab + nPosTab; 4937 else 4938 nTab2 = rRef1.nTab; 4939 if ( nTab2 < nTab1 ) 4940 { // PutInOrder 4941 rRef1.nTab = nTab2; 4942 rRef2.nTab = nTab1; 4943 rRef1.nRelTab = rRef1.nTab - nPosTab; 4944 rRef2.nRelTab = rRef2.nTab - nPosTab; 4945 } 4946 } 4947 if ( bIsName && bIsRel ) 4948 pRangeData = (ScRangeData*) this; // not dereferenced in rangenam 4949 } 4950 if (bIsName) 4951 t = static_cast<ScToken*>(pArr->GetNextReference()); 4952 else 4953 t = static_cast<ScToken*>(pArr->GetNextReferenceOrName()); 4954 } 4955 if ( !bIsName ) 4956 { 4957 SCsTAB nMaxTabMod = (SCsTAB) pDoc->GetTableCount(); 4958 pArr->Reset(); 4959 while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL ) 4960 { 4961 if ( t->GetRef() == 1 ) 4962 { 4963 ScSingleRefData& rRef1 = t->GetSingleRef(); 4964 if ( rRef1.IsRelName() && rRef1.IsTabRel() ) 4965 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx 4966 nTab = rRef1.nRelTab + nPosTab; 4967 if ( nTab < 0 ) 4968 nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod ); 4969 else if ( nTab > nMaxTab ) 4970 nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod ); 4971 rRef1.nRelTab = nTab - nPosTab; 4972 } 4973 else 4974 { 4975 if ( rRef1.IsTabRel() ) 4976 nTab = rRef1.nRelTab + nOldPosTab; 4977 else 4978 nTab = rRef1.nTab; 4979 if ( nTab == nOldTab ) 4980 rRef1.nTab = nNewTab; 4981 else if ( nStart <= nTab && nTab <= nEnd ) 4982 rRef1.nTab = nTab + nDir; 4983 rRef1.nRelTab = rRef1.nTab - nPosTab; 4984 } 4985 if( t->GetType() == svDoubleRef ) 4986 { 4987 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 4988 if ( rRef2.IsRelName() && rRef2.IsTabRel() ) 4989 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx 4990 nTab = rRef2.nRelTab + nPosTab; 4991 if ( nTab < 0 ) 4992 nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod ); 4993 else if ( nTab > nMaxTab ) 4994 nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod ); 4995 rRef2.nRelTab = nTab - nPosTab; 4996 } 4997 else 4998 { 4999 if ( rRef2.IsTabRel() ) 5000 nTab = rRef2.nRelTab + nOldPosTab; 5001 else 5002 nTab = rRef2.nTab; 5003 if ( nTab == nOldTab ) 5004 rRef2.nTab = nNewTab; 5005 else if ( nStart <= nTab && nTab <= nEnd ) 5006 rRef2.nTab = nTab + nDir; 5007 rRef2.nRelTab = rRef2.nTab - nPosTab; 5008 } 5009 SCsTAB nTab1, nTab2; 5010 if ( rRef1.IsTabRel() ) 5011 nTab1 = rRef1.nRelTab + nPosTab; 5012 else 5013 nTab1 = rRef1.nTab; 5014 if ( rRef2.IsTabRel() ) 5015 nTab2 = rRef2.nRelTab + nPosTab; 5016 else 5017 nTab2 = rRef1.nTab; 5018 if ( nTab2 < nTab1 ) 5019 { // PutInOrder 5020 rRef1.nTab = nTab2; 5021 rRef2.nTab = nTab1; 5022 rRef1.nRelTab = rRef1.nTab - nPosTab; 5023 rRef2.nRelTab = rRef2.nTab - nPosTab; 5024 } 5025 } 5026 } 5027 } 5028 } 5029 return pRangeData; 5030 } 5031 5032 5033 void ScCompiler::CreateStringFromExternal(rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP) 5034 { 5035 FormulaToken* t = pTokenP; 5036 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 5037 switch (t->GetType()) 5038 { 5039 case svExternalName: 5040 { 5041 const String *pStr = pRefMgr->getExternalFileName(t->GetIndex()); 5042 String aFileName = pStr ? *pStr : ScGlobal::GetRscString(STR_NO_NAME_REF); 5043 rBuffer.append(pConv->makeExternalNameStr( aFileName, t->GetString())); 5044 } 5045 break; 5046 case svExternalSingleRef: 5047 pConv->makeExternalRefStr( 5048 rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetSingleRef(), pRefMgr); 5049 break; 5050 case svExternalDoubleRef: 5051 pConv->makeExternalRefStr( 5052 rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetDoubleRef(), pRefMgr); 5053 break; 5054 default: 5055 // warning, not error, otherwise we may end up with a never 5056 // ending message box loop if this was the cursor cell to be redrawn. 5057 DBG_WARNING("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef"); 5058 } 5059 } 5060 5061 void ScCompiler::CreateStringFromMatrix( rtl::OUStringBuffer& rBuffer, 5062 FormulaToken* pTokenP) 5063 { 5064 const ScMatrix* pMatrix = static_cast<ScToken*>(pTokenP)->GetMatrix(); 5065 SCSIZE nC, nMaxC, nR, nMaxR; 5066 5067 pMatrix->GetDimensions( nMaxC, nMaxR); 5068 5069 rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) ); 5070 for( nR = 0 ; nR < nMaxR ; nR++) 5071 { 5072 if( nR > 0) 5073 { 5074 rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) ); 5075 } 5076 5077 for( nC = 0 ; nC < nMaxC ; nC++) 5078 { 5079 if( nC > 0) 5080 { 5081 rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) ); 5082 } 5083 5084 if( pMatrix->IsValue( nC, nR ) ) 5085 { 5086 ScMatValType nType; 5087 const ScMatrixValue* pVal = pMatrix->Get( nC, nR, nType); 5088 5089 if( nType == SC_MATVAL_BOOLEAN ) 5090 AppendBoolean( rBuffer, pVal->GetBoolean() ); 5091 else 5092 { 5093 sal_uInt16 nErr = pVal->GetError(); 5094 if( nErr ) 5095 rBuffer.append( ScGlobal::GetErrorString( nErr ) ); 5096 else 5097 AppendDouble( rBuffer, pVal->fVal ); 5098 } 5099 } 5100 else if( pMatrix->IsEmpty( nC, nR ) ) 5101 ; 5102 else if( pMatrix->IsString( nC, nR ) ) 5103 AppendString( rBuffer, pMatrix->GetString( nC, nR ) ); 5104 } 5105 } 5106 rBuffer.append( mxSymbols->getSymbol(ocArrayClose) ); 5107 } 5108 5109 void ScCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP) 5110 { 5111 const OpCode eOp = _pTokenP->GetOpCode(); 5112 ScSingleRefData& rRef = static_cast<ScToken*>(_pTokenP)->GetSingleRef(); 5113 ScComplexRefData aRef; 5114 aRef.Ref1 = aRef.Ref2 = rRef; 5115 if ( eOp == ocColRowName ) 5116 { 5117 rRef.CalcAbsIfRel( aPos ); 5118 if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) ) 5119 { 5120 String aStr; 5121 pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr ); 5122 EnQuote( aStr ); 5123 rBuffer.append(aStr); 5124 } 5125 else 5126 { 5127 rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); 5128 pConv->MakeRefStr (rBuffer, *this, aRef, sal_True ); 5129 } 5130 } 5131 else 5132 pConv->MakeRefStr( rBuffer, *this, aRef, sal_True ); 5133 } 5134 // ----------------------------------------------------------------------------- 5135 void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP) 5136 { 5137 pConv->MakeRefStr( rBuffer, *this, static_cast<ScToken*>(_pTokenP)->GetDoubleRef(), sal_False ); 5138 } 5139 // ----------------------------------------------------------------------------- 5140 void ScCompiler::CreateStringFromIndex(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP) 5141 { 5142 const OpCode eOp = _pTokenP->GetOpCode(); 5143 rtl::OUStringBuffer aBuffer; 5144 switch ( eOp ) 5145 { 5146 case ocName: 5147 { 5148 ScRangeData* pData = pDoc->GetRangeName()->FindIndex(_pTokenP->GetIndex()); 5149 if (pData) 5150 { 5151 if (pData->HasType(RT_SHARED)) 5152 pData->UpdateSymbol( aBuffer, aPos, GetGrammar()); 5153 else 5154 aBuffer.append(pData->GetName()); 5155 } 5156 } 5157 break; 5158 case ocDBArea: 5159 { 5160 ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(_pTokenP->GetIndex()); 5161 if (pDBData) 5162 aBuffer.append(pDBData->GetName()); 5163 } 5164 break; 5165 default: 5166 ; // nothing 5167 } 5168 if ( aBuffer.getLength() ) 5169 rBuffer.append(aBuffer); 5170 else 5171 rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); 5172 } 5173 // ----------------------------------------------------------------------------- 5174 void ScCompiler::LocalizeString( String& rName ) 5175 { 5176 ScGlobal::GetAddInCollection()->LocalizeString( rName ); 5177 } 5178 // ----------------------------------------------------------------------------- 5179 sal_Bool ScCompiler::IsImportingXML() const 5180 { 5181 return pDoc->IsImportingXML(); 5182 } 5183 5184 // Put quotes around string if non-alphanumeric characters are contained, 5185 // quote characters contained within are escaped by '\\'. 5186 sal_Bool ScCompiler::EnQuote( String& rStr ) 5187 { 5188 sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.Len() ); 5189 if ( !CharClass::isNumericType( nType ) 5190 && CharClass::isAlphaNumericType( nType ) ) 5191 return sal_False; 5192 5193 xub_StrLen nPos = 0; 5194 while ( (nPos = rStr.Search( '\'', nPos)) != STRING_NOTFOUND ) 5195 { 5196 rStr.Insert( '\\', nPos ); 5197 nPos += 2; 5198 } 5199 rStr.Insert( '\'', 0 ); 5200 rStr += '\''; 5201 return sal_True; 5202 } 5203 5204 sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const 5205 { 5206 return pConv->getSpecialSymbol(eType); 5207 } 5208 5209 void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const 5210 { 5211 // All known AddIn functions. 5212 sheet::FormulaOpCodeMapEntry aEntry; 5213 aEntry.Token.OpCode = ocExternal; 5214 5215 ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection(); 5216 const long nCount = pColl->GetFuncCount(); 5217 for (long i=0; i < nCount; ++i) 5218 { 5219 const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i); 5220 if (pFuncData) 5221 { 5222 if ( _bIsEnglish ) 5223 { 5224 String aName; 5225 if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName)) 5226 aEntry.Name = aName; 5227 else 5228 aEntry.Name = pFuncData->GetUpperName(); 5229 } 5230 else 5231 aEntry.Name = pFuncData->GetUpperLocal(); 5232 aEntry.Token.Data <<= ::rtl::OUString( pFuncData->GetOriginalName()); 5233 _rVec.push_back( aEntry); 5234 } 5235 } 5236 // FIXME: what about those old non-UNO AddIns? 5237 } 5238 // ----------------------------------------------------------------------------- 5239 sal_Bool ScCompiler::HandleSingleRef() 5240 { 5241 ScSingleRefData& rRef = static_cast<ScToken*>((FormulaToken*)pToken)->GetSingleRef(); 5242 rRef.CalcAbsIfRel( aPos ); 5243 if ( !rRef.Valid() ) 5244 { 5245 SetError( errNoRef ); 5246 return sal_True; 5247 } 5248 SCCOL nCol = rRef.nCol; 5249 SCROW nRow = rRef.nRow; 5250 SCTAB nTab = rRef.nTab; 5251 ScAddress aLook( nCol, nRow, nTab ); 5252 sal_Bool bColName = rRef.IsColRel(); 5253 SCCOL nMyCol = aPos.Col(); 5254 SCROW nMyRow = aPos.Row(); 5255 sal_Bool bInList = sal_False; 5256 sal_Bool bValidName = sal_False; 5257 ScRangePairList* pRL = (bColName ? 5258 pDoc->GetColNameRanges() : pDoc->GetRowNameRanges()); 5259 ScRange aRange; 5260 for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() ) 5261 { 5262 if ( pR->GetRange(0).In( aLook ) ) 5263 { 5264 bInList = bValidName = sal_True; 5265 aRange = pR->GetRange(1); 5266 if ( bColName ) 5267 { 5268 aRange.aStart.SetCol( nCol ); 5269 aRange.aEnd.SetCol( nCol ); 5270 } 5271 else 5272 { 5273 aRange.aStart.SetRow( nRow ); 5274 aRange.aEnd.SetRow( nRow ); 5275 } 5276 break; // for 5277 } 5278 } 5279 if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() ) 5280 { // automagically or created by copying and NamePos isn't in list 5281 sal_Bool bString = pDoc->HasStringData( nCol, nRow, nTab ); 5282 if ( !bString && !pDoc->GetCell( aLook ) ) 5283 bString = sal_True; // empty cell is ok 5284 if ( bString ) 5285 { //! coresponds with ScInterpreter::ScColRowNameAuto() 5286 bValidName = sal_True; 5287 if ( bColName ) 5288 { // ColName 5289 SCROW nStartRow = nRow + 1; 5290 if ( nStartRow > MAXROW ) 5291 nStartRow = MAXROW; 5292 SCROW nMaxRow = MAXROW; 5293 if ( nMyCol == nCol ) 5294 { // formula cell in same column 5295 if ( nMyRow == nStartRow ) 5296 { // take remainder under name cell 5297 nStartRow++; 5298 if ( nStartRow > MAXROW ) 5299 nStartRow = MAXROW; 5300 } 5301 else if ( nMyRow > nStartRow ) 5302 { // from name cell down to formula cell 5303 nMaxRow = nMyRow - 1; 5304 } 5305 } 5306 for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() ) 5307 { // next defined ColNameRange below limits row 5308 const ScRange& rRange = pR->GetRange(1); 5309 if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() ) 5310 { // identical column range 5311 SCROW nTmp = rRange.aStart.Row(); 5312 if ( nStartRow < nTmp && nTmp <= nMaxRow ) 5313 nMaxRow = nTmp - 1; 5314 } 5315 } 5316 aRange.aStart.Set( nCol, nStartRow, nTab ); 5317 aRange.aEnd.Set( nCol, nMaxRow, nTab ); 5318 } 5319 else 5320 { // RowName 5321 SCCOL nStartCol = nCol + 1; 5322 if ( nStartCol > MAXCOL ) 5323 nStartCol = MAXCOL; 5324 SCCOL nMaxCol = MAXCOL; 5325 if ( nMyRow == nRow ) 5326 { // formula cell in same row 5327 if ( nMyCol == nStartCol ) 5328 { // take remainder right from name cell 5329 nStartCol++; 5330 if ( nStartCol > MAXCOL ) 5331 nStartCol = MAXCOL; 5332 } 5333 else if ( nMyCol > nStartCol ) 5334 { // from name cell right to formula cell 5335 nMaxCol = nMyCol - 1; 5336 } 5337 } 5338 for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() ) 5339 { // next defined RowNameRange to the right limits column 5340 const ScRange& rRange = pR->GetRange(1); 5341 if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() ) 5342 { // identical row range 5343 SCCOL nTmp = rRange.aStart.Col(); 5344 if ( nStartCol < nTmp && nTmp <= nMaxCol ) 5345 nMaxCol = nTmp - 1; 5346 } 5347 } 5348 aRange.aStart.Set( nStartCol, nRow, nTab ); 5349 aRange.aEnd.Set( nMaxCol, nRow, nTab ); 5350 } 5351 } 5352 } 5353 if ( bValidName ) 5354 { 5355 // And now the magic to distinguish between a range and a single 5356 // cell thereof, which is picked position-dependent of the formula 5357 // cell. If a direct neighbor is a binary operator (ocAdd, ...) a 5358 // SingleRef matching the column/row of the formula cell is 5359 // generated. A ocColRowName or ocIntersect as a neighbor results 5360 // in a range. Special case: if label is valid for a single cell, a 5361 // position independent SingleRef is generated. 5362 sal_Bool bSingle = (aRange.aStart == aRange.aEnd); 5363 sal_Bool bFound; 5364 if ( bSingle ) 5365 bFound = sal_True; 5366 else 5367 { 5368 FormulaToken* p1 = pArr->PeekPrevNoSpaces(); 5369 FormulaToken* p2 = pArr->PeekNextNoSpaces(); 5370 // begin/end of a formula => single 5371 OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd ); 5372 OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd ); 5373 if ( eOp1 != ocColRowName && eOp1 != ocIntersect 5374 && eOp2 != ocColRowName && eOp2 != ocIntersect ) 5375 { 5376 if ( (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) || 5377 (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP)) 5378 bSingle = sal_True; 5379 } 5380 if ( bSingle ) 5381 { // column and/or row must match range 5382 if ( bColName ) 5383 { 5384 bFound = (aRange.aStart.Row() <= nMyRow 5385 && nMyRow <= aRange.aEnd.Row()); 5386 if ( bFound ) 5387 aRange.aStart.SetRow( nMyRow ); 5388 } 5389 else 5390 { 5391 bFound = (aRange.aStart.Col() <= nMyCol 5392 && nMyCol <= aRange.aEnd.Col()); 5393 if ( bFound ) 5394 aRange.aStart.SetCol( nMyCol ); 5395 } 5396 } 5397 else 5398 bFound = sal_True; 5399 } 5400 if ( !bFound ) 5401 SetError(errNoRef); 5402 else if ( !bCompileForFAP ) 5403 { 5404 ScTokenArray* pNew = new ScTokenArray(); 5405 if ( bSingle ) 5406 { 5407 ScSingleRefData aRefData; 5408 aRefData.InitAddress( aRange.aStart ); 5409 if ( bColName ) 5410 aRefData.SetColRel( sal_True ); 5411 else 5412 aRefData.SetRowRel( sal_True ); 5413 aRefData.CalcRelFromAbs( aPos ); 5414 pNew->AddSingleReference( aRefData ); 5415 } 5416 else 5417 { 5418 ScComplexRefData aRefData; 5419 aRefData.InitRange( aRange ); 5420 if ( bColName ) 5421 { 5422 aRefData.Ref1.SetColRel( sal_True ); 5423 aRefData.Ref2.SetColRel( sal_True ); 5424 } 5425 else 5426 { 5427 aRefData.Ref1.SetRowRel( sal_True ); 5428 aRefData.Ref2.SetRowRel( sal_True ); 5429 } 5430 aRefData.CalcRelFromAbs( aPos ); 5431 if ( bInList ) 5432 pNew->AddDoubleReference( aRefData ); 5433 else 5434 { // automagically 5435 pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) ); 5436 } 5437 } 5438 PushTokenArray( pNew, sal_True ); 5439 pNew->Reset(); 5440 return GetToken(); 5441 } 5442 } 5443 else 5444 SetError(errNoName); 5445 return sal_True; 5446 } 5447 // ----------------------------------------------------------------------------- 5448 sal_Bool ScCompiler::HandleDbData() 5449 { 5450 ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex( pToken->GetIndex() ); 5451 if ( !pDBData ) 5452 SetError(errNoName); 5453 else if ( !bCompileForFAP ) 5454 { 5455 ScComplexRefData aRefData; 5456 aRefData.InitFlags(); 5457 pDBData->GetArea( (SCTAB&) aRefData.Ref1.nTab, 5458 (SCCOL&) aRefData.Ref1.nCol, 5459 (SCROW&) aRefData.Ref1.nRow, 5460 (SCCOL&) aRefData.Ref2.nCol, 5461 (SCROW&) aRefData.Ref2.nRow); 5462 aRefData.Ref2.nTab = aRefData.Ref1.nTab; 5463 aRefData.CalcRelFromAbs( aPos ); 5464 ScTokenArray* pNew = new ScTokenArray(); 5465 pNew->AddDoubleReference( aRefData ); 5466 PushTokenArray( pNew, sal_True ); 5467 pNew->Reset(); 5468 return GetToken(); 5469 } 5470 return sal_True; 5471 } 5472 5473 String GetScCompilerNativeSymbol( OpCode eOp ) 5474 { 5475 return ScCompiler::GetNativeSymbol( eOp ); 5476 } 5477 // ----------------------------------------------------------------------------- 5478 FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef ) 5479 { 5480 return ScToken::ExtendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef ); 5481 } 5482