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