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