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