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