LCOV - code coverage report
Current view: top level - sc/source/core/tool - compiler.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 2295 0.0 %
Date: 2014-04-14 Functions: 0 141 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "compiler.hxx"
      21             : 
      22             : #include <sfx2/app.hxx>
      23             : #include <sfx2/objsh.hxx>
      24             : #include <basic/sbmeth.hxx>
      25             : #include <basic/sbstar.hxx>
      26             : #include <svl/zforlist.hxx>
      27             : #include "svl/sharedstringpool.hxx"
      28             : #include <sal/macros.h>
      29             : #include <tools/rcid.h>
      30             : #include <tools/solar.h>
      31             : #include <unotools/charclass.hxx>
      32             : #include <com/sun/star/lang/Locale.hpp>
      33             : #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
      34             : #include <com/sun/star/sheet/FormulaLanguage.hpp>
      35             : #include <com/sun/star/sheet/FormulaMapGroup.hpp>
      36             : #include <comphelper/processfactory.hxx>
      37             : #include <comphelper/string.hxx>
      38             : #include <unotools/transliterationwrapper.hxx>
      39             : #include <tools/urlobj.hxx>
      40             : #include <rtl/math.hxx>
      41             : #include <rtl/ustring.hxx>
      42             : #include <svtools/miscopt.hxx>
      43             : #include <ctype.h>
      44             : #include <stdio.h>
      45             : #include <stdlib.h>
      46             : #include <string.h>
      47             : #include <math.h>
      48             : #include "rangenam.hxx"
      49             : #include "dbdata.hxx"
      50             : #include "document.hxx"
      51             : #include "callform.hxx"
      52             : #include "addincol.hxx"
      53             : #include "refupdat.hxx"
      54             : #include "scresid.hxx"
      55             : #include "sc.hrc"
      56             : #include "globstr.hrc"
      57             : #include "formulacell.hxx"
      58             : #include "dociter.hxx"
      59             : #include "docoptio.hxx"
      60             : #include <formula/errorcodes.hxx>
      61             : #include "parclass.hxx"
      62             : #include "autonamecache.hxx"
      63             : #include "externalrefmgr.hxx"
      64             : #include "rangeutl.hxx"
      65             : #include "convuno.hxx"
      66             : #include "tokenuno.hxx"
      67             : #include "formulaparserpool.hxx"
      68             : #include "tokenarray.hxx"
      69             : #include "scmatrix.hxx"
      70             : #include <tokenstringcontext.hxx>
      71             : 
      72             : using namespace formula;
      73             : using namespace ::com::sun::star;
      74             : using ::std::vector;
      75             : 
      76             : CharClass*                          ScCompiler::pCharClassEnglish = NULL;
      77             : const ScCompiler::Convention*       ScCompiler::pConventions[ ]   = { NULL, NULL, NULL, NULL, NULL, NULL };
      78             : 
      79             : enum ScanState
      80             : {
      81             :     ssGetChar,
      82             :     ssGetBool,
      83             :     ssGetValue,
      84             :     ssGetString,
      85             :     ssSkipString,
      86             :     ssGetIdent,
      87             :     ssGetReference,
      88             :     ssSkipReference,
      89             :     ssGetErrorConstant,
      90             :     ssStop
      91             : };
      92             : 
      93             : static const sal_Char* pInternal[2] = { "TTT", "__DEBUG_VAR" };
      94             : 
      95             : using namespace ::com::sun::star::i18n;
      96             : 
      97             : class ScCompilerRecursionGuard
      98             : {
      99             : private:
     100             :             short&              rRecursion;
     101             : public:
     102             :                                 ScCompilerRecursionGuard( short& rRec )
     103             :                                     : rRecursion( rRec ) { ++rRecursion; }
     104             :                                 ~ScCompilerRecursionGuard() { --rRecursion; }
     105             : };
     106             : 
     107           0 : void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap,FormulaGrammar::Grammar _eGrammar  ) const
     108             : {
     109             :     size_t nSymbolOffset;
     110           0 :     switch( _eGrammar )
     111             :     {
     112             :         case FormulaGrammar::GRAM_PODF:
     113           0 :             nSymbolOffset = offsetof( AddInMap, pUpper);
     114           0 :             break;
     115             :         default:
     116             :         case FormulaGrammar::GRAM_ODFF:
     117           0 :             nSymbolOffset = offsetof( AddInMap, pODFF);
     118           0 :             break;
     119             :         case FormulaGrammar::GRAM_ENGLISH:
     120           0 :             nSymbolOffset = offsetof( AddInMap, pEnglish);
     121           0 :             break;
     122             :     }
     123           0 :     const AddInMap* pMap = GetAddInMap();
     124           0 :     const AddInMap* const pStop = pMap + GetAddInMapCount();
     125           0 :     for ( ; pMap < pStop; ++pMap)
     126             :     {
     127             :         char const * const * ppSymbol =
     128             :             reinterpret_cast< char const * const * >(
     129           0 :                     reinterpret_cast< char const * >(pMap) + nSymbolOffset);
     130             :         xMap->putExternal( OUString::createFromAscii( *ppSymbol),
     131           0 :                 OUString::createFromAscii( pMap->pOriginal));
     132             :     }
     133           0 : }
     134             : 
     135           0 : void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const
     136             : {
     137           0 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
     138           0 :     long nCount = pColl->GetFuncCount();
     139           0 :     for (long i=0; i < nCount; ++i)
     140             :     {
     141           0 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
     142           0 :         if (pFuncData)
     143           0 :             xMap->putExternalSoftly( pFuncData->GetUpperName(),
     144           0 :                     pFuncData->GetOriginalName());
     145             :     }
     146           0 : }
     147             : 
     148           0 : void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const
     149             : {
     150           0 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
     151           0 :     long nCount = pColl->GetFuncCount();
     152           0 :     for (long i=0; i < nCount; ++i)
     153             :     {
     154           0 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
     155           0 :         if (pFuncData)
     156             :         {
     157           0 :             OUString aName;
     158           0 :             if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
     159           0 :                 xMap->putExternalSoftly( aName, pFuncData->GetOriginalName());
     160             :             else
     161           0 :                 xMap->putExternalSoftly( pFuncData->GetUpperName(),
     162           0 :                         pFuncData->GetOriginalName());
     163             :         }
     164             :     }
     165           0 : }
     166             : 
     167           0 : void ScCompiler::DeInit()
     168             : {
     169           0 :     if (pCharClassEnglish)
     170             :     {
     171           0 :         delete pCharClassEnglish;
     172           0 :         pCharClassEnglish = NULL;
     173             :     }
     174           0 : }
     175             : 
     176           0 : bool ScCompiler::IsEnglishSymbol( const OUString& rName )
     177             : {
     178             :     // function names are always case-insensitive
     179           0 :     OUString aUpper = ScGlobal::pCharClass->uppercase(rName);
     180             : 
     181             :     // 1. built-in function name
     182           0 :     OpCode eOp = ScCompiler::GetEnglishOpCode( aUpper );
     183           0 :     if ( eOp != ocNone )
     184             :     {
     185           0 :         return true;
     186             :     }
     187             :     // 2. old add in functions
     188           0 :     if (ScGlobal::GetFuncCollection()->findByName(aUpper))
     189             :     {
     190           0 :         return true;
     191             :     }
     192             : 
     193             :     // 3. new (uno) add in functions
     194           0 :     OUString aIntName = ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
     195           0 :     if (!aIntName.isEmpty())
     196             :     {
     197           0 :         return true;
     198             :     }
     199           0 :     return false;       // no valid function name
     200             : }
     201             : 
     202           0 : void ScCompiler::InitCharClassEnglish()
     203             : {
     204           0 :     ::com::sun::star::lang::Locale aLocale( "en", "US", "");
     205             :     pCharClassEnglish = new CharClass(
     206           0 :             ::comphelper::getProcessComponentContext(), LanguageTag( aLocale));
     207           0 : }
     208             : 
     209           0 : void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
     210             : {
     211             :     OSL_ENSURE( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED");
     212           0 :     if (eGrammar == GetGrammar())
     213           0 :         return;     // nothing to be done
     214             : 
     215           0 :     if( eGrammar == FormulaGrammar::GRAM_EXTERNAL )
     216             :     {
     217           0 :         meGrammar = eGrammar;
     218           0 :         mxSymbols = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
     219             :     }
     220             :     else
     221             :     {
     222           0 :         FormulaGrammar::Grammar eMyGrammar = eGrammar;
     223           0 :         const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar);
     224           0 :         OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage);
     225             :         OSL_ENSURE( xMap, "ScCompiler::SetGrammar: unknown formula language");
     226           0 :         if (!xMap)
     227             :         {
     228           0 :             xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
     229           0 :             eMyGrammar = xMap->getGrammar();
     230             :         }
     231             : 
     232             :         // Save old grammar for call to SetGrammarAndRefConvention().
     233           0 :         FormulaGrammar::Grammar eOldGrammar = GetGrammar();
     234             :         // This also sets the grammar associated with the map!
     235           0 :         SetFormulaLanguage( xMap);
     236             : 
     237             :         // Override if necessary.
     238           0 :         if (eMyGrammar != GetGrammar())
     239           0 :             SetGrammarAndRefConvention( eMyGrammar, eOldGrammar);
     240             :     }
     241             : 
     242           0 :     if (pDoc && maTabNames.empty())
     243             :     {
     244           0 :         maTabNames = pDoc->GetAllTableNames();
     245           0 :         std::vector<OUString>::iterator it = maTabNames.begin(), itEnd = maTabNames.end();
     246           0 :         for (; it != itEnd; ++it)
     247           0 :             ScCompiler::CheckTabQuotes(*it, formula::FormulaGrammar::extractRefConvention(meGrammar));
     248             :     }
     249             : }
     250             : 
     251           0 : void ScCompiler::SetNumberFormatter( SvNumberFormatter* pFormatter )
     252             : {
     253           0 :     mpFormatter = pFormatter;
     254           0 : }
     255             : 
     256           0 : void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap )
     257             : {
     258           0 :     if (xMap.get())
     259             :     {
     260           0 :         mxSymbols = xMap;
     261           0 :         if (mxSymbols->isEnglish())
     262             :         {
     263           0 :             if (!pCharClassEnglish)
     264           0 :                 InitCharClassEnglish();
     265           0 :             pCharClass = pCharClassEnglish;
     266             :         }
     267             :         else
     268           0 :             pCharClass = ScGlobal::pCharClass;
     269           0 :         SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar());
     270             :     }
     271           0 : }
     272             : 
     273           0 : void ScCompiler::SetGrammarAndRefConvention(
     274             :         const FormulaGrammar::Grammar eNewGrammar, const FormulaGrammar::Grammar eOldGrammar )
     275             : {
     276           0 :     meGrammar = eNewGrammar;    //! SetRefConvention needs the new grammar set!
     277           0 :     FormulaGrammar::AddressConvention eConv = FormulaGrammar::extractRefConvention( meGrammar);
     278           0 :     if (eConv == FormulaGrammar::CONV_UNSPECIFIED && eOldGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
     279             :     {
     280           0 :         if (pDoc)
     281           0 :             SetRefConvention( pDoc->GetAddressConvention());
     282             :         else
     283           0 :             SetRefConvention( GetRefConvention( FormulaGrammar::CONV_OOO ) );
     284             :     }
     285             :     else
     286           0 :         SetRefConvention( eConv );
     287           0 : }
     288             : 
     289           0 : OUString ScCompiler::FindAddInFunction( const OUString& rUpperName, bool bLocalFirst ) const
     290             : {
     291           0 :     return ScGlobal::GetAddInCollection()->FindFunction(rUpperName, bLocalFirst);    // bLocalFirst=false for english
     292             : }
     293             : 
     294           0 : ScCompiler::Convention::~Convention()
     295             : {
     296           0 :     delete [] mpCharTable;
     297           0 :     mpCharTable = NULL;
     298           0 : }
     299             : 
     300           0 : ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv )
     301             :         :
     302           0 :     meConv( eConv )
     303             : {
     304             :     int i;
     305           0 :     sal_uLong *t= new sal_uLong [128];
     306             : 
     307           0 :     ScCompiler::pConventions[ meConv ] = this;
     308           0 :     mpCharTable = t;
     309             : 
     310           0 :     for (i = 0; i < 128; i++)
     311           0 :         t[i] = SC_COMPILER_C_ILLEGAL;
     312             : 
     313           0 : /*   */     t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     314           0 : /* ! */     t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     315           0 :             if (FormulaGrammar::CONV_ODF == meConv)
     316           0 : /* ! */         t[33] |= SC_COMPILER_C_ODF_LABEL_OP;
     317           0 : /* " */     t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP;
     318           0 : /* # */     t[35] = SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_CHAR_ERRCONST;
     319           0 : /* $ */     t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT;
     320           0 :             if (FormulaGrammar::CONV_ODF == meConv)
     321           0 : /* $ */         t[36] |= SC_COMPILER_C_ODF_NAME_MARKER;
     322           0 : /* % */     t[37] = SC_COMPILER_C_VALUE;
     323           0 : /* & */     t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     324           0 : /* ' */     t[39] = SC_COMPILER_C_NAME_SEP;
     325           0 : /* ( */     t[40] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     326           0 : /* ) */     t[41] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     327           0 : /* * */     t[42] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     328           0 : /* + */     t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
     329           0 : /* , */     t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE;
     330           0 : /* - */     t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
     331           0 : /* . */     t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
     332           0 : /* / */     t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     333             : 
     334           0 :             for (i = 48; i < 58; i++)
     335           0 : /* 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;
     336             : 
     337           0 : /* : */     t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD;
     338           0 : /* ; */     t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     339           0 : /* < */     t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     340           0 : /* = */     t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     341           0 : /* > */     t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     342           0 : /* ? */     t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME;
     343             : /* @ */     // FREE
     344             : 
     345           0 :     for (i = 65; i < 91; i++)
     346           0 : /* 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;
     347             : 
     348           0 :     if (FormulaGrammar::CONV_ODF == meConv)
     349             :     {
     350           0 : /* [ */     t[91] = SC_COMPILER_C_ODF_LBRACKET;
     351             : /* \ */     // FREE
     352           0 : /* ] */     t[93] = SC_COMPILER_C_ODF_RBRACKET;
     353             :     }
     354             :     else
     355             :     {
     356             : /* [ */     // FREE
     357             : /* \ */     // FREE
     358             : /* ] */     // FREE
     359             :     }
     360           0 : /* ^ */     t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     361           0 : /* _ */     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;
     362             : /* ` */     // FREE
     363             : 
     364           0 :             for (i = 97; i < 123; i++)
     365           0 : /* 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;
     366             : 
     367           0 : /* { */     t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open
     368           0 : /* | */     t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific)
     369           0 : /* } */     t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close
     370           0 : /* ~ */     t[126] = SC_COMPILER_C_CHAR;        // OOo specific
     371             : /* 127 */   // FREE
     372             : 
     373           0 :     if( FormulaGrammar::CONV_XL_A1 == meConv || FormulaGrammar::CONV_XL_R1C1 == meConv || FormulaGrammar::CONV_XL_OOX == meConv )
     374             :     {
     375           0 : /*   */     t[32] |=   SC_COMPILER_C_WORD;
     376           0 : /* ! */     t[33] |=   SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD;
     377           0 : /* " */     t[34] |=   SC_COMPILER_C_WORD;
     378           0 : /* # */     t[35] &= (~SC_COMPILER_C_WORD_SEP);
     379           0 : /* # */     t[35] |=   SC_COMPILER_C_WORD;
     380           0 : /* % */     t[37] |=   SC_COMPILER_C_WORD;
     381           0 : /* ' */     t[39] |=   SC_COMPILER_C_WORD;
     382             : 
     383           0 : /* % */     t[37] |=   SC_COMPILER_C_WORD;
     384           0 : /* & */     t[38] |=   SC_COMPILER_C_WORD;
     385           0 : /* ' */     t[39] |=   SC_COMPILER_C_WORD;
     386           0 : /* ( */     t[40] |=   SC_COMPILER_C_WORD;
     387           0 : /* ) */     t[41] |=   SC_COMPILER_C_WORD;
     388           0 : /* * */     t[42] |=   SC_COMPILER_C_WORD;
     389           0 : /* + */     t[43] |=   SC_COMPILER_C_WORD;
     390             : #if 0 /* this really needs to be locale specific. */
     391             : /* , */     t[44]  =   SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     392             : #else
     393           0 : /* , */     t[44] |=   SC_COMPILER_C_WORD;
     394             : #endif
     395           0 : /* - */     t[45] |=   SC_COMPILER_C_WORD;
     396             : 
     397           0 : /* ; */     t[59] |=   SC_COMPILER_C_WORD;
     398           0 : /* < */     t[60] |=   SC_COMPILER_C_WORD;
     399           0 : /* = */     t[61] |=   SC_COMPILER_C_WORD;
     400           0 : /* > */     t[62] |=   SC_COMPILER_C_WORD;
     401             : /* ? */     // question really is not permitted in sheet name
     402           0 : /* @ */     t[64] |=   SC_COMPILER_C_WORD;
     403           0 : /* [ */     t[91] |=   SC_COMPILER_C_WORD;
     404           0 : /* ] */     t[93] |=   SC_COMPILER_C_WORD;
     405           0 : /* { */     t[123]|=   SC_COMPILER_C_WORD;
     406           0 : /* | */     t[124]|=   SC_COMPILER_C_WORD;
     407           0 : /* } */     t[125]|=   SC_COMPILER_C_WORD;
     408           0 : /* ~ */     t[126]|=   SC_COMPILER_C_WORD;
     409             : 
     410           0 :         if( FormulaGrammar::CONV_XL_R1C1 == meConv )
     411             :         {
     412           0 : /* [ */     t[91] |= SC_COMPILER_C_IDENT;
     413           0 : /* ] */     t[93] |= SC_COMPILER_C_IDENT;
     414             :         }
     415           0 :         if( FormulaGrammar::CONV_XL_OOX == meConv )
     416             :         {
     417           0 : /* [ */     t[91] |= SC_COMPILER_C_CHAR_IDENT;
     418           0 : /* ] */     t[93] |= SC_COMPILER_C_IDENT;
     419             :         }
     420             :     }
     421           0 : }
     422             : 
     423           0 : static bool lcl_isValidQuotedText( const OUString& rFormula, sal_Int32 nSrcPos, ParseResult& rRes )
     424             : {
     425             :     // Tokens that start at ' can have anything in them until a final '
     426             :     // but '' marks an escaped '
     427             :     // We've earlier guaranteed that a string containing '' will be
     428             :     // surrounded by '
     429           0 :     if (rFormula[nSrcPos] == '\'')
     430             :     {
     431           0 :         sal_Int32 nPos = nSrcPos+1;
     432           0 :         while (nPos < rFormula.getLength())
     433             :         {
     434           0 :             if (rFormula[nPos] == '\'')
     435             :             {
     436           0 :                 if ( (nPos+1 == rFormula.getLength()) || (rFormula[nPos+1] != '\'') )
     437             :                 {
     438           0 :                     rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
     439           0 :                     rRes.EndPos = nPos+1;
     440           0 :                     return true;
     441             :                 }
     442           0 :                 ++nPos;
     443             :             }
     444           0 :             ++nPos;
     445             :         }
     446             :     }
     447             : 
     448           0 :     return false;
     449             : }
     450             : 
     451           0 : static bool lcl_parseExternalName(
     452             :         const OUString& rSymbol,
     453             :         OUString& rFile,
     454             :         OUString& rName,
     455             :         const sal_Unicode cSep,
     456             :         const ScDocument* pDoc = NULL,
     457             :         const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks = NULL )
     458             : {
     459             :     /* TODO: future versions will have to support sheet-local names too, thus
     460             :      * return a possible sheet name as well. */
     461           0 :     const sal_Unicode* const pStart = rSymbol.getStr();
     462           0 :     const sal_Unicode* p = pStart;
     463           0 :     sal_Int32 nLen = rSymbol.getLength();
     464           0 :     sal_Unicode cPrev = 0;
     465           0 :     OUString aTmpFile, aTmpName;
     466           0 :     sal_Int32 i = 0;
     467           0 :     bool bInName = false;
     468           0 :     if (cSep == '!')
     469             :     {
     470             :         // For XL use existing parser that resolves bracketed and quoted and
     471             :         // indexed external document names.
     472           0 :         ScRange aRange;
     473           0 :         OUString aStartTabName, aEndTabName;
     474           0 :         sal_uInt16 nFlags = 0;
     475             :         p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName,
     476           0 :                 aEndTabName, nFlags, true, pExternalLinks );
     477           0 :         if (!p || p == pStart)
     478           0 :             return false;
     479           0 :         i = sal_Int32(p - pStart);
     480           0 :         cPrev = *(p-1);
     481             :     }
     482           0 :     for ( ; i < nLen; ++i, ++p)
     483             :     {
     484           0 :         sal_Unicode c = *p;
     485           0 :         if (i == 0)
     486             :         {
     487           0 :             if (c == '.' || c == cSep)
     488           0 :                 return false;
     489             : 
     490           0 :             if (c == '\'')
     491             :             {
     492             :                 // Move to the next char and loop until the second single
     493             :                 // quote.
     494           0 :                 cPrev = c;
     495           0 :                 ++i; ++p;
     496           0 :                 for (sal_Int32 j = i; j < nLen; ++j, ++p)
     497             :                 {
     498           0 :                     c = *p;
     499           0 :                     if (c == '\'')
     500             :                     {
     501           0 :                         if (j == i)
     502             :                         {
     503             :                             // empty quote e.g. (=''!Name)
     504           0 :                             return false;
     505             :                         }
     506             : 
     507           0 :                         if (cPrev == '\'')
     508             :                         {
     509             :                             // two consecutive quotes equal a single quote in
     510             :                             // the file name.
     511           0 :                             aTmpFile += OUString(c);
     512           0 :                             cPrev = 'a';
     513             :                         }
     514             :                         else
     515           0 :                             cPrev = c;
     516             : 
     517           0 :                         continue;
     518             :                     }
     519             : 
     520           0 :                     if (cPrev == '\'' && j != i)
     521             :                     {
     522             :                         // this is not a quote but the previous one is.  This
     523             :                         // ends the parsing of the quoted segment.  At this
     524             :                         // point, the current char must equal the separator
     525             :                         // char.
     526             : 
     527           0 :                         i = j;
     528           0 :                         bInName = true;
     529           0 :                         aTmpName += OUString(c); // Keep the separator as part of the name.
     530           0 :                         break;
     531             :                     }
     532           0 :                     aTmpFile += OUString(c);
     533           0 :                     cPrev = c;
     534             :                 }
     535             : 
     536           0 :                 if (!bInName)
     537             :                 {
     538             :                     // premature ending of the quoted segment.
     539           0 :                     return false;
     540             :                 }
     541             : 
     542           0 :                 if (c != cSep)
     543             :                 {
     544             :                     // only the separator is allowed after the closing quote.
     545           0 :                     return false;
     546             :                 }
     547             : 
     548           0 :                 cPrev = c;
     549           0 :                 continue;
     550             :             }
     551             :         }
     552             : 
     553           0 :         if (bInName)
     554             :         {
     555           0 :             if (c == cSep)
     556             :             {
     557             :                 // A second separator ?  Not a valid external name.
     558           0 :                 return false;
     559             :             }
     560           0 :             aTmpName += OUString(c);
     561             :         }
     562             :         else
     563             :         {
     564           0 :             if (c == cSep)
     565             :             {
     566           0 :                 bInName = true;
     567           0 :                 aTmpName += OUString(c); // Keep the separator as part of the name.
     568             :             }
     569             :             else
     570             :             {
     571             :                 do
     572             :                 {
     573           0 :                     if (rtl::isAsciiAlphanumeric(c))
     574             :                         // allowed.
     575           0 :                         break;
     576             : 
     577           0 :                     if (c > 128)
     578             :                         // non-ASCII character is allowed.
     579           0 :                         break;
     580             : 
     581           0 :                     bool bValid = false;
     582           0 :                     switch (c)
     583             :                     {
     584             :                         case '_':
     585             :                         case '-':
     586             :                         case '.':
     587             :                             // these special characters are allowed.
     588           0 :                             bValid = true;
     589           0 :                             break;
     590             :                     }
     591           0 :                     if (bValid)
     592           0 :                         break;
     593             : 
     594           0 :                     return false;
     595             :                 }
     596             :                 while (false);
     597           0 :                 aTmpFile += OUString(c);
     598             :             }
     599             :         }
     600           0 :         cPrev = c;
     601             :     }
     602             : 
     603           0 :     if (!bInName)
     604             :     {
     605             :         // No name found - most likely the symbol has no '!'s.
     606           0 :         return false;
     607             :     }
     608             : 
     609           0 :     sal_Int32 nNameLen = aTmpName.getLength();
     610           0 :     if (nNameLen < 2)
     611             :     {
     612             :         // Name must be at least 2-char long (separator plus name).
     613           0 :         return false;
     614             :     }
     615             : 
     616           0 :     if (aTmpName[0] != cSep)
     617             :     {
     618             :         // 1st char of the name must equal the separator.
     619           0 :         return false;
     620             :     }
     621             : 
     622           0 :     if (aTmpName[nNameLen-1] == '!')
     623             :     {
     624             :         // Check against #REF!.
     625           0 :         if (aTmpName.equalsAscii("#REF!"))
     626           0 :             return false;
     627             :     }
     628             : 
     629           0 :     rFile = aTmpFile;
     630           0 :     rName = aTmpName.copy(1); // Skip the first char as it is always the separator.
     631           0 :     return true;
     632             : }
     633             : 
     634           0 : static OUString lcl_makeExternalNameStr(const OUString& rFile, const OUString& rName,
     635             :         const sal_Unicode cSep, bool bODF )
     636             : {
     637           0 :     OUString aEscQuote("''");
     638           0 :     OUString aFile(rFile.replaceAll("'", aEscQuote));
     639           0 :     OUString aName(rName);
     640           0 :     if (bODF)
     641           0 :         aName = aName.replaceAll("'", aEscQuote);
     642           0 :     OUStringBuffer aBuf(aFile.getLength() + aName.getLength() + 9);
     643           0 :     if (bODF)
     644           0 :         aBuf.append( '[');
     645           0 :     aBuf.append( "'" + aFile + "'" + OUString(cSep));
     646           0 :     if (bODF)
     647           0 :         aBuf.append( "$$'" );
     648           0 :     aBuf.append( aName);
     649           0 :     if (bODF)
     650           0 :         aBuf.append( "']" );
     651           0 :     return aBuf.makeStringAndClear();
     652             : }
     653             : 
     654           0 : static bool lcl_getLastTabName( OUString& rTabName2, const OUString& rTabName1,
     655             :                                 const vector<OUString>& rTabNames, const ScRange& rRef )
     656             : {
     657           0 :     SCsTAB nTabSpan = rRef.aEnd.Tab() - rRef.aStart.Tab();
     658           0 :     if (nTabSpan > 0)
     659             :     {
     660           0 :         size_t nCount = rTabNames.size();
     661           0 :         vector<OUString>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end();
     662           0 :         vector<OUString>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1);
     663           0 :         if (itr == rTabNames.end())
     664             :         {
     665           0 :             rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     666           0 :             return false;
     667             :         }
     668             : 
     669           0 :         size_t nDist = ::std::distance(itrBeg, itr);
     670           0 :         if (nDist + static_cast<size_t>(nTabSpan) >= nCount)
     671             :         {
     672           0 :             rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     673           0 :             return false;
     674             :         }
     675             : 
     676           0 :         rTabName2 = rTabNames[nDist+nTabSpan];
     677             :     }
     678             :     else
     679           0 :         rTabName2 = rTabName1;
     680             : 
     681           0 :     return true;
     682             : }
     683             : 
     684           0 : struct Convention_A1 : public ScCompiler::Convention
     685             : {
     686           0 :     Convention_A1( FormulaGrammar::AddressConvention eConv ) : ScCompiler::Convention( eConv ) { }
     687             :     static void MakeColStr( OUStringBuffer& rBuffer, SCCOL nCol );
     688             :     static void MakeRowStr( OUStringBuffer& rBuffer, SCROW nRow );
     689             : 
     690           0 :     ParseResult parseAnyToken( const OUString& rFormula,
     691             :                                sal_Int32 nSrcPos,
     692             :                                const CharClass* pCharClass) const SAL_OVERRIDE
     693             :     {
     694           0 :         ParseResult aRet;
     695           0 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
     696           0 :             return aRet;
     697             : 
     698             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
     699             :             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
     700             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
     701             :         // '?' allowed in range names because of Xcl :-/
     702           0 :         static const OUString aAddAllowed("?#");
     703             :         return pCharClass->parseAnyToken( rFormula,
     704           0 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
     705             :     }
     706             : 
     707           0 :     virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode /*cLast*/ ) const SAL_OVERRIDE
     708             :     {
     709           0 :         return mpCharTable[static_cast<sal_uInt8>(c)];
     710             :     }
     711             : };
     712             : 
     713           0 : void Convention_A1::MakeColStr( OUStringBuffer& rBuffer, SCCOL nCol )
     714             : {
     715           0 :     if ( !ValidCol( nCol) )
     716           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     717             :     else
     718           0 :         ::ScColToAlpha( rBuffer, nCol);
     719           0 : }
     720             : 
     721           0 : void Convention_A1::MakeRowStr( OUStringBuffer& rBuffer, SCROW nRow )
     722             : {
     723           0 :     if ( !ValidRow(nRow) )
     724           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     725             :     else
     726           0 :         rBuffer.append(sal_Int32(nRow + 1));
     727           0 : }
     728             : 
     729           0 : struct ConventionOOO_A1 : public Convention_A1
     730             : {
     731           0 :     ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO) { }
     732           0 :     ConventionOOO_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1 (eConv) { }
     733             : 
     734           0 :     static OUString MakeTabStr( const std::vector<OUString>& rTabNames, SCTAB nTab )
     735             :     {
     736           0 :         OUString aString;
     737           0 :         if (static_cast<size_t>(nTab) >= rTabNames.size())
     738           0 :             aString = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     739             :         else
     740           0 :             aString = rTabNames[nTab];
     741           0 :         aString += ".";
     742           0 :         return aString;
     743             :     }
     744             : 
     745           0 :     void MakeOneRefStrImpl(
     746             :         OUStringBuffer& rBuffer,
     747             :         const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     748             :         const ScSingleRefData& rRef, const ScAddress& rAbsRef,
     749             :         bool bForceTab, bool bODF ) const
     750             :     {
     751           0 :         if( rRef.IsFlag3D() || bForceTab )
     752             :         {
     753           0 :             if (!ValidTab(rAbsRef.Tab()) || rRef.IsTabDeleted())
     754             :             {
     755           0 :                 if (!rRef.IsTabRel())
     756           0 :                     rBuffer.append('$');
     757           0 :                 rBuffer.append(rErrRef);
     758           0 :                 rBuffer.append('.');
     759             :             }
     760             :             else
     761             :             {
     762           0 :                 OUString aRefStr(MakeTabStr(rTabNames, rAbsRef.Tab()));
     763           0 :                 if (!rRef.IsTabRel())
     764           0 :                     rBuffer.append('$');
     765           0 :                 rBuffer.append(aRefStr);
     766             :             }
     767             :         }
     768           0 :         else if (bODF)
     769           0 :             rBuffer.append('.');
     770           0 :         if (!rRef.IsColRel())
     771           0 :             rBuffer.append('$');
     772           0 :         if (!ValidCol(rAbsRef.Col()) || rRef.IsColDeleted())
     773           0 :             rBuffer.append(rErrRef);
     774             :         else
     775           0 :             MakeColStr(rBuffer, rAbsRef.Col());
     776           0 :         if (!rRef.IsRowRel())
     777           0 :             rBuffer.append('$');
     778           0 :         if (!ValidRow(rAbsRef.Row()) || rRef.IsRowDeleted())
     779           0 :             rBuffer.append(rErrRef);
     780             :         else
     781           0 :             MakeRowStr(rBuffer, rAbsRef.Row());
     782           0 :     }
     783             : 
     784           0 :     void makeRefStr( OUStringBuffer&   rBuffer,
     785             :                      formula::FormulaGrammar::Grammar /*eGram*/,
     786             :                      const ScAddress& rPos,
     787             :                      const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     788             :                      const ScComplexRefData& rRef,
     789             :                      bool bSingleRef ) const SAL_OVERRIDE
     790             :     {
     791           0 :         ScComplexRefData aRef( rRef );
     792             :         // In case absolute/relative positions weren't separately available:
     793             :         // transform relative to absolute!
     794           0 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
     795           0 :         if( !bSingleRef )
     796           0 :             aAbs2 = aRef.Ref2.toAbs(rPos);
     797             : 
     798           0 :         MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref1, aAbs1, false, false);
     799           0 :         if (!bSingleRef)
     800             :         {
     801           0 :             rBuffer.append(':');
     802           0 :             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref2, aAbs2, aAbs1.Tab() != aAbs2.Tab(), false);
     803             :         }
     804           0 :     }
     805             : 
     806           0 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
     807             :     {
     808           0 :         switch (eSymType)
     809             :         {
     810             :             case ScCompiler::Convention::ABS_SHEET_PREFIX:
     811           0 :                 return '$';
     812             :             case ScCompiler::Convention::SHEET_SEPARATOR:
     813           0 :                 return '.';
     814             :         }
     815             : 
     816           0 :         return sal_Unicode(0);
     817             :     }
     818             : 
     819           0 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
     820             :             const ScDocument* pDoc,
     821             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
     822             :     {
     823           0 :         return lcl_parseExternalName(rSymbol, rFile, rName, '#', pDoc, pExternalLinks);
     824             :     }
     825             : 
     826           0 :     virtual OUString makeExternalNameStr( const OUString& rFile, const OUString& rName ) const SAL_OVERRIDE
     827             :     {
     828           0 :         return lcl_makeExternalNameStr( rFile, rName, '#', false);
     829             :     }
     830             : 
     831           0 :     bool makeExternalSingleRefStr(
     832             :         OUStringBuffer& rBuffer, const OUString& rFileName, const OUString& rTabName,
     833             :         const ScSingleRefData& rRef, const ScAddress& rPos, bool bDisplayTabName, bool bEncodeUrl ) const
     834             :     {
     835           0 :         ScAddress aAbsRef = rRef.toAbs(rPos);
     836           0 :         if (bDisplayTabName)
     837             :         {
     838           0 :             OUString aFile;
     839           0 :             if (bEncodeUrl)
     840           0 :                 aFile = rFileName;
     841             :             else
     842           0 :                 aFile = INetURLObject::decode(rFileName, '%', INetURLObject::DECODE_UNAMBIGUOUS);
     843             : 
     844           0 :             rBuffer.append("'" + aFile.replaceAll("'", "''") + "'#");
     845             : 
     846           0 :             if (!rRef.IsTabRel())
     847           0 :                 rBuffer.append('$');
     848           0 :             ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
     849             : 
     850           0 :             rBuffer.append('.');
     851             :         }
     852             : 
     853           0 :         if (!rRef.IsColRel())
     854           0 :             rBuffer.append('$');
     855           0 :         MakeColStr( rBuffer, aAbsRef.Col());
     856           0 :         if (!rRef.IsRowRel())
     857           0 :             rBuffer.append('$');
     858           0 :         MakeRowStr( rBuffer, aAbsRef.Row());
     859             : 
     860           0 :         return true;
     861             :     }
     862             : 
     863           0 :     void makeExternalRefStrImpl(
     864             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     865             :         const OUString& rTabName, const ScSingleRefData& rRef, bool bODF ) const
     866             :     {
     867           0 :         if (bODF)
     868           0 :             rBuffer.append( '[');
     869             : 
     870           0 :         bool bEncodeUrl = bODF;
     871           0 :         makeExternalSingleRefStr(rBuffer, rFileName, rTabName, rRef, rPos, true, bEncodeUrl);
     872           0 :         if (bODF)
     873           0 :             rBuffer.append( ']');
     874           0 :     }
     875             : 
     876           0 :     virtual void makeExternalRefStr(
     877             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     878             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
     879             :     {
     880           0 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, false);
     881           0 :     }
     882             : 
     883           0 :     void makeExternalRefStrImpl(
     884             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     885             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
     886             :         const ScComplexRefData& rRef, bool bODF ) const
     887             :     {
     888           0 :         ScRange aAbsRange = rRef.toAbs(rPos);
     889             : 
     890           0 :         if (bODF)
     891           0 :             rBuffer.append( '[');
     892             :         // Ensure that there's always a closing bracket, no premature returns.
     893           0 :         bool bEncodeUrl = bODF;
     894             : 
     895             :         do
     896             :         {
     897           0 :             if (!makeExternalSingleRefStr(rBuffer, rFileName, rTabName, rRef.Ref1, rPos, true, bEncodeUrl))
     898           0 :                 break;
     899             : 
     900           0 :             rBuffer.append(':');
     901             : 
     902           0 :             OUString aLastTabName;
     903           0 :             bool bDisplayTabName = (aAbsRange.aStart.Tab() != aAbsRange.aEnd.Tab());
     904           0 :             if (bDisplayTabName)
     905             :             {
     906             :                 // Get the name of the last table.
     907           0 :                 if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, aAbsRange))
     908             :                 {
     909             :                     OSL_FAIL( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found");
     910             :                     // aLastTabName contains #REF!, proceed.
     911             :                 }
     912             :             }
     913           0 :             else if (bODF)
     914           0 :                 rBuffer.append( '.');      // need at least the sheet separator in ODF
     915             :             makeExternalSingleRefStr(
     916           0 :                 rBuffer, rFileName, aLastTabName, rRef.Ref2, rPos, bDisplayTabName, bEncodeUrl);
     917             :         } while (false);
     918             : 
     919           0 :         if (bODF)
     920           0 :             rBuffer.append( ']');
     921           0 :     }
     922             : 
     923           0 :     virtual void makeExternalRefStr(
     924             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     925             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
     926             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
     927             :     {
     928           0 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabNames, rTabName, rRef, false);
     929           0 :     }
     930             : };
     931             : 
     932           0 : struct ConventionOOO_A1_ODF : public ConventionOOO_A1
     933             : {
     934           0 :     ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF) { }
     935           0 :     void makeRefStr( OUStringBuffer&   rBuffer,
     936             :                      formula::FormulaGrammar::Grammar eGram,
     937             :                      const ScAddress& rPos,
     938             :                      const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     939             :                      const ScComplexRefData& rRef,
     940             :                      bool bSingleRef ) const SAL_OVERRIDE
     941             :     {
     942           0 :         rBuffer.append('[');
     943           0 :         ScComplexRefData aRef( rRef );
     944             :         // In case absolute/relative positions weren't separately available:
     945             :         // transform relative to absolute!
     946           0 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
     947           0 :         if( !bSingleRef )
     948           0 :             aAbs2 = aRef.Ref2.toAbs(rPos);
     949             : 
     950           0 :         if (FormulaGrammar::isODFF(eGram) && (!ValidAddress(aAbs1) || !ValidAddress(aAbs2)))
     951             :         {
     952           0 :             rBuffer.append(rErrRef);
     953             :             // For ODFF write [#REF!], but not for PODF so apps reading ODF
     954             :             // 1.0/1.1 may have a better chance if they implemented the old
     955             :             // form.
     956             :         }
     957             :         else
     958             :         {
     959           0 :             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref1, aAbs1, false, true);
     960           0 :             if (!bSingleRef)
     961             :             {
     962           0 :                 rBuffer.append(':');
     963           0 :                 MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref2, aAbs2, aAbs1.Tab() != aAbs2.Tab(), true);
     964             :             }
     965             :         }
     966           0 :         rBuffer.append(']');
     967           0 :     }
     968             : 
     969           0 :     virtual OUString makeExternalNameStr( const OUString& rFile, const OUString& rName ) const SAL_OVERRIDE
     970             :     {
     971           0 :         return lcl_makeExternalNameStr( rFile, rName, '#', true);
     972             :     }
     973             : 
     974           0 :     virtual void makeExternalRefStr(
     975             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     976             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
     977             :     {
     978           0 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, true);
     979           0 :     }
     980             : 
     981           0 :     virtual void makeExternalRefStr(
     982             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     983             :         const std::vector<OUString>& rTabNames,
     984             :         const OUString& rTabName, const ScComplexRefData& rRef ) const SAL_OVERRIDE
     985             :     {
     986           0 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabNames, rTabName, rRef, true);
     987           0 :     }
     988             : };
     989             : 
     990           0 : struct ConventionXL
     991             : {
     992           0 :     static void GetTab(
     993             :         const ScAddress& rPos, const std::vector<OUString>& rTabNames,
     994             :         const ScSingleRefData& rRef, OUString& rTabName )
     995             :     {
     996           0 :         ScAddress aAbs = rRef.toAbs(rPos);
     997           0 :         if (rRef.IsTabDeleted() || static_cast<size_t>(aAbs.Tab()) >= rTabNames.size())
     998             :         {
     999           0 :             rTabName = ScGlobal::GetRscString( STR_NO_REF_TABLE );
    1000           0 :             return;
    1001             :         }
    1002           0 :         rTabName = rTabNames[aAbs.Tab()];
    1003             :     }
    1004             : 
    1005           0 :     static void MakeTabStr( OUStringBuffer& rBuf,
    1006             :                             const ScAddress& rPos,
    1007             :                             const std::vector<OUString>& rTabNames,
    1008             :                             const ScComplexRefData& rRef,
    1009             :                             bool bSingleRef )
    1010             :     {
    1011           0 :         if( rRef.Ref1.IsFlag3D() )
    1012             :         {
    1013           0 :             OUString aStartTabName, aEndTabName;
    1014             : 
    1015           0 :             GetTab(rPos, rTabNames, rRef.Ref1, aStartTabName);
    1016             : 
    1017           0 :             if( !bSingleRef && rRef.Ref2.IsFlag3D() )
    1018             :             {
    1019           0 :                 GetTab(rPos, rTabNames, rRef.Ref2, aEndTabName);
    1020             :             }
    1021             : 
    1022           0 :             rBuf.append( aStartTabName );
    1023           0 :             if( !bSingleRef && rRef.Ref2.IsFlag3D() && aStartTabName != aEndTabName )
    1024             :             {
    1025           0 :                 rBuf.append( ':' );
    1026           0 :                 rBuf.append( aEndTabName );
    1027             :             }
    1028             : 
    1029           0 :             rBuf.append( '!' );
    1030             :         }
    1031           0 :     }
    1032             : 
    1033           0 :     static sal_Unicode getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType )
    1034             :     {
    1035           0 :         switch (eSymType)
    1036             :         {
    1037             :             case ScCompiler::Convention::ABS_SHEET_PREFIX:
    1038           0 :                 return sal_Unicode(0);
    1039             :             case ScCompiler::Convention::SHEET_SEPARATOR:
    1040           0 :                 return '!';
    1041             :         }
    1042           0 :         return sal_Unicode(0);
    1043             :     }
    1044             : 
    1045           0 :     static bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1046             :             const ScDocument* pDoc,
    1047             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
    1048             :     {
    1049           0 :         return lcl_parseExternalName( rSymbol, rFile, rName, '!', pDoc, pExternalLinks);
    1050             :     }
    1051             : 
    1052           0 :     static OUString makeExternalNameStr( const OUString& rFile, const OUString& rName )
    1053             :     {
    1054           0 :         return lcl_makeExternalNameStr( rFile, rName, '!', false);
    1055             :     }
    1056             : 
    1057           0 :     static void makeExternalDocStr( OUStringBuffer& rBuffer, const OUString& rFullName, bool bEncodeUrl )
    1058             :     {
    1059             :         // Format that is easier to deal with inside OOo, because we use file
    1060             :         // URL, and all characetrs are allowed.  Check if it makes sense to do
    1061             :         // it the way Gnumeric does it.  Gnumeric doesn't use the URL form
    1062             :         // and allows relative file path.
    1063             :         //
    1064             :         //   ['file:///path/to/source/filename.xls']
    1065             : 
    1066           0 :         rBuffer.append('[');
    1067           0 :         rBuffer.append('\'');
    1068           0 :         OUString aFullName;
    1069           0 :         if (bEncodeUrl)
    1070           0 :             aFullName = rFullName;
    1071             :         else
    1072           0 :             aFullName = INetURLObject::decode(rFullName, '%', INetURLObject::DECODE_UNAMBIGUOUS);
    1073             : 
    1074           0 :         const sal_Unicode* pBuf = aFullName.getStr();
    1075           0 :         sal_Int32 nLen = aFullName.getLength();
    1076           0 :         for (sal_Int32 i = 0; i < nLen; ++i)
    1077             :         {
    1078           0 :             const sal_Unicode c = pBuf[i];
    1079           0 :             if (c == '\'')
    1080           0 :                 rBuffer.append(c);
    1081           0 :             rBuffer.append(c);
    1082             :         }
    1083           0 :         rBuffer.append('\'');
    1084           0 :         rBuffer.append(']');
    1085           0 :     }
    1086             : 
    1087           0 :     static void makeExternalTabNameRange( OUStringBuffer& rBuf, const OUString& rTabName,
    1088             :                                           const vector<OUString>& rTabNames,
    1089             :                                           const ScRange& rRef )
    1090             :     {
    1091           0 :         OUString aLastTabName;
    1092           0 :         if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef))
    1093             :         {
    1094           0 :             ScRangeStringConverter::AppendTableName(rBuf, aLastTabName);
    1095           0 :             return;
    1096             :         }
    1097             : 
    1098           0 :         ScRangeStringConverter::AppendTableName(rBuf, rTabName);
    1099           0 :         if (rTabName != aLastTabName)
    1100             :         {
    1101           0 :             rBuf.append(':');
    1102           0 :             ScRangeStringConverter::AppendTableName(rBuf, rTabName);
    1103           0 :         }
    1104             :     }
    1105             : 
    1106           0 :     static void parseExternalDocName( const OUString& rFormula, sal_Int32& rSrcPos )
    1107             :     {
    1108           0 :         sal_Int32 nLen = rFormula.getLength();
    1109           0 :         const sal_Unicode* p = rFormula.getStr();
    1110           0 :         sal_Unicode cPrev = 0;
    1111           0 :         for (sal_Int32 i = rSrcPos; i < nLen; ++i)
    1112             :         {
    1113           0 :             sal_Unicode c = p[i];
    1114           0 :             if (i == rSrcPos)
    1115             :             {
    1116             :                 // first character must be '['.
    1117           0 :                 if (c != '[')
    1118           0 :                     return;
    1119             :             }
    1120           0 :             else if (i == rSrcPos + 1)
    1121             :             {
    1122             :                 // second character must be a single quote.
    1123           0 :                 if (c != '\'')
    1124           0 :                     return;
    1125             :             }
    1126           0 :             else if (c == '\'')
    1127             :             {
    1128           0 :                 if (cPrev == '\'')
    1129             :                     // two successive single quote is treated as a single
    1130             :                     // valid character.
    1131           0 :                     c = 'a';
    1132             :             }
    1133           0 :             else if (c == ']')
    1134             :             {
    1135           0 :                 if (cPrev == '\'')
    1136             :                 {
    1137             :                     // valid source document path found.  Increment the
    1138             :                     // current position to skip the source path.
    1139           0 :                     rSrcPos = i + 1;
    1140           0 :                     if (rSrcPos >= nLen)
    1141           0 :                         rSrcPos = nLen - 1;
    1142           0 :                     return;
    1143             :                 }
    1144             :                 else
    1145           0 :                     return;
    1146             :             }
    1147             :             else
    1148             :             {
    1149             :                 // any other character
    1150           0 :                 if (i > rSrcPos + 2 && cPrev == '\'')
    1151             :                     // unless it's the 3rd character, a normal character
    1152             :                     // following immediately a single quote is invalid.
    1153           0 :                     return;
    1154             :             }
    1155           0 :             cPrev = c;
    1156             :         }
    1157             :     }
    1158             : };
    1159             : 
    1160           0 : struct ConventionXL_A1 : public Convention_A1, public ConventionXL
    1161             : {
    1162           0 :     ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1 ) { }
    1163           0 :     ConventionXL_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1( eConv ) { }
    1164             : 
    1165           0 :     void makeSingleCellStr( OUStringBuffer& rBuf, const ScSingleRefData& rRef, const ScAddress& rAbs ) const
    1166             :     {
    1167           0 :         if (!rRef.IsColRel())
    1168           0 :             rBuf.append('$');
    1169           0 :         MakeColStr(rBuf, rAbs.Col());
    1170           0 :         if (!rRef.IsRowRel())
    1171           0 :             rBuf.append('$');
    1172           0 :         MakeRowStr(rBuf, rAbs.Row());
    1173           0 :     }
    1174             : 
    1175           0 :     void makeRefStr( OUStringBuffer&   rBuf,
    1176             :                      formula::FormulaGrammar::Grammar /*eGram*/,
    1177             :                      const ScAddress& rPos,
    1178             :                      const OUString& /*rErrRef*/, const std::vector<OUString>& rTabNames,
    1179             :                      const ScComplexRefData& rRef,
    1180             :                      bool bSingleRef ) const SAL_OVERRIDE
    1181             :     {
    1182           0 :         ScComplexRefData aRef( rRef );
    1183             : 
    1184             :         // Play fast and loose with invalid refs.  There is not much point in producing
    1185             :         // Foo!A1:#REF! versus #REF! at this point
    1186           0 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
    1187             : 
    1188           0 :         MakeTabStr(rBuf, rPos, rTabNames, aRef, bSingleRef);
    1189             : 
    1190           0 :         if (!ValidAddress(aAbs1))
    1191             :         {
    1192           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1193           0 :             return;
    1194             :         }
    1195             : 
    1196           0 :         if( !bSingleRef )
    1197             :         {
    1198           0 :             aAbs2 = aRef.Ref2.toAbs(rPos);
    1199           0 :             if (!ValidAddress(aAbs2))
    1200             :             {
    1201           0 :                 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1202           0 :                 return;
    1203             :             }
    1204             : 
    1205           0 :             if (aAbs1.Col() == 0 && aAbs2.Col() >= MAXCOL)
    1206             :             {
    1207           0 :                 if (!aRef.Ref1.IsRowRel())
    1208           0 :                     rBuf.append( '$' );
    1209           0 :                 MakeRowStr(rBuf, aAbs1.Row());
    1210           0 :                 rBuf.append( ':' );
    1211           0 :                 if (!aRef.Ref2.IsRowRel())
    1212           0 :                     rBuf.append( '$' );
    1213           0 :                 MakeRowStr(rBuf, aAbs2.Row());
    1214           0 :                 return;
    1215             :             }
    1216             : 
    1217           0 :             if (aAbs1.Row() == 0 && aAbs2.Row() >= MAXROW)
    1218             :             {
    1219           0 :                 if (!aRef.Ref1.IsColRel())
    1220           0 :                     rBuf.append( '$' );
    1221           0 :                 MakeColStr(rBuf, aAbs1.Col());
    1222           0 :                 rBuf.append( ':' );
    1223           0 :                 if (!aRef.Ref2.IsColRel())
    1224           0 :                     rBuf.append( '$' );
    1225           0 :                 MakeColStr(rBuf, aAbs2.Col());
    1226           0 :                 return;
    1227             :             }
    1228             :         }
    1229             : 
    1230           0 :         makeSingleCellStr(rBuf, aRef.Ref1, aAbs1);
    1231           0 :         if (!bSingleRef)
    1232             :         {
    1233           0 :             rBuf.append( ':' );
    1234           0 :             makeSingleCellStr(rBuf, aRef.Ref2, aAbs2);
    1235             :         }
    1236             :     }
    1237             : 
    1238           0 :     virtual ParseResult parseAnyToken( const OUString& rFormula,
    1239             :                                        sal_Int32 nSrcPos,
    1240             :                                        const CharClass* pCharClass) const SAL_OVERRIDE
    1241             :     {
    1242           0 :         ParseResult aRet;
    1243           0 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
    1244           0 :             return aRet;
    1245             : 
    1246             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
    1247             :             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
    1248             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
    1249             :         // '?' allowed in range names
    1250           0 :         const OUString aAddAllowed("?!");
    1251             :         return pCharClass->parseAnyToken( rFormula,
    1252           0 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
    1253             :     }
    1254             : 
    1255           0 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
    1256             :     {
    1257           0 :         return ConventionXL::getSpecialSymbol(eSymType);
    1258             :     }
    1259             : 
    1260           0 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1261             :             const ScDocument* pDoc,
    1262             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
    1263             :     {
    1264           0 :         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
    1265             :     }
    1266             : 
    1267           0 :     virtual OUString makeExternalNameStr( const OUString& rFile, const OUString& rName ) const SAL_OVERRIDE
    1268             :     {
    1269           0 :         return ConventionXL::makeExternalNameStr(rFile, rName);
    1270             :     }
    1271             : 
    1272           0 :     virtual void makeExternalRefStr(
    1273             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
    1274             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1275             :     {
    1276             :         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
    1277             :         // This is a little different from the format Excel uses, as Excel
    1278             :         // puts [] only around the file name.  But we need to enclose the
    1279             :         // whole file path with [] because the file name can contain any
    1280             :         // characters.
    1281             : 
    1282           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1283           0 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1284           0 :         rBuffer.append('!');
    1285             : 
    1286           0 :         makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
    1287           0 :     }
    1288             : 
    1289           0 :     virtual void makeExternalRefStr(
    1290             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
    1291             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1292             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1293             :     {
    1294           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1295             : 
    1296           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1297           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1298           0 :         rBuffer.append('!');
    1299             : 
    1300           0 :         makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1301           0 :         if (aAbsRef.aStart != aAbsRef.aEnd)
    1302             :         {
    1303           0 :             rBuffer.append(':');
    1304           0 :             makeSingleCellStr(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1305             :         }
    1306           0 :     }
    1307             : };
    1308             : 
    1309           0 : struct ConventionXL_OOX : public ConventionXL_A1
    1310             : {
    1311           0 :     ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
    1312             : };
    1313             : 
    1314             : static void
    1315           0 : r1c1_add_col( OUStringBuffer &rBuf, const ScSingleRefData& rRef, const ScAddress& rAbsRef )
    1316             : {
    1317           0 :     rBuf.append( 'C' );
    1318           0 :     if( rRef.IsColRel() )
    1319             :     {
    1320           0 :         SCCOL nCol = rRef.Col();
    1321           0 :         if (nCol != 0)
    1322           0 :             rBuf.append("[").append(OUString::number(nCol)).append("]");
    1323             :     }
    1324             :     else
    1325           0 :         rBuf.append( OUString::number( rAbsRef.Col() + 1 ) );
    1326           0 : }
    1327             : static void
    1328           0 : r1c1_add_row( OUStringBuffer &rBuf, const ScSingleRefData& rRef, const ScAddress& rAbsRef )
    1329             : {
    1330           0 :     rBuf.append( 'R' );
    1331           0 :     if( rRef.IsRowRel() )
    1332             :     {
    1333           0 :         if (rRef.Row() != 0)
    1334             :         {
    1335           0 :             rBuf.append("[").append( OUString::number(rRef.Row()) ).append("]");
    1336             :         }
    1337             :     }
    1338             :     else
    1339           0 :         rBuf.append( OUString::number( rAbsRef.Row() + 1 ) );
    1340           0 : }
    1341             : 
    1342           0 : struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
    1343             : {
    1344           0 :     ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1 ) { }
    1345           0 :     void makeRefStr( OUStringBuffer&   rBuf,
    1346             :                      formula::FormulaGrammar::Grammar /*eGram*/,
    1347             :                      const ScAddress& rPos,
    1348             :                      const OUString& /*rErrRef*/, const std::vector<OUString>& rTabNames,
    1349             :                      const ScComplexRefData& rRef,
    1350             :                      bool bSingleRef ) const SAL_OVERRIDE
    1351             :     {
    1352           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1353           0 :         ScComplexRefData aRef( rRef );
    1354             : 
    1355           0 :         MakeTabStr(rBuf, rPos, rTabNames, aRef, bSingleRef);
    1356             : 
    1357             :         // Play fast and loose with invalid refs.  There is not much point in producing
    1358             :         // Foo!A1:#REF! versus #REF! at this point
    1359           0 :         if (!ValidCol(aAbsRef.aStart.Col()) || !ValidRow(aAbsRef.aStart.Row()))
    1360             :         {
    1361           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1362           0 :             return;
    1363             :         }
    1364             : 
    1365           0 :         if( !bSingleRef )
    1366             :         {
    1367           0 :             if (!ValidCol(aAbsRef.aEnd.Col()) || !ValidRow(aAbsRef.aEnd.Row()))
    1368             :             {
    1369           0 :                 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1370           0 :                 return;
    1371             :             }
    1372             : 
    1373           0 :             if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= MAXCOL)
    1374             :             {
    1375           0 :                 r1c1_add_row(rBuf,  rRef.Ref1, aAbsRef.aStart);
    1376           0 :                 if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() ||
    1377           0 :                     rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel() )
    1378             :                 {
    1379           0 :                     rBuf.append( ':' );
    1380           0 :                     r1c1_add_row(rBuf,  rRef.Ref2, aAbsRef.aEnd);
    1381             :                 }
    1382           0 :                 return;
    1383             : 
    1384             :             }
    1385             : 
    1386           0 :             if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= MAXROW)
    1387             :             {
    1388           0 :                 r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
    1389           0 :                 if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() ||
    1390           0 :                     rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
    1391             :                 {
    1392           0 :                     rBuf.append( ':' );
    1393           0 :                     r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1394             :                 }
    1395           0 :                 return;
    1396             :             }
    1397             :         }
    1398             : 
    1399           0 :         r1c1_add_row(rBuf, rRef.Ref1, aAbsRef.aStart);
    1400           0 :         r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
    1401           0 :         if (!bSingleRef)
    1402             :         {
    1403           0 :             rBuf.append( ':' );
    1404           0 :             r1c1_add_row(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1405           0 :             r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1406             :         }
    1407             :     }
    1408             : 
    1409           0 :     ParseResult parseAnyToken( const OUString& rFormula,
    1410             :                                sal_Int32 nSrcPos,
    1411             :                                const CharClass* pCharClass) const SAL_OVERRIDE
    1412             :     {
    1413           0 :         ConventionXL::parseExternalDocName(rFormula, nSrcPos);
    1414             : 
    1415           0 :         ParseResult aRet;
    1416           0 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
    1417           0 :             return aRet;
    1418             : 
    1419             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
    1420             :             KParseTokens::ASC_UNDERSCORE ;
    1421             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
    1422             :         // '?' allowed in range names
    1423           0 :         const OUString aAddAllowed("?-[]!");
    1424             : 
    1425             :         return pCharClass->parseAnyToken( rFormula,
    1426           0 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
    1427             :     }
    1428             : 
    1429           0 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
    1430             :     {
    1431           0 :         return ConventionXL::getSpecialSymbol(eSymType);
    1432             :     }
    1433             : 
    1434           0 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1435             :             const ScDocument* pDoc,
    1436             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
    1437             :     {
    1438           0 :         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
    1439             :     }
    1440             : 
    1441           0 :     virtual OUString makeExternalNameStr( const OUString& rFile, const OUString& rName ) const SAL_OVERRIDE
    1442             :     {
    1443           0 :         return ConventionXL::makeExternalNameStr(rFile, rName);
    1444             :     }
    1445             : 
    1446           0 :     virtual void makeExternalRefStr(
    1447             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
    1448             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1449             :     {
    1450             :         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
    1451             :         // This is a little different from the format Excel uses, as Excel
    1452             :         // puts [] only around the file name.  But we need to enclose the
    1453             :         // whole file path with [] because the file name can contain any
    1454             :         // characters.
    1455             : 
    1456           0 :         ScAddress aAbsRef = rRef.toAbs(rPos);
    1457           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1458           0 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1459           0 :         rBuffer.append('!');
    1460             : 
    1461           0 :         r1c1_add_row(rBuffer, rRef, aAbsRef);
    1462           0 :         r1c1_add_col(rBuffer, rRef, aAbsRef);
    1463           0 :     }
    1464             : 
    1465           0 :     virtual void makeExternalRefStr(
    1466             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
    1467             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1468             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1469             :     {
    1470           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1471             : 
    1472           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1473           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1474           0 :         rBuffer.append('!');
    1475             : 
    1476           0 :         if (!ValidCol(aAbsRef.aEnd.Col()) || !ValidRow(aAbsRef.aEnd.Row()))
    1477             :         {
    1478           0 :             rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1479           0 :             return;
    1480             :         }
    1481             : 
    1482           0 :         if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= MAXCOL)
    1483             :         {
    1484           0 :             r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1485           0 :             if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel())
    1486             :             {
    1487           0 :                 rBuffer.append(':');
    1488           0 :                 r1c1_add_row(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1489             :             }
    1490           0 :             return;
    1491             :         }
    1492             : 
    1493           0 :         if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= MAXROW)
    1494             :         {
    1495           0 :             r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1496           0 :             if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() || rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
    1497             :             {
    1498           0 :                 rBuffer.append(':');
    1499           0 :                 r1c1_add_col(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1500             :             }
    1501           0 :             return;
    1502             :         }
    1503             : 
    1504           0 :         r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1505           0 :         r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1506           0 :         rBuffer.append(':');
    1507           0 :         r1c1_add_row(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1508           0 :         r1c1_add_col(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1509             :     }
    1510             : 
    1511           0 :     virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode cLast ) const SAL_OVERRIDE
    1512             :     {
    1513           0 :         sal_uLong nFlags = mpCharTable[static_cast<sal_uInt8>(c)];
    1514           0 :         if (c == '-' && cLast == '[')
    1515             :             // '-' can occur within a reference string only after '[' e.g. R[-1]C.
    1516           0 :             nFlags |= SC_COMPILER_C_IDENT;
    1517           0 :         return nFlags;
    1518             :     }
    1519             : };
    1520             : 
    1521           0 : ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, ScTokenArray& rArr ) :
    1522             :     FormulaCompiler(rArr),
    1523           0 :     pDoc(rCxt.getDoc()),
    1524             :     aPos(rPos),
    1525           0 :     mpFormatter(pDoc->GetFormatTable()),
    1526             :     pCharClass(ScGlobal::pCharClass),
    1527             :     mnPredetectedReference(0),
    1528             :     mnRangeOpPosInSymbol(-1),
    1529           0 :     pConv(GetRefConvention(FormulaGrammar::CONV_OOO)),
    1530             :     meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
    1531             :     mbCloseBrackets(true),
    1532             :     mbRewind(false),
    1533           0 :     maTabNames(rCxt.getTabNames())
    1534             : {
    1535           0 :     nMaxTab = pDoc->GetTableCount() - 1;
    1536           0 :     SetGrammar(rCxt.getGrammar());
    1537           0 : }
    1538             : 
    1539           0 : ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArray& rArr)
    1540             :         : FormulaCompiler(rArr),
    1541             :         pDoc( pDocument ),
    1542             :         aPos( rPos ),
    1543           0 :         mpFormatter(pDoc->GetFormatTable()),
    1544             :         pCharClass( ScGlobal::pCharClass ),
    1545             :         mnPredetectedReference(0),
    1546             :         mnRangeOpPosInSymbol(-1),
    1547           0 :         pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
    1548             :         meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
    1549             :         mbCloseBrackets( true ),
    1550           0 :         mbRewind( false )
    1551             : {
    1552           0 :     nMaxTab = pDoc->GetTableCount() - 1;
    1553           0 : }
    1554             : 
    1555           0 : ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos ) :
    1556           0 :     pDoc(rCxt.getDoc()),
    1557             :     aPos(rPos),
    1558           0 :     mpFormatter(pDoc ? pDoc->GetFormatTable() : NULL),
    1559             :     pCharClass(ScGlobal::pCharClass),
    1560             :     mnPredetectedReference(0),
    1561             :     mnRangeOpPosInSymbol(-1),
    1562           0 :     pConv(GetRefConvention(FormulaGrammar::CONV_OOO)),
    1563             :     meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
    1564             :     mbCloseBrackets(true),
    1565             :     mbRewind(false),
    1566           0 :     maTabNames(rCxt.getTabNames())
    1567             : {
    1568           0 :     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
    1569           0 :     SetGrammar(rCxt.getGrammar());
    1570           0 : }
    1571             : 
    1572           0 : ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos)
    1573             :         :
    1574             :         pDoc( pDocument ),
    1575             :         aPos( rPos ),
    1576           0 :         mpFormatter(pDoc ? pDoc->GetFormatTable() : NULL),
    1577             :         pCharClass( ScGlobal::pCharClass ),
    1578             :         mnPredetectedReference(0),
    1579             :         mnRangeOpPosInSymbol(-1),
    1580           0 :         pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
    1581             :         meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
    1582             :         mbCloseBrackets( true ),
    1583           0 :         mbRewind( false )
    1584             : {
    1585           0 :     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
    1586           0 : }
    1587             : 
    1588           0 : ScCompiler::~ScCompiler()
    1589             : {
    1590           0 : }
    1591             : 
    1592           0 : void ScCompiler::CheckTabQuotes( OUString& rString,
    1593             :                                  const FormulaGrammar::AddressConvention eConv )
    1594             : {
    1595             :     using namespace ::com::sun::star::i18n;
    1596           0 :     sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE;
    1597           0 :     sal_Int32 nContFlags = nStartFlags;
    1598             :     ParseResult aRes = ScGlobal::pCharClass->parsePredefinedToken(
    1599           0 :         KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_OUSTRING, nContFlags, EMPTY_OUSTRING);
    1600           0 :     bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.getLength());
    1601             : 
    1602           0 :     switch ( eConv )
    1603             :     {
    1604             :         default :
    1605             :         case FormulaGrammar::CONV_UNSPECIFIED :
    1606           0 :             break;
    1607             :         case FormulaGrammar::CONV_OOO :
    1608             :         case FormulaGrammar::CONV_XL_A1 :
    1609             :         case FormulaGrammar::CONV_XL_R1C1 :
    1610             :         case FormulaGrammar::CONV_XL_OOX :
    1611             :         case FormulaGrammar::CONV_ODF :
    1612           0 :             if( bNeedsQuote )
    1613             :             {
    1614           0 :                 const OUString one_quote('\'');
    1615           0 :                 const OUString two_quote("''");
    1616             :                 // escape embedded quotes
    1617           0 :                 rString = rString.replaceAll( one_quote, two_quote );
    1618             :             }
    1619           0 :             break;
    1620             :     }
    1621             : 
    1622           0 :     if ( !bNeedsQuote && CharClass::isAsciiNumeric( rString ) )
    1623             :     {
    1624             :         // Prevent any possible confusion resulting from pure numeric sheet names.
    1625           0 :         bNeedsQuote = true;
    1626             :     }
    1627             : 
    1628           0 :     if( bNeedsQuote )
    1629             :     {
    1630           0 :         rString = "'" + rString + "'";
    1631           0 :     }
    1632           0 : }
    1633             : 
    1634           0 : sal_Int32 ScCompiler::GetDocTabPos( const OUString& rString )
    1635             : {
    1636           0 :     if (rString[0] != '\'')
    1637           0 :         return -1;
    1638           0 :     sal_Int32 nPos = ScGlobal::FindUnquoted( rString, SC_COMPILER_FILE_TAB_SEP);
    1639             :     // it must be 'Doc'#
    1640           0 :     if (nPos != -1 && rString[nPos-1] != '\'')
    1641           0 :         nPos = -1;
    1642           0 :     return nPos;
    1643             : }
    1644             : 
    1645           0 : void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv )
    1646             : {
    1647           0 :     const Convention* p = GetRefConvention(eConv);
    1648           0 :     if (p)
    1649           0 :         SetRefConvention(p);
    1650           0 : }
    1651             : 
    1652           0 : const ScCompiler::Convention* ScCompiler::GetRefConvention( FormulaGrammar::AddressConvention eConv )
    1653             : {
    1654             : 
    1655           0 :     switch (eConv)
    1656             :     {
    1657             :         case FormulaGrammar::CONV_OOO:
    1658             :         {
    1659           0 :             static const ConventionOOO_A1 ConvOOO_A1;
    1660           0 :             return &ConvOOO_A1;
    1661             :         }
    1662             :         case FormulaGrammar::CONV_ODF:
    1663             :         {
    1664           0 :             static const ConventionOOO_A1_ODF ConvOOO_A1_ODF;
    1665           0 :             return &ConvOOO_A1_ODF;
    1666             :         }
    1667             :         case FormulaGrammar::CONV_XL_A1:
    1668             :         {
    1669           0 :             static const ConventionXL_A1 ConvXL_A1;
    1670           0 :             return &ConvXL_A1;
    1671             :         }
    1672             :         case FormulaGrammar::CONV_XL_R1C1:
    1673             :         {
    1674           0 :             static const ConventionXL_R1C1 ConvXL_R1C1;
    1675           0 :             return &ConvXL_R1C1;
    1676             :         }
    1677             :         case FormulaGrammar::CONV_XL_OOX:
    1678             :         {
    1679           0 :             static const ConventionXL_OOX ConvXL_OOX;
    1680           0 :             return &ConvXL_OOX;
    1681             :         }
    1682             :         case FormulaGrammar::CONV_UNSPECIFIED:
    1683             :         default:
    1684             :             ;
    1685             :     }
    1686             : 
    1687           0 :     return NULL;
    1688             : }
    1689             : 
    1690           0 : void ScCompiler::SetRefConvention( const ScCompiler::Convention *pConvP )
    1691             : {
    1692           0 :     pConv = pConvP;
    1693           0 :     meGrammar = FormulaGrammar::mergeToGrammar( meGrammar, pConv->meConv);
    1694             :     OSL_ENSURE( FormulaGrammar::isSupported( meGrammar),
    1695             :             "ScCompiler::SetRefConvention: unsupported grammar resulting");
    1696           0 : }
    1697             : 
    1698           0 : void ScCompiler::SetError(sal_uInt16 nError)
    1699             : {
    1700           0 :     if( !pArr->GetCodeError() )
    1701           0 :         pArr->SetCodeError( nError);
    1702           0 : }
    1703             : 
    1704           0 : static sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, sal_Int32 nMax )
    1705             : {
    1706           0 :     const sal_Unicode* const pStop = pDst + nMax;
    1707           0 :     while ( *pSrc && pDst < pStop )
    1708             :     {
    1709           0 :         *pDst++ = *pSrc++;
    1710             :     }
    1711           0 :     *pDst = 0;
    1712           0 :     return pDst;
    1713             : }
    1714             : 
    1715             : // NextSymbol
    1716             : 
    1717             : // Zerlegt die Formel in einzelne Symbole fuer die weitere
    1718             : // Verarbeitung (Turing-Maschine).
    1719             : 
    1720             : // Ausgangs Zustand = GetChar
    1721             : 
    1722             : // Alter Zustand | gelesenes Zeichen | Aktion                | Neuer Zustand
    1723             : //---------------+-------------------+-----------------------+---------------
    1724             : // GetChar       | ;()+-*/^=&        | Symbol=Zeichen        | Stop
    1725             : //               | <>                | Symbol=Zeichen        | GetBool
    1726             : //               | $ Buchstabe       | Symbol=Zeichen        | GetWord
    1727             : //               | Ziffer            | Symbol=Zeichen        | GetValue
    1728             : //               | "                 | Keine                 | GetString
    1729             : //               | Sonst             | Keine                 | GetChar
    1730             : //---------------+-------------------+-----------------------+---------------
    1731             : // GetBool       | =>                | Symbol=Symbol+Zeichen | Stop
    1732             : //               | Sonst             | Dec(CharPos)          | Stop
    1733             : //---------------+-------------------+-----------------------+---------------
    1734             : // GetWord       | SepSymbol         | Dec(CharPos)          | Stop
    1735             : //               | ()+-*/^=<>&~      |                       |
    1736             : //               | Leerzeichen       | Dec(CharPos)          | Stop
    1737             : //               | $_:.              |                       |
    1738             : //               | Buchstabe,Ziffer  | Symbol=Symbol+Zeichen | GetWord
    1739             : //               | Sonst             | Fehler                | Stop
    1740             : //---------------+-------------------+-----------------------+---------------
    1741             : // GetValue      | ;()*/^=<>&        |                       |
    1742             : //               | Leerzeichen       | Dec(CharPos)          | Stop
    1743             : //               | Ziffer E+-%,.     | Symbol=Symbol+Zeichen | GetValue
    1744             : //               | Sonst             | Fehler                | Stop
    1745             : //---------------+-------------------+-----------------------+---------------
    1746             : // GetString     | "                 | Keine                 | Stop
    1747             : //               | Sonst             | Symbol=Symbol+Zeichen | GetString
    1748             : //---------------+-------------------+-----------------------+---------------
    1749             : 
    1750           0 : sal_Int32 ScCompiler::NextSymbol(bool bInArray)
    1751             : {
    1752           0 :     cSymbol[MAXSTRLEN-1] = 0;       // Stopper
    1753           0 :     sal_Unicode* pSym = cSymbol;
    1754           0 :     const sal_Unicode* const pStart = aFormula.getStr();
    1755           0 :     const sal_Unicode* pSrc = pStart + nSrcPos;
    1756           0 :     bool bi18n = false;
    1757           0 :     sal_Unicode c = *pSrc;
    1758           0 :     sal_Unicode cLast = 0;
    1759           0 :     bool bQuote = false;
    1760           0 :     mnRangeOpPosInSymbol = -1;
    1761           0 :     ScanState eState = ssGetChar;
    1762           0 :     sal_Int32 nSpaces = 0;
    1763           0 :     sal_Unicode cSep = mxSymbols->getSymbolChar( ocSep);
    1764           0 :     sal_Unicode cArrayColSep = mxSymbols->getSymbolChar( ocArrayColSep);
    1765           0 :     sal_Unicode cArrayRowSep = mxSymbols->getSymbolChar( ocArrayRowSep);
    1766           0 :     sal_Unicode cDecSep = (mxSymbols->isEnglish() ? '.' :
    1767           0 :             ScGlobal::pLocaleData->getNumDecimalSep()[0]);
    1768             : 
    1769             :     // special symbols specific to address convention used
    1770           0 :     sal_Unicode cSheetPrefix = pConv->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX);
    1771           0 :     sal_Unicode cSheetSep    = pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
    1772             : 
    1773           0 :     int nDecSeps = 0;
    1774           0 :     bool bAutoIntersection = false;
    1775           0 :     int nRefInName = 0;
    1776           0 :     bool bErrorConstantHadSlash = false;
    1777           0 :     mnPredetectedReference = 0;
    1778             :     // try to parse simple tokens before calling i18n parser
    1779           0 :     while ((c != 0) && (eState != ssStop) )
    1780             :     {
    1781           0 :         pSrc++;
    1782           0 :         sal_uLong nMask = GetCharTableFlags( c, cLast );
    1783             : 
    1784             :         // The parameter separator and the array column and row separators end
    1785             :         // things unconditionally if not in string or reference.
    1786           0 :         if (c == cSep || (bInArray && (c == cArrayColSep || c == cArrayRowSep)))
    1787             :         {
    1788           0 :             switch (eState)
    1789             :             {
    1790             :                 // these are to be continued
    1791             :                 case ssGetString:
    1792             :                 case ssSkipString:
    1793             :                 case ssGetReference:
    1794             :                 case ssSkipReference:
    1795           0 :                     break;
    1796             :                 default:
    1797           0 :                     if (eState == ssGetChar)
    1798           0 :                         *pSym++ = c;
    1799             :                     else
    1800           0 :                         pSrc--;
    1801           0 :                     eState = ssStop;
    1802             :             }
    1803             :         }
    1804             : Label_MaskStateMachine:
    1805           0 :         switch (eState)
    1806             :         {
    1807             :             case ssGetChar :
    1808             :             {
    1809             :                 // Order is important!
    1810           0 :                 if( nMask & SC_COMPILER_C_ODF_LABEL_OP )
    1811             :                 {
    1812             :                     // '!!' automatic intersection
    1813           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_ODF_LABEL_OP)
    1814             :                     {
    1815             :                         /* TODO: For now the UI "space operator" is used, this
    1816             :                          * could be enhanced using a specialized OpCode to get
    1817             :                          * rid of the space ambiguity, which would need some
    1818             :                          * places to be adapted though. And we would still need
    1819             :                          * to support the ambiguous space operator for UI
    1820             :                          * purposes anyway. However, we then could check for
    1821             :                          * invalid usage of '!!', which currently isn't
    1822             :                          * possible. */
    1823           0 :                         if (!bAutoIntersection)
    1824             :                         {
    1825           0 :                             ++pSrc;
    1826           0 :                             nSpaces += 2;   // must match the character count
    1827           0 :                             bAutoIntersection = true;
    1828             :                         }
    1829             :                         else
    1830             :                         {
    1831           0 :                             pSrc--;
    1832           0 :                             eState = ssStop;
    1833             :                         }
    1834             :                     }
    1835             :                     else
    1836             :                     {
    1837           0 :                         nMask &= ~SC_COMPILER_C_ODF_LABEL_OP;
    1838           0 :                         goto Label_MaskStateMachine;
    1839             :                     }
    1840             :                 }
    1841           0 :                 else if( nMask & SC_COMPILER_C_ODF_NAME_MARKER )
    1842             :                 {
    1843             :                     // '$$' defined name marker
    1844           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_ODF_NAME_MARKER)
    1845             :                     {
    1846             :                         // both eaten, not added to pSym
    1847           0 :                         ++pSrc;
    1848             :                     }
    1849             :                     else
    1850             :                     {
    1851           0 :                         nMask &= ~SC_COMPILER_C_ODF_NAME_MARKER;
    1852           0 :                         goto Label_MaskStateMachine;
    1853             :                     }
    1854             :                 }
    1855           0 :                 else if( nMask & SC_COMPILER_C_CHAR )
    1856             :                 {
    1857           0 :                     *pSym++ = c;
    1858           0 :                     eState = ssStop;
    1859             :                 }
    1860           0 :                 else if( nMask & SC_COMPILER_C_ODF_LBRACKET )
    1861             :                 {
    1862             :                     // eaten, not added to pSym
    1863           0 :                     eState = ssGetReference;
    1864           0 :                     mnPredetectedReference = 1;
    1865             :                 }
    1866           0 :                 else if( nMask & SC_COMPILER_C_CHAR_BOOL )
    1867             :                 {
    1868           0 :                     *pSym++ = c;
    1869           0 :                     eState = ssGetBool;
    1870             :                 }
    1871           0 :                 else if( nMask & SC_COMPILER_C_CHAR_VALUE )
    1872             :                 {
    1873           0 :                     *pSym++ = c;
    1874           0 :                     eState = ssGetValue;
    1875             :                 }
    1876           0 :                 else if( nMask & SC_COMPILER_C_CHAR_STRING )
    1877             :                 {
    1878           0 :                     *pSym++ = c;
    1879           0 :                     eState = ssGetString;
    1880             :                 }
    1881           0 :                 else if( nMask & SC_COMPILER_C_CHAR_ERRCONST )
    1882             :                 {
    1883           0 :                     *pSym++ = c;
    1884           0 :                     eState = ssGetErrorConstant;
    1885             :                 }
    1886           0 :                 else if( nMask & SC_COMPILER_C_CHAR_DONTCARE )
    1887             :                 {
    1888           0 :                     nSpaces++;
    1889             :                 }
    1890           0 :                 else if( nMask & SC_COMPILER_C_CHAR_IDENT )
    1891             :                 {   // try to get a simple ASCII identifier before calling
    1892             :                     // i18n, to gain performance during import
    1893           0 :                     *pSym++ = c;
    1894           0 :                     eState = ssGetIdent;
    1895             :                 }
    1896             :                 else
    1897             :                 {
    1898           0 :                     bi18n = true;
    1899           0 :                     eState = ssStop;
    1900             :                 }
    1901             :             }
    1902           0 :             break;
    1903             :             case ssGetIdent:
    1904             :             {
    1905           0 :                 if ( nMask & SC_COMPILER_C_IDENT )
    1906             :                 {   // This catches also $Sheet1.A$1, for example.
    1907           0 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    1908             :                     {
    1909           0 :                         SetError(errStringOverflow);
    1910           0 :                         eState = ssStop;
    1911             :                     }
    1912             :                     else
    1913           0 :                         *pSym++ = c;
    1914             :                 }
    1915           0 :                 else if (c == ':' && mnRangeOpPosInSymbol < 0)
    1916             :                 {
    1917             :                     // One range operator may form Sheet1.A:A, which we need to
    1918             :                     // pass as one entity to IsReference().
    1919           0 :                     mnRangeOpPosInSymbol = pSym - &cSymbol[0];
    1920           0 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    1921             :                     {
    1922           0 :                         SetError(errStringOverflow);
    1923           0 :                         eState = ssStop;
    1924             :                     }
    1925             :                     else
    1926           0 :                         *pSym++ = c;
    1927             :                 }
    1928           0 :                 else if ( 128 <= c || '\'' == c )
    1929             :                 {   // High values need reparsing with i18n,
    1930             :                     // single quoted $'sheet' names too (otherwise we'd had to
    1931             :                     // implement everything twice).
    1932           0 :                     bi18n = true;
    1933           0 :                     eState = ssStop;
    1934             :                 }
    1935             :                 else
    1936             :                 {
    1937           0 :                     pSrc--;
    1938           0 :                     eState = ssStop;
    1939             :                 }
    1940             :             }
    1941           0 :             break;
    1942             :             case ssGetBool :
    1943             :             {
    1944           0 :                 if( nMask & SC_COMPILER_C_BOOL )
    1945             :                 {
    1946           0 :                     *pSym++ = c;
    1947           0 :                     eState = ssStop;
    1948             :                 }
    1949             :                 else
    1950             :                 {
    1951           0 :                     pSrc--;
    1952           0 :                     eState = ssStop;
    1953             :                 }
    1954             :             }
    1955           0 :             break;
    1956             :             case ssGetValue :
    1957             :             {
    1958           0 :                 if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    1959             :                 {
    1960           0 :                     SetError(errStringOverflow);
    1961           0 :                     eState = ssStop;
    1962             :                 }
    1963           0 :                 else if (c == cDecSep)
    1964             :                 {
    1965           0 :                     if (++nDecSeps > 1)
    1966             :                     {
    1967             :                         // reparse with i18n, may be numeric sheet name as well
    1968           0 :                         bi18n = true;
    1969           0 :                         eState = ssStop;
    1970             :                     }
    1971             :                     else
    1972           0 :                         *pSym++ = c;
    1973             :                 }
    1974           0 :                 else if( nMask & SC_COMPILER_C_VALUE )
    1975           0 :                     *pSym++ = c;
    1976           0 :                 else if( nMask & SC_COMPILER_C_VALUE_SEP )
    1977             :                 {
    1978           0 :                     pSrc--;
    1979           0 :                     eState = ssStop;
    1980             :                 }
    1981           0 :                 else if (c == 'E' || c == 'e')
    1982             :                 {
    1983           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_VALUE_EXP)
    1984           0 :                         *pSym++ = c;
    1985             :                     else
    1986             :                     {
    1987             :                         // reparse with i18n
    1988           0 :                         bi18n = true;
    1989           0 :                         eState = ssStop;
    1990             :                     }
    1991             :                 }
    1992           0 :                 else if( nMask & SC_COMPILER_C_VALUE_SIGN )
    1993             :                 {
    1994           0 :                     if (((cLast == 'E') || (cLast == 'e')) &&
    1995           0 :                             (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_VALUE_VALUE))
    1996             :                     {
    1997           0 :                         *pSym++ = c;
    1998             :                     }
    1999             :                     else
    2000             :                     {
    2001           0 :                         pSrc--;
    2002           0 :                         eState = ssStop;
    2003             :                     }
    2004             :                 }
    2005             :                 else
    2006             :                 {
    2007             :                     // reparse with i18n
    2008           0 :                     bi18n = true;
    2009           0 :                     eState = ssStop;
    2010             :                 }
    2011             :             }
    2012           0 :             break;
    2013             :             case ssGetString :
    2014             :             {
    2015           0 :                 if( nMask & SC_COMPILER_C_STRING_SEP )
    2016             :                 {
    2017           0 :                     if ( !bQuote )
    2018             :                     {
    2019           0 :                         if ( *pSrc == '"' )
    2020           0 :                             bQuote = true;      // "" => literal "
    2021             :                         else
    2022           0 :                             eState = ssStop;
    2023             :                     }
    2024             :                     else
    2025           0 :                         bQuote = false;
    2026             :                 }
    2027           0 :                 if ( !bQuote )
    2028             :                 {
    2029           0 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2030             :                     {
    2031           0 :                         SetError(errStringOverflow);
    2032           0 :                         eState = ssSkipString;
    2033             :                     }
    2034             :                     else
    2035           0 :                         *pSym++ = c;
    2036             :                 }
    2037             :             }
    2038           0 :             break;
    2039             :             case ssSkipString:
    2040           0 :                 if( nMask & SC_COMPILER_C_STRING_SEP )
    2041           0 :                     eState = ssStop;
    2042           0 :                 break;
    2043             :             case ssGetErrorConstant:
    2044             :                 {
    2045             :                     // ODFF Error ::= '#' [A-Z0-9]+ ([!?] | ('/' ([A-Z] | ([0-9] [!?]))))
    2046             :                     // BUT, in UI these may have been translated! So don't
    2047             :                     // check for ASCII alnum. Note that this construct can't be
    2048             :                     // parsed with i18n.
    2049             :                     /* TODO: be strict when reading ODFF, check for ASCII alnum
    2050             :                      * and proper continuation after '/'. However, even with
    2051             :                      * the lax parsing only the error constants we have defined
    2052             :                      * as opcode symbols will be recognized and others result
    2053             :                      * in ocBad, so the result is actually conformant. */
    2054           0 :                     bool bAdd = true;
    2055           0 :                     if ('!' == c || '?' == c)
    2056           0 :                         eState = ssStop;
    2057           0 :                     else if ('/' == c)
    2058             :                     {
    2059           0 :                         if (!bErrorConstantHadSlash)
    2060           0 :                             bErrorConstantHadSlash = true;
    2061             :                         else
    2062             :                         {
    2063           0 :                             bAdd = false;
    2064           0 :                             eState = ssStop;
    2065             :                         }
    2066             :                     }
    2067           0 :                     else if ((nMask & SC_COMPILER_C_WORD_SEP) ||
    2068           0 :                             (c < 128 && !rtl::isAsciiAlphanumeric( c)))
    2069             :                     {
    2070           0 :                         bAdd = false;
    2071           0 :                         eState = ssStop;
    2072             :                     }
    2073           0 :                     if (!bAdd)
    2074           0 :                         --pSrc;
    2075             :                     else
    2076             :                     {
    2077           0 :                         if (pSym == &cSymbol[ MAXSTRLEN-1 ])
    2078             :                         {
    2079           0 :                             SetError( errStringOverflow);
    2080           0 :                             eState = ssStop;
    2081             :                         }
    2082             :                         else
    2083           0 :                             *pSym++ = c;
    2084             :                     }
    2085             :                 }
    2086           0 :                 break;
    2087             :             case ssGetReference:
    2088           0 :                 if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2089             :                 {
    2090           0 :                     SetError( errStringOverflow);
    2091           0 :                     eState = ssSkipReference;
    2092             :                 }
    2093             :                 // fall through and follow logic
    2094             :             case ssSkipReference:
    2095             :                 // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being
    2096             :                 // mandatory also if no sheet name. 'External'# is optional,
    2097             :                 // sheet name is optional, quotes around sheet name are
    2098             :                 // optional if no quote contained. [#REF!] is valid.
    2099             :                 // 2nd usage: ['Sheet'.$$'DefinedName']
    2100             :                 // 3rd usage: ['External'#$$'DefinedName']
    2101             :                 // 4th usage: ['External'#$'Sheet'.$$'DefinedName']
    2102             :                 // Also for all these names quotes are optional if no quote
    2103             :                 // contained.
    2104             :                 {
    2105             : 
    2106             :                     // nRefInName: 0 := not in sheet name yet. 'External'
    2107             :                     // is parsed as if it was a sheet name and nRefInName
    2108             :                     // is reset when # is encountered immediately after closing
    2109             :                     // quote. Same with 'DefinedName', nRefInName is cleared
    2110             :                     // when : is encountered.
    2111             : 
    2112             :                     // Encountered leading $ before sheet name.
    2113             :                     static const int kDollar    = (1 << 1);
    2114             :                     // Encountered ' opening quote, which may be after $ or
    2115             :                     // not.
    2116             :                     static const int kOpen      = (1 << 2);
    2117             :                     // Somewhere in name.
    2118             :                     static const int kName      = (1 << 3);
    2119             :                     // Encountered ' in name, will be cleared if double or
    2120             :                     // transformed to kClose if not, in which case kOpen is
    2121             :                     // cleared.
    2122             :                     static const int kQuote     = (1 << 4);
    2123             :                     // Past ' closing quote.
    2124             :                     static const int kClose     = (1 << 5);
    2125             :                     // Encountered # file/sheet separator.
    2126             :                     static const int kFileSep   = (1 << 6);
    2127             :                     // Past . sheet name separator.
    2128             :                     static const int kPast      = (1 << 7);
    2129             :                     // Marked name $$ follows sheet name separator, detected
    2130             :                     // while we're still on the separator. Will be cleared when
    2131             :                     // entering the name.
    2132             :                     static const int kMarkAhead = (1 << 8);
    2133             :                     // In marked defined name.
    2134             :                     static const int kDefName   = (1 << 9);
    2135             :                     // Encountered # of #REF!
    2136             :                     static const int kRefErr    = (1 << 10);
    2137             : 
    2138           0 :                     bool bAddToSymbol = true;
    2139           0 :                     if ((nMask & SC_COMPILER_C_ODF_RBRACKET) && !(nRefInName & kOpen))
    2140             :                     {
    2141             :                         OSL_ENSURE( nRefInName & (kPast | kDefName | kRefErr),
    2142             :                                 "ScCompiler::NextSymbol: reference: "
    2143             :                                 "closing bracket ']' without prior sheet name separator '.' violates ODF spec");
    2144             :                         // eaten, not added to pSym
    2145           0 :                         bAddToSymbol = false;
    2146           0 :                         eState = ssStop;
    2147             :                     }
    2148           0 :                     else if (cSheetSep == c && nRefInName == 0)
    2149             :                     {
    2150             :                         // eat it, no sheet name [.A1]
    2151           0 :                         bAddToSymbol = false;
    2152           0 :                         nRefInName |= kPast;
    2153           0 :                         if ('$' == pSrc[0] && '$' == pSrc[1])
    2154           0 :                             nRefInName |= kMarkAhead;
    2155             :                     }
    2156           0 :                     else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName)))
    2157             :                     {
    2158             :                         // Not in col/row yet.
    2159             : 
    2160           0 :                         if (SC_COMPILER_FILE_TAB_SEP == c && (nRefInName & kFileSep))
    2161           0 :                             nRefInName = 0;
    2162           0 :                         else if ('$' == c && '$' == pSrc[0] && !(nRefInName & kOpen))
    2163             :                         {
    2164           0 :                             nRefInName &= ~kMarkAhead;
    2165           0 :                             if (!(nRefInName & kDefName))
    2166             :                             {
    2167             :                                 // eaten, not added to pSym (2 chars)
    2168           0 :                                 bAddToSymbol = false;
    2169           0 :                                 ++pSrc;
    2170           0 :                                 nRefInName &= kPast;
    2171           0 :                                 nRefInName |= kDefName;
    2172             :                             }
    2173             :                             else
    2174             :                             {
    2175             :                                 // ScAddress::Parse() will recognize this as
    2176             :                                 // invalid later.
    2177           0 :                                 if (eState != ssSkipReference)
    2178             :                                 {
    2179           0 :                                     *pSym++ = c;
    2180           0 :                                     *pSym++ = *pSrc++;
    2181             :                                 }
    2182           0 :                                 bAddToSymbol = false;
    2183             :                             }
    2184             :                         }
    2185           0 :                         else if (cSheetPrefix == c && nRefInName == 0)
    2186           0 :                             nRefInName |= kDollar;
    2187           0 :                         else if ('\'' == c)
    2188             :                         {
    2189             :                             // TODO: The conventions' parseExternalName()
    2190             :                             // should handle quoted names, but as long as they
    2191             :                             // don't remove non-embedded quotes here.
    2192           0 :                             if (!(nRefInName & kName))
    2193             :                             {
    2194           0 :                                 nRefInName |= (kOpen | kName);
    2195           0 :                                 bAddToSymbol = !(nRefInName & kDefName);
    2196             :                             }
    2197           0 :                             else if (!(nRefInName & kOpen))
    2198             :                             {
    2199             :                                 OSL_FAIL("ScCompiler::NextSymbol: reference: "
    2200             :                                         "a ''' without the name being enclosed in '...' violates ODF spec");
    2201             :                             }
    2202           0 :                             else if (nRefInName & kQuote)
    2203             :                             {
    2204             :                                 // escaped embedded quote
    2205           0 :                                 nRefInName &= ~kQuote;
    2206             :                             }
    2207             :                             else
    2208             :                             {
    2209           0 :                                 switch (pSrc[0])
    2210             :                                 {
    2211             :                                     case '\'':
    2212             :                                         // escapes embedded quote
    2213           0 :                                         nRefInName |= kQuote;
    2214           0 :                                         break;
    2215             :                                     case SC_COMPILER_FILE_TAB_SEP:
    2216             :                                         // sheet name should follow
    2217           0 :                                         nRefInName |= kFileSep;
    2218             :                                         // fallthru
    2219             :                                     default:
    2220             :                                         // quote not followed by quote => close
    2221           0 :                                         nRefInName |= kClose;
    2222           0 :                                         nRefInName &= ~kOpen;
    2223             :                                 }
    2224           0 :                                 bAddToSymbol = !(nRefInName & kDefName);
    2225             :                             }
    2226             :                         }
    2227           0 :                         else if ('#' == c && nRefInName == 0)
    2228           0 :                             nRefInName |= kRefErr;
    2229           0 :                         else if (cSheetSep == c && !(nRefInName & kOpen))
    2230             :                         {
    2231             :                             // unquoted sheet name separator
    2232           0 :                             nRefInName |= kPast;
    2233           0 :                             if ('$' == pSrc[0] && '$' == pSrc[1])
    2234           0 :                                 nRefInName |= kMarkAhead;
    2235             :                         }
    2236           0 :                         else if (':' == c && !(nRefInName & kOpen))
    2237             :                         {
    2238             :                             OSL_FAIL("ScCompiler::NextSymbol: reference: "
    2239             :                                     "range operator ':' without prior sheet name separator '.' violates ODF spec");
    2240           0 :                             nRefInName = 0;
    2241           0 :                             ++mnPredetectedReference;
    2242             :                         }
    2243           0 :                         else if (!(nRefInName & kName))
    2244             :                         {
    2245             :                             // start unquoted name
    2246           0 :                             nRefInName |= kName;
    2247             :                         }
    2248             :                     }
    2249           0 :                     else if (':' == c)
    2250             :                     {
    2251             :                         // range operator
    2252           0 :                         nRefInName = 0;
    2253           0 :                         ++mnPredetectedReference;
    2254             :                     }
    2255           0 :                     if (bAddToSymbol && eState != ssSkipReference)
    2256           0 :                         *pSym++ = c;    // everything is part of reference
    2257             :                 }
    2258           0 :                 break;
    2259             :             case ssStop:
    2260             :                 ;   // nothing, prevent warning
    2261           0 :                 break;
    2262             :         }
    2263           0 :         cLast = c;
    2264           0 :         c = *pSrc;
    2265             :     }
    2266           0 :     if ( bi18n )
    2267             :     {
    2268           0 :         nSrcPos = nSrcPos + nSpaces;
    2269           0 :         OUStringBuffer aSymbol;
    2270           0 :         mnRangeOpPosInSymbol = -1;
    2271           0 :         sal_uInt16 nErr = 0;
    2272           0 :         do
    2273             :         {
    2274           0 :             bi18n = false;
    2275             :             // special case  (e.g. $'sheetname' in OOO A1)
    2276           0 :             if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' )
    2277           0 :                 aSymbol.append(pStart[nSrcPos++]);
    2278             : 
    2279           0 :             ParseResult aRes = pConv->parseAnyToken( aFormula, nSrcPos, pCharClass );
    2280             : 
    2281           0 :             if ( !aRes.TokenType )
    2282           0 :                 SetError( nErr = errIllegalChar );      // parsed chars as string
    2283           0 :             if ( aRes.EndPos <= nSrcPos )
    2284             :             {   // ?!?
    2285           0 :                 SetError( nErr = errIllegalChar );
    2286           0 :                 nSrcPos = aFormula.getLength();
    2287           0 :                 aSymbol.truncate(0);
    2288             :             }
    2289             :             else
    2290             :             {
    2291           0 :                 aSymbol.append( pStart + nSrcPos, aRes.EndPos - nSrcPos);
    2292           0 :                 nSrcPos = aRes.EndPos;
    2293           0 :                 c = pStart[nSrcPos];
    2294           0 :                 if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME )
    2295             :                 {   // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
    2296           0 :                     bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP);
    2297             :                 }
    2298             :                 // One range operator restarts parsing for second reference.
    2299           0 :                 if (c == ':' && mnRangeOpPosInSymbol < 0)
    2300             :                 {
    2301           0 :                     mnRangeOpPosInSymbol = aSymbol.getLength();
    2302           0 :                     bi18n = true;
    2303             :                 }
    2304           0 :                 if ( bi18n )
    2305           0 :                     aSymbol.append(pStart[nSrcPos++]);
    2306           0 :             }
    2307           0 :         } while ( bi18n && !nErr );
    2308           0 :         sal_Int32 nLen = aSymbol.getLength();
    2309           0 :         if ( nLen >= MAXSTRLEN )
    2310             :         {
    2311           0 :             SetError( errStringOverflow );
    2312           0 :             nLen = MAXSTRLEN-1;
    2313             :         }
    2314           0 :         lcl_UnicodeStrNCpy( cSymbol, aSymbol.getStr(), nLen );
    2315           0 :         pSym = &cSymbol[nLen];
    2316             :     }
    2317             :     else
    2318             :     {
    2319           0 :         nSrcPos = pSrc - pStart;
    2320           0 :         *pSym = 0;
    2321             :     }
    2322           0 :     if (mnRangeOpPosInSymbol >= 0 && mnRangeOpPosInSymbol == (pSym-1) - &cSymbol[0])
    2323             :     {
    2324             :         // This is a trailing range operator, which is nonsense. Will be caught
    2325             :         // in next round.
    2326           0 :         mnRangeOpPosInSymbol = -1;
    2327           0 :         *--pSym = 0;
    2328           0 :         --nSrcPos;
    2329             :     }
    2330           0 :     if ( bAutoCorrect )
    2331           0 :         aCorrectedSymbol = cSymbol;
    2332           0 :     if (bAutoIntersection && nSpaces > 1)
    2333           0 :         --nSpaces;  // replace '!!' with only one space
    2334           0 :     return nSpaces;
    2335             : }
    2336             : 
    2337             : // Convert symbol to token
    2338             : 
    2339           0 : bool ScCompiler::IsOpCode( const OUString& rName, bool bInArray )
    2340             : {
    2341           0 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
    2342           0 :     bool bFound = (iLook != mxSymbols->getHashMap()->end());
    2343           0 :     if (bFound)
    2344             :     {
    2345           0 :         ScRawToken aToken;
    2346           0 :         OpCode eOp = iLook->second;
    2347           0 :         if (bInArray)
    2348             :         {
    2349           0 :             if (rName.equals(mxSymbols->getSymbol(ocArrayColSep)))
    2350           0 :                 eOp = ocArrayColSep;
    2351           0 :             else if (rName.equals(mxSymbols->getSymbol(ocArrayRowSep)))
    2352           0 :                 eOp = ocArrayRowSep;
    2353             :         }
    2354           0 :         aToken.SetOpCode(eOp);
    2355           0 :         pRawToken = aToken.Clone();
    2356             :     }
    2357           0 :     else if (mxSymbols->isODFF())
    2358             :     {
    2359             :         // ODFF names that are not written in the current mapping but to be
    2360             :         // recognized. New names will be written in a future relase, then
    2361             :         // exchange (!) with the names in
    2362             :         // formula/source/core/resource/core_resource.src to be able to still
    2363             :         // read the old names as well.
    2364             :         struct FunctionName
    2365             :         {
    2366             :             const sal_Char* pName;
    2367             :             OpCode          eOp;
    2368             :         };
    2369             :         static const FunctionName aOdffAliases[] = {
    2370             :             // Renamed old names, still accept them:
    2371             :             { "B",              ocB },              // B -> BINOM.DIST.RANGE
    2372             :             { "TDIST",          ocTDist },          // TDIST -> LEGACY.TDIST
    2373             :             { "EASTERSUNDAY",   ocEasterSunday },   // EASTERSUNDAY -> ORG.OPENOFFICE.EASTERSUNDAY
    2374             :             { "ZGZ",            ocZGZ },            // ZGZ -> RRI
    2375             :             // Renamed new names, prepare to read future names:
    2376             :             { "ORG.OPENOFFICE.GOALSEEK", ocBackSolver } // GOALSEEK -> ORG.OPENOFFICE.GOALSEEK
    2377             :         };
    2378             :         static const size_t nOdffAliases = sizeof(aOdffAliases) / sizeof(aOdffAliases[0]);
    2379           0 :         for (size_t i=0; i<nOdffAliases; ++i)
    2380             :         {
    2381           0 :             if (rName.equalsIgnoreAsciiCaseAscii( aOdffAliases[i].pName))
    2382             :             {
    2383           0 :                 ScRawToken aToken;
    2384           0 :                 aToken.SetOpCode( aOdffAliases[i].eOp);
    2385           0 :                 pRawToken = aToken.Clone();
    2386           0 :                 bFound = true;
    2387           0 :                 break;  // for
    2388             :             }
    2389             :         }
    2390             :     }
    2391           0 :     if (!bFound)
    2392             :     {
    2393           0 :         OUString aIntName;
    2394           0 :         if (mxSymbols->hasExternals())
    2395             :         {
    2396             :             // If symbols are set by filters get mapping to exact name.
    2397             :             ExternalHashMap::const_iterator iExt(
    2398           0 :                     mxSymbols->getExternalHashMap()->find( rName));
    2399           0 :             if (iExt != mxSymbols->getExternalHashMap()->end())
    2400             :             {
    2401           0 :                 if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt).second))
    2402           0 :                     aIntName = (*iExt).second;
    2403             :             }
    2404           0 :             if (aIntName.isEmpty())
    2405             :             {
    2406             :                 // If that isn't found we might continue with rName lookup as a
    2407             :                 // last resort by just falling through to FindFunction(), but
    2408             :                 // it shouldn't happen if the map was setup correctly. Don't
    2409             :                 // waste time and bail out.
    2410           0 :                 return false;
    2411             :             }
    2412             :         }
    2413           0 :         if (aIntName.isEmpty())
    2414             :         {
    2415             :             // Old (deprecated) addins first for legacy.
    2416           0 :             if (ScGlobal::GetFuncCollection()->findByName(cSymbol))
    2417             :             {
    2418           0 :                 ScRawToken aToken;
    2419           0 :                 aToken.SetExternal( cSymbol );
    2420           0 :                 pRawToken = aToken.Clone();
    2421             :             }
    2422             :             else
    2423             :                 // bLocalFirst=false for (English) upper full original name
    2424             :                 // (service.function)
    2425           0 :                 aIntName = ScGlobal::GetAddInCollection()->FindFunction(
    2426           0 :                         rName, !mxSymbols->isEnglish());
    2427             :         }
    2428           0 :         if (!aIntName.isEmpty())
    2429             :         {
    2430           0 :             ScRawToken aToken;
    2431           0 :             aToken.SetExternal( aIntName.getStr() );     // international name
    2432           0 :             pRawToken = aToken.Clone();
    2433           0 :             bFound = true;
    2434           0 :         }
    2435             :     }
    2436             :     OpCode eOp;
    2437           0 :     if (bFound && ((eOp = pRawToken->GetOpCode()) == ocSub || eOp == ocNegSub))
    2438             :     {
    2439             :         bool bShouldBeNegSub =
    2440           0 :             (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub ||
    2441           0 :              (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_BIN_OP) ||
    2442           0 :              eLastOp == ocArrayOpen ||
    2443           0 :              eLastOp == ocArrayColSep || eLastOp == ocArrayRowSep);
    2444           0 :         if (bShouldBeNegSub && eOp == ocSub)
    2445           0 :             pRawToken->NewOpCode( ocNegSub );
    2446             :             //! if ocNegSub had ForceArray we'd have to set it here
    2447           0 :         else if (!bShouldBeNegSub && eOp == ocNegSub)
    2448           0 :             pRawToken->NewOpCode( ocSub );
    2449             :     }
    2450           0 :     return bFound;
    2451             : }
    2452             : 
    2453           0 : bool ScCompiler::IsOpCode2( const OUString& rName )
    2454             : {
    2455           0 :     bool bFound = false;
    2456             :     sal_uInt16 i;
    2457             : 
    2458           0 :     for( i = ocInternalBegin; i <= ocInternalEnd && !bFound; i++ )
    2459           0 :         bFound = rName.equalsAscii( pInternal[ i-ocInternalBegin ] );
    2460             : 
    2461           0 :     if (bFound)
    2462             :     {
    2463           0 :         ScRawToken aToken;
    2464           0 :         aToken.SetOpCode( (OpCode) --i );
    2465           0 :         pRawToken = aToken.Clone();
    2466             :     }
    2467           0 :     return bFound;
    2468             : }
    2469             : 
    2470           0 : bool ScCompiler::IsValue( const OUString& rSym )
    2471             : {
    2472             :     double fVal;
    2473           0 :     sal_uInt32 nIndex = mxSymbols->isEnglish() ? mpFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US) : 0;
    2474             : 
    2475           0 :     if (!mpFormatter->IsNumberFormat(rSym, nIndex, fVal))
    2476           0 :         return false;
    2477             : 
    2478           0 :     sal_uInt16 nType = mpFormatter->GetType(nIndex);
    2479             : 
    2480             :     // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
    2481             :     // Dates should never be entered directly and automatically converted
    2482             :     // to serial, because the serial would be wrong if null-date changed.
    2483             :     // Usually it wouldn't be accepted anyway because the date separator
    2484             :     // clashed with other separators or operators.
    2485           0 :     if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE))
    2486           0 :         return false;
    2487             : 
    2488           0 :     if (nType == NUMBERFORMAT_LOGICAL)
    2489             :     {
    2490           0 :         const sal_Unicode* p = aFormula.getStr() + nSrcPos;
    2491           0 :         while( *p == ' ' )
    2492           0 :             p++;
    2493           0 :         if (*p == '(')
    2494           0 :             return false;   // Boolean function instead.
    2495             :     }
    2496             : 
    2497           0 :     if( nType == NUMBERFORMAT_TEXT )
    2498             :         // HACK: number too big!
    2499           0 :         SetError( errIllegalArgument );
    2500           0 :     ScRawToken aToken;
    2501           0 :     aToken.SetDouble( fVal );
    2502           0 :     pRawToken = aToken.Clone();
    2503           0 :     return true;
    2504             : }
    2505             : 
    2506           0 : bool ScCompiler::IsString()
    2507             : {
    2508           0 :     const sal_Unicode* p = cSymbol;
    2509           0 :     while ( *p )
    2510           0 :         p++;
    2511           0 :     sal_Int32 nLen = sal::static_int_cast<sal_Int32>( p - cSymbol - 1 );
    2512           0 :     bool bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"'));
    2513           0 :     if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1)
    2514             :     {
    2515           0 :         SetError(errStringOverflow);
    2516           0 :         return false;
    2517             :     }
    2518           0 :     if ( bQuote )
    2519             :     {
    2520           0 :         cSymbol[nLen] = '\0';
    2521           0 :         ScRawToken aToken;
    2522           0 :         const sal_Unicode* pStr = cSymbol+1;
    2523           0 :         svl::SharedString aSS = pDoc->GetSharedStringPool().intern(OUString(pStr));
    2524           0 :         aToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    2525           0 :         pRawToken = aToken.Clone();
    2526           0 :         return true;
    2527             :     }
    2528           0 :     return false;
    2529             : }
    2530             : 
    2531           0 : bool ScCompiler::IsPredetectedReference(const OUString& rName)
    2532             : {
    2533             :     // Speedup documents with lots of broken references, e.g. sheet deleted.
    2534           0 :     sal_Int32 nPos = rName.indexOf("#REF!");
    2535           0 :     if (nPos != -1)
    2536             :     {
    2537             :         /* TODO: this may be enhanced by reusing scan information from
    2538             :          * NextSymbol(), the positions of quotes and special characters found
    2539             :          * there for $'sheet'.A1:... could be stored in a vector. We don't
    2540             :          * fully rescan here whether found positions are within single quotes
    2541             :          * for performance reasons. This code does not check for possible
    2542             :          * occurrences of insane "valid" sheet names like
    2543             :          * 'haha.#REF!1fooledyou' and will generate an error on such. */
    2544           0 :         if (nPos == 0)
    2545             :         {
    2546             :             // Per ODFF the correct string for a reference error is just #REF!,
    2547             :             // so pass it on.
    2548           0 :             if (rName.getLength() == 5)
    2549           0 :                 return IsErrorConstant( rName);
    2550           0 :             return false;           // #REF!.AB42 or #REF!42 or #REF!#REF!
    2551             :         }
    2552           0 :         sal_Unicode c = rName[nPos-1];      // before #REF!
    2553           0 :         if ('$' == c)
    2554             :         {
    2555           0 :             if (nPos == 1)
    2556           0 :                 return false;       // $#REF!.AB42 or $#REF!42 or $#REF!#REF!
    2557           0 :             c = rName[nPos-2];              // before $#REF!
    2558             :         }
    2559           0 :         sal_Unicode c2 = nPos+5 < rName.getLength() ? rName[nPos+5] : 0;     // after #REF!
    2560           0 :         switch (c)
    2561             :         {
    2562             :             case '.':
    2563           0 :                 if ('$' == c2 || '#' == c2 || ('0' <= c2 && c2 <= '9'))
    2564           0 :                     return false;   // sheet.#REF!42 or sheet.#REF!#REF!
    2565           0 :                 break;
    2566             :             case ':':
    2567           0 :                 if (mnPredetectedReference > 1 &&
    2568           0 :                         ('.' == c2 || '$' == c2 || '#' == c2 ||
    2569           0 :                          ('0' <= c2 && c2 <= '9')))
    2570           0 :                     return false;   // :#REF!.AB42 or :#REF!42 or :#REF!#REF!
    2571           0 :                 break;
    2572             :             default:
    2573           0 :                 if (comphelper::string::isalphaAscii(c) &&
    2574           0 :                         ((mnPredetectedReference > 1 && ':' == c2) || 0 == c2))
    2575           0 :                     return false;   // AB#REF!: or AB#REF!
    2576             :         }
    2577             :     }
    2578           0 :     switch (mnPredetectedReference)
    2579             :     {
    2580             :         case 1:
    2581           0 :             return IsSingleReference( rName);
    2582             :         case 2:
    2583           0 :             return IsDoubleReference( rName);
    2584             :     }
    2585           0 :     return false;
    2586             : }
    2587             : 
    2588           0 : bool ScCompiler::IsDoubleReference( const OUString& rName )
    2589             : {
    2590           0 :     ScRange aRange( aPos, aPos );
    2591           0 :     const ScAddress::Details aDetails( pConv->meConv, aPos );
    2592           0 :     ScAddress::ExternalInfo aExtInfo;
    2593           0 :     sal_uInt16 nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    2594           0 :     if( nFlags & SCA_VALID )
    2595             :     {
    2596           0 :         ScRawToken aToken;
    2597             :         ScComplexRefData aRef;
    2598           0 :         aRef.InitRange( aRange );
    2599           0 :         aRef.Ref1.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
    2600           0 :         aRef.Ref1.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
    2601           0 :         aRef.Ref1.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
    2602           0 :         if ( !(nFlags & SCA_VALID_TAB) )
    2603           0 :             aRef.Ref1.SetTabDeleted( true );        // #REF!
    2604           0 :         aRef.Ref1.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
    2605           0 :         aRef.Ref2.SetColRel( (nFlags & SCA_COL2_ABSOLUTE) == 0 );
    2606           0 :         aRef.Ref2.SetRowRel( (nFlags & SCA_ROW2_ABSOLUTE) == 0 );
    2607           0 :         aRef.Ref2.SetTabRel( (nFlags & SCA_TAB2_ABSOLUTE) == 0 );
    2608           0 :         if ( !(nFlags & SCA_VALID_TAB2) )
    2609           0 :             aRef.Ref2.SetTabDeleted( true );        // #REF!
    2610           0 :         aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
    2611           0 :         aRef.SetRange(aRange, aPos);
    2612           0 :         if (aExtInfo.mbExternal)
    2613             :         {
    2614           0 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2615           0 :             const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
    2616             :             aToken.SetExternalDoubleRef(
    2617           0 :                 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
    2618           0 :             maExternalFiles.push_back(aExtInfo.mnFileId);
    2619             :         }
    2620             :         else
    2621             :         {
    2622           0 :             aToken.SetDoubleReference(aRef);
    2623             :         }
    2624           0 :         pRawToken = aToken.Clone();
    2625             :     }
    2626             : 
    2627           0 :     return ( nFlags & SCA_VALID ) != 0;
    2628             : }
    2629             : 
    2630           0 : bool ScCompiler::IsSingleReference( const OUString& rName )
    2631             : {
    2632           0 :     ScAddress aAddr( aPos );
    2633           0 :     const ScAddress::Details aDetails( pConv->meConv, aPos );
    2634           0 :     ScAddress::ExternalInfo aExtInfo;
    2635           0 :     sal_uInt16 nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    2636             :     // Something must be valid in order to recognize Sheet1.blah or blah.a1
    2637             :     // as a (wrong) reference.
    2638           0 :     if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) )
    2639             :     {
    2640           0 :         ScRawToken aToken;
    2641             :         ScSingleRefData aRef;
    2642           0 :         aRef.InitAddress( aAddr );
    2643           0 :         aRef.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
    2644           0 :         aRef.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
    2645           0 :         aRef.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
    2646           0 :         aRef.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
    2647             :         // the reference is really invalid
    2648           0 :         if( !( nFlags & SCA_VALID ) )
    2649             :         {
    2650           0 :             if( !( nFlags & SCA_VALID_COL ) )
    2651           0 :                 aRef.SetColDeleted(true);
    2652           0 :             if( !( nFlags & SCA_VALID_ROW ) )
    2653           0 :                 aRef.SetRowDeleted(true);
    2654           0 :             if( !( nFlags & SCA_VALID_TAB ) )
    2655           0 :                 aRef.SetTabDeleted(true);
    2656           0 :             nFlags |= SCA_VALID;
    2657             :         }
    2658           0 :         aRef.SetAddress(aAddr, aPos);
    2659             : 
    2660           0 :         if (aExtInfo.mbExternal)
    2661             :         {
    2662           0 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2663           0 :             const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
    2664             :             aToken.SetExternalSingleRef(
    2665           0 :                 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
    2666           0 :             maExternalFiles.push_back(aExtInfo.mnFileId);
    2667             :         }
    2668             :         else
    2669           0 :             aToken.SetSingleReference(aRef);
    2670           0 :         pRawToken = aToken.Clone();
    2671             :     }
    2672             : 
    2673           0 :     return ( nFlags & SCA_VALID ) != 0;
    2674             : }
    2675             : 
    2676           0 : bool ScCompiler::IsReference( const OUString& rName )
    2677             : {
    2678             :     // Has to be called before IsValue
    2679           0 :     sal_Unicode ch1 = rName[0];
    2680           0 :     sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' :
    2681           0 :         ScGlobal::pLocaleData->getNumDecimalSep()[0] );
    2682           0 :     if ( ch1 == cDecSep )
    2683           0 :         return false;
    2684             :     // Who was that imbecile introducing '.' as the sheet name separator!?!
    2685           0 :     if ( rtl::isAsciiDigit( ch1 ) )
    2686             :     {
    2687             :         // Numerical sheet name is valid.
    2688             :         // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01
    2689             :         // Don't create a #REF! of values. But also do not bail out on
    2690             :         // something like 3:3, meaning entire row 3.
    2691             :         do
    2692             :         {
    2693           0 :             const sal_Int32 nPos = ScGlobal::FindUnquoted( rName, '.');
    2694           0 :             if ( nPos == -1 )
    2695             :             {
    2696           0 :                 if (ScGlobal::FindUnquoted( rName, ':') != -1)
    2697           0 :                     break;      // may be 3:3, continue as usual
    2698           0 :                 return false;
    2699             :             }
    2700           0 :             sal_Unicode const * const pTabSep = rName.getStr() + nPos;
    2701           0 :             sal_Unicode ch2 = pTabSep[1];   // maybe a column identifier
    2702           0 :             if ( !(ch2 == '$' || rtl::isAsciiAlpha( ch2 )) )
    2703           0 :                 return false;
    2704           0 :             if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e')   // E + - digit
    2705           0 :                     && (GetCharTableFlags( pTabSep[2], pTabSep[1] ) & SC_COMPILER_C_VALUE_EXP) )
    2706             :             {   // #91053#
    2707             :                 // If it is an 1.E2 expression check if "1" is an existent sheet
    2708             :                 // name. If so, a desired value 1.E2 would have to be entered as
    2709             :                 // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to
    2710             :                 // require numerical sheet names always being entered quoted, which
    2711             :                 // is not desirable (too many 1999, 2000, 2001 sheets in use).
    2712             :                 // Furthermore, XML files created with versions prior to SRC640e
    2713             :                 // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes()
    2714             :                 // and would produce wrong formulas if the conditions here are met.
    2715             :                 // If you can live with these restrictions you may remove the
    2716             :                 // check and return an unconditional FALSE.
    2717           0 :                 OUString aTabName( rName.copy( 0, nPos ) );
    2718             :                 SCTAB nTab;
    2719           0 :                 if ( !pDoc->GetTable( aTabName, nTab ) )
    2720           0 :                     return false;
    2721             :                 // If sheet "1" exists and the expression is 1.E+2 continue as
    2722             :                 // usual, the ScRange/ScAddress parser will take care of it.
    2723             :             }
    2724             :         } while(false);
    2725             :     }
    2726             : 
    2727           0 :     if (IsSingleReference( rName))
    2728           0 :         return true;
    2729             : 
    2730             :     // Though the range operator is handled explicitly, when encountering
    2731             :     // something like Sheet1.A:A we will have to treat it as one entity if it
    2732             :     // doesn't pass as single cell reference.
    2733           0 :     if (mnRangeOpPosInSymbol > 0)   // ":foo" would be nonsense
    2734             :     {
    2735           0 :         if (IsDoubleReference( rName))
    2736           0 :             return true;
    2737             :         // Now try with a symbol up to the range operator, rewind source
    2738             :         // position.
    2739           0 :         sal_Int32 nLen = mnRangeOpPosInSymbol;
    2740           0 :         while (cSymbol[++nLen])
    2741             :             ;
    2742           0 :         cSymbol[mnRangeOpPosInSymbol] = 0;
    2743           0 :         nSrcPos -= (nLen - mnRangeOpPosInSymbol);
    2744           0 :         mnRangeOpPosInSymbol = -1;
    2745           0 :         mbRewind = true;
    2746           0 :         return true;    // end all checks
    2747             :     }
    2748             :     else
    2749             :     {
    2750             :         // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness,
    2751             :         // mnRangeOpPosInSymbol did not catch the range operator as it is
    2752             :         // within a quoted name.
    2753           0 :         switch (pConv->meConv)
    2754             :         {
    2755             :             case FormulaGrammar::CONV_XL_A1:
    2756             :             case FormulaGrammar::CONV_XL_R1C1:
    2757             :             case FormulaGrammar::CONV_XL_OOX:
    2758           0 :                 if (rName[0] == '\'' && IsDoubleReference( rName))
    2759           0 :                     return true;
    2760           0 :                 break;
    2761             :             default:
    2762             :                 ;   // nothing
    2763             :         }
    2764             :     }
    2765           0 :     return false;
    2766             : }
    2767             : 
    2768           0 : bool ScCompiler::IsMacro( const OUString& rName )
    2769             : {
    2770             : #ifdef DISABLE_SCRIPTING
    2771             :     (void) rName;
    2772             : 
    2773             :     return false;
    2774             : #else
    2775             : 
    2776             :     // Calling SfxObjectShell::GetBasic() may result in all sort of things
    2777             :     // including obtaining the model and deep down in
    2778             :     // SfxBaseModel::getDocumentStorage() acquiring the SolarMutex, which when
    2779             :     // formulas are compiled from a threaded import may result in a deadlock.
    2780             :     // Check first if we actually could acquire it and if not bail out.
    2781             :     /* FIXME: yes, but how ... */
    2782           0 :     comphelper::SolarMutex& rSolarMutex = Application::GetSolarMutex();
    2783           0 :     if (!rSolarMutex.tryToAcquire())
    2784             :     {
    2785             :         SAL_WARN( "sc.core", "ScCompiler::IsMacro - SolarMutex would deadlock, not obtaining Basic");
    2786           0 :         return false;   // bad luck
    2787             :     }
    2788             : 
    2789           0 :     OUString aName( rName);
    2790           0 :     StarBASIC* pObj = 0;
    2791           0 :     SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
    2792             : 
    2793           0 :     SfxApplication* pSfxApp = SFX_APP();
    2794             : 
    2795             :     try
    2796             :     {
    2797           0 :         if( pDocSh )//XXX
    2798           0 :             pObj = pDocSh->GetBasic();
    2799             :         else
    2800           0 :             pObj = pSfxApp->GetBasic();
    2801             :     }
    2802           0 :     catch (...)
    2803             :     {
    2804           0 :         return false;
    2805             :     }
    2806             : 
    2807             :     // ODFF recommends to store user-defined functions prefixed with "USER.",
    2808             :     // use only unprefixed name if encountered. BASIC doesn't allow '.' in a
    2809             :     // function name so a function "USER.FOO" could not exist, and macro check
    2810             :     // is assigned the lowest priority in function name check.
    2811           0 :     if (FormulaGrammar::isODFF( GetGrammar()) && aName.startsWithIgnoreAsciiCase("USER."))
    2812           0 :         aName = aName.copy(5);
    2813             : 
    2814           0 :     SbxMethod* pMeth = (SbxMethod*) pObj->Find( aName, SbxCLASS_METHOD );
    2815           0 :     if( !pMeth )
    2816             :     {
    2817           0 :         rSolarMutex.release();
    2818           0 :         return false;
    2819             :     }
    2820             :     // It really should be a BASIC function!
    2821           0 :     if( pMeth->GetType() == SbxVOID
    2822           0 :      || ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
    2823           0 :      || !pMeth->ISA(SbMethod) )
    2824             :     {
    2825           0 :         rSolarMutex.release();
    2826           0 :         return false;
    2827             :     }
    2828           0 :     ScRawToken aToken;
    2829           0 :     aToken.SetExternal( aName.getStr() );
    2830           0 :     aToken.eOp = ocMacro;
    2831           0 :     pRawToken = aToken.Clone();
    2832           0 :     rSolarMutex.release();
    2833           0 :     return true;
    2834             : #endif
    2835             : }
    2836             : 
    2837           0 : bool ScCompiler::IsNamedRange( const OUString& rUpperName )
    2838             : {
    2839             :     // IsNamedRange is called only from NextNewToken, with an upper-case string
    2840             : 
    2841             :     // try local names first
    2842           0 :     bool bGlobal = false;
    2843           0 :     ScRangeName* pRangeName = pDoc->GetRangeName(aPos.Tab());
    2844           0 :     const ScRangeData* pData = NULL;
    2845           0 :     if (pRangeName)
    2846           0 :         pData = pRangeName->findByUpperName(rUpperName);
    2847           0 :     if (!pData)
    2848             :     {
    2849           0 :         pRangeName = pDoc->GetRangeName();
    2850           0 :         if (pRangeName)
    2851           0 :             pData = pRangeName->findByUpperName(rUpperName);
    2852           0 :         if (pData)
    2853           0 :             bGlobal = true;
    2854             :     }
    2855             : 
    2856           0 :     if (pData)
    2857             :     {
    2858           0 :         ScRawToken aToken;
    2859           0 :         aToken.SetName(bGlobal, pData->GetIndex());
    2860           0 :         pRawToken = aToken.Clone();
    2861           0 :         return true;
    2862             :     }
    2863             :     else
    2864           0 :         return false;
    2865             : }
    2866             : 
    2867           0 : bool ScCompiler::IsExternalNamedRange( const OUString& rSymbol )
    2868             : {
    2869             :     /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc)
    2870             :      * correctly parses external named references in OOo, as required per RFE
    2871             :      * #i3740#, just that we can't store them in ODF yet. We will need an OASIS
    2872             :      * spec first. Until then don't pretend to support external names that
    2873             :      * wouldn't survive a save and reload cycle, return false instead. */
    2874             : 
    2875           0 :     if (!pConv)
    2876           0 :         return false;
    2877             : 
    2878           0 :     OUString aFile, aName;
    2879           0 :     if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks))
    2880           0 :         return false;
    2881             : 
    2882           0 :     ScRawToken aToken;
    2883           0 :     if (aFile.getLength() > MAXSTRLEN || aName.getLength() > MAXSTRLEN)
    2884           0 :         return false;
    2885             : 
    2886           0 :     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2887           0 :     OUString aTmp = aFile;
    2888           0 :     pRefMgr->convertToAbsName(aTmp);
    2889           0 :     aFile = aTmp;
    2890           0 :     sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile);
    2891           0 :     if (!pRefMgr->isValidRangeName(nFileId, aName))
    2892             :         // range name doesn't exist in the source document.
    2893           0 :         return false;
    2894             : 
    2895           0 :     const OUString* pRealName = pRefMgr->getRealRangeName(nFileId, aName);
    2896           0 :     aToken.SetExternalName(nFileId, pRealName ? *pRealName : OUString(aTmp));
    2897           0 :     pRawToken = aToken.Clone();
    2898           0 :     maExternalFiles.push_back(nFileId);
    2899           0 :     return true;
    2900             : }
    2901             : 
    2902           0 : bool ScCompiler::IsDBRange( const OUString& rName )
    2903             : {
    2904           0 :     if (rName.equalsAscii("[]"))
    2905             :     {
    2906           0 :         if (pRawToken && pRawToken->GetOpCode() == ocDBArea)
    2907             :         {
    2908             :             // In OOXML, a database range is named Table1[], Table2[] etc.
    2909             :             // Skip the [] part if the previous token is a valid db range.
    2910           0 :             ScRawToken aToken;
    2911           0 :             aToken.eOp = ocSkip;
    2912           0 :             pRawToken = aToken.Clone();
    2913           0 :             return true;
    2914             :         }
    2915             :     }
    2916           0 :     ScDBCollection::NamedDBs& rDBs = pDoc->GetDBCollection()->getNamedDBs();
    2917           0 :     const ScDBData* p = rDBs.findByUpperName(rName);
    2918           0 :     if (!p)
    2919           0 :         return false;
    2920             : 
    2921           0 :     ScRawToken aToken;
    2922           0 :     aToken.SetName(true, p->GetIndex()); // DB range is always global.
    2923           0 :     aToken.eOp = ocDBArea;
    2924           0 :     pRawToken = aToken.Clone();
    2925           0 :     return true;
    2926             : }
    2927             : 
    2928           0 : bool ScCompiler::IsColRowName( const OUString& rName )
    2929             : {
    2930           0 :     bool bInList = false;
    2931           0 :     bool bFound = false;
    2932             :     ScSingleRefData aRef;
    2933           0 :     OUString aName( rName );
    2934           0 :     DeQuote( aName );
    2935           0 :     SCTAB nThisTab = aPos.Tab();
    2936           0 :     for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- )
    2937             :     {   // first check ranges on this sheet, in case of duplicated names
    2938           0 :         for ( short jRow=0; jRow<2 && !bInList; jRow++ )
    2939             :         {
    2940             :             ScRangePairList* pRL;
    2941           0 :             if ( !jRow )
    2942           0 :                 pRL = pDoc->GetColNameRanges();
    2943             :             else
    2944           0 :                 pRL = pDoc->GetRowNameRanges();
    2945           0 :             for ( size_t iPair = 0, nPairs = pRL->size(); iPair < nPairs && !bInList; ++iPair )
    2946             :             {
    2947           0 :                 ScRangePair* pR = (*pRL)[iPair];
    2948           0 :                 const ScRange& rNameRange = pR->GetRange(0);
    2949           0 :                 if ( jThisTab && !(rNameRange.aStart.Tab() <= nThisTab &&
    2950           0 :                         nThisTab <= rNameRange.aEnd.Tab()) )
    2951           0 :                     continue;   // for
    2952           0 :                 ScCellIterator aIter( pDoc, rNameRange );
    2953           0 :                 for (bool bHas = aIter.first(); bHas && !bInList; bHas = aIter.next())
    2954             :                 {
    2955             :                     // Don't crash if cell (via CompileNameFormula) encounters
    2956             :                     // a formula cell without code and
    2957             :                     // HasStringData/Interpret/Compile is executed and all that
    2958             :                     // recursive..
    2959             :                     // Furthermore, *this* cell won't be touched, since no RPN exists yet.
    2960           0 :                     CellType eType = aIter.getType();
    2961           0 :                     bool bOk = false;
    2962           0 :                     if (eType == CELLTYPE_FORMULA)
    2963             :                     {
    2964           0 :                         ScFormulaCell* pFC = aIter.getFormulaCell();
    2965           0 :                         bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    2966             :                     }
    2967             :                     else
    2968           0 :                         bOk = true;
    2969             : 
    2970           0 :                     if (bOk && aIter.hasString())
    2971             :                     {
    2972           0 :                         OUString aStr = aIter.getString();
    2973           0 :                         if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
    2974             :                         {
    2975           0 :                             aRef.InitFlags();
    2976           0 :                             if ( !jRow )
    2977           0 :                                 aRef.SetColRel( true );     // ColName
    2978             :                             else
    2979           0 :                                 aRef.SetRowRel( true );     // RowName
    2980           0 :                             aRef.SetAddress(aIter.GetPos(), aPos);
    2981           0 :                             bInList = bFound = true;
    2982           0 :                         }
    2983             :                     }
    2984             :                 }
    2985           0 :             }
    2986             :         }
    2987             :     }
    2988           0 :     if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
    2989             :     {   // search in current sheet
    2990           0 :         long nDistance = 0, nMax = 0;
    2991           0 :         long nMyCol = (long) aPos.Col();
    2992           0 :         long nMyRow = (long) aPos.Row();
    2993           0 :         bool bTwo = false;
    2994           0 :         ScAddress aOne( 0, 0, aPos.Tab() );
    2995           0 :         ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() );
    2996             : 
    2997           0 :         ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache();
    2998           0 :         if ( pNameCache )
    2999             :         {
    3000             :             //  use GetNameOccurrences to collect all positions of aName on the sheet
    3001             :             //  (only once), similar to the outer part of the loop in the "else" branch.
    3002             : 
    3003           0 :             const ScAutoNameAddresses& rAddresses = pNameCache->GetNameOccurrences( aName, aPos.Tab() );
    3004             : 
    3005             :             //  Loop through the found positions, similar to the inner part of the loop in the "else" branch.
    3006             :             //  The order of addresses in the vector is the same as from ScCellIterator.
    3007             : 
    3008           0 :             ScAutoNameAddresses::const_iterator aEnd(rAddresses.end());
    3009           0 :             for ( ScAutoNameAddresses::const_iterator aAdrIter(rAddresses.begin()); aAdrIter != aEnd; ++aAdrIter )
    3010             :             {
    3011           0 :                 ScAddress aAddress( *aAdrIter );        // cell address with an equal string
    3012             : 
    3013           0 :                 if ( bFound )
    3014             :                 {   // stop if everything else is further away
    3015           0 :                     if ( nMax < (long)aAddress.Col() )
    3016           0 :                         break;      // aIter
    3017             :                 }
    3018           0 :                 if ( aAddress != aPos )
    3019             :                 {
    3020             :                     // same treatment as in isEqual case below
    3021             : 
    3022           0 :                     SCCOL nCol = aAddress.Col();
    3023           0 :                     SCROW nRow = aAddress.Row();
    3024           0 :                     long nC = nMyCol - nCol;
    3025           0 :                     long nR = nMyRow - nRow;
    3026           0 :                     if ( bFound )
    3027             :                     {
    3028           0 :                         long nD = nC * nC + nR * nR;
    3029           0 :                         if ( nD < nDistance )
    3030             :                         {
    3031           0 :                             if ( nC < 0 || nR < 0 )
    3032             :                             {   // right or below
    3033           0 :                                 bTwo = true;
    3034           0 :                                 aTwo.Set( nCol, nRow, aAddress.Tab() );
    3035           0 :                                 nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3036           0 :                                 nDistance = nD;
    3037             :                             }
    3038           0 :                             else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
    3039             :                             {
    3040             :                                 // upper left, only if not further up than the
    3041             :                                 // current entry and nMyRow is below (CellIter
    3042             :                                 // runs column-wise)
    3043           0 :                                 bTwo = false;
    3044           0 :                                 aOne.Set( nCol, nRow, aAddress.Tab() );
    3045           0 :                                 nMax = std::max( nMyCol + nC, nMyRow + nR );
    3046           0 :                                 nDistance = nD;
    3047             :                             }
    3048             :                         }
    3049             :                     }
    3050             :                     else
    3051             :                     {
    3052           0 :                         aOne.Set( nCol, nRow, aAddress.Tab() );
    3053           0 :                         nDistance = nC * nC + nR * nR;
    3054           0 :                         nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3055             : 
    3056             :                     }
    3057           0 :                     bFound = true;
    3058             :                 }
    3059             :             }
    3060             :         }
    3061             :         else
    3062             :         {
    3063           0 :             ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) );
    3064           0 :             for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
    3065             :             {
    3066           0 :                 if ( bFound )
    3067             :                 {   // stop if everything else is further away
    3068           0 :                     if ( nMax < (long)aIter.GetPos().Col() )
    3069           0 :                         break;      // aIter
    3070             :                 }
    3071           0 :                 CellType eType = aIter.getType();
    3072           0 :                 bool bOk = false;
    3073           0 :                 if (eType == CELLTYPE_FORMULA)
    3074             :                 {
    3075           0 :                     ScFormulaCell* pFC = aIter.getFormulaCell();
    3076           0 :                     bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    3077             :                 }
    3078             :                 else
    3079           0 :                     bOk = true;
    3080             : 
    3081           0 :                 if (bOk && aIter.hasString())
    3082             :                 {
    3083           0 :                     OUString aStr = aIter.getString();
    3084           0 :                     if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
    3085             :                     {
    3086           0 :                         SCCOL nCol = aIter.GetPos().Col();
    3087           0 :                         SCROW nRow = aIter.GetPos().Row();
    3088           0 :                         long nC = nMyCol - nCol;
    3089           0 :                         long nR = nMyRow - nRow;
    3090           0 :                         if ( bFound )
    3091             :                         {
    3092           0 :                             long nD = nC * nC + nR * nR;
    3093           0 :                             if ( nD < nDistance )
    3094             :                             {
    3095           0 :                                 if ( nC < 0 || nR < 0 )
    3096             :                                 {   // right or below
    3097           0 :                                     bTwo = true;
    3098           0 :                                     aTwo.Set( nCol, nRow, aIter.GetPos().Tab() );
    3099           0 :                                     nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3100           0 :                                     nDistance = nD;
    3101             :                                 }
    3102           0 :                                 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
    3103             :                                 {
    3104             :                                     // upper left, only if not further up than the
    3105             :                                     // current entry and nMyRow is below (CellIter
    3106             :                                     // runs column-wise)
    3107           0 :                                     bTwo = false;
    3108           0 :                                     aOne.Set( nCol, nRow, aIter.GetPos().Tab() );
    3109           0 :                                     nMax = std::max( nMyCol + nC, nMyRow + nR );
    3110           0 :                                     nDistance = nD;
    3111             :                                 }
    3112             :                             }
    3113             :                         }
    3114             :                         else
    3115             :                         {
    3116           0 :                             aOne.Set( nCol, nRow, aIter.GetPos().Tab() );
    3117           0 :                             nDistance = nC * nC + nR * nR;
    3118           0 :                             nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3119             :                         }
    3120           0 :                         bFound = true;
    3121           0 :                     }
    3122             :                 }
    3123           0 :             }
    3124             :         }
    3125             : 
    3126           0 :         if ( bFound )
    3127             :         {
    3128           0 :             ScAddress aAdr;
    3129           0 :             if ( bTwo )
    3130             :             {
    3131           0 :                 if ( nMyCol >= (long)aOne.Col() && nMyRow >= (long)aOne.Row() )
    3132           0 :                     aAdr = aOne;        // upper left takes precedence
    3133             :                 else
    3134             :                 {
    3135           0 :                     if ( nMyCol < (long)aOne.Col() )
    3136             :                     {   // two to the right
    3137           0 :                         if ( nMyRow >= (long)aTwo.Row() )
    3138           0 :                             aAdr = aTwo;        // directly right
    3139             :                         else
    3140           0 :                             aAdr = aOne;
    3141             :                     }
    3142             :                     else
    3143             :                     {   // two below or below and right, take the nearest
    3144           0 :                         long nC1 = nMyCol - aOne.Col();
    3145           0 :                         long nR1 = nMyRow - aOne.Row();
    3146           0 :                         long nC2 = nMyCol - aTwo.Col();
    3147           0 :                         long nR2 = nMyRow - aTwo.Row();
    3148           0 :                         if ( nC1 * nC1 + nR1 * nR1 <= nC2 * nC2 + nR2 * nR2 )
    3149           0 :                             aAdr = aOne;
    3150             :                         else
    3151           0 :                             aAdr = aTwo;
    3152             :                     }
    3153             :                 }
    3154             :             }
    3155             :             else
    3156           0 :                 aAdr = aOne;
    3157           0 :             aRef.InitAddress( aAdr );
    3158           0 :             if ( (aAdr.Row() != MAXROW && pDoc->HasStringData(
    3159           0 :                     aAdr.Col(), aAdr.Row() + 1, aAdr.Tab()))
    3160           0 :               || (aAdr.Row() != 0 && pDoc->HasStringData(
    3161           0 :                     aAdr.Col(), aAdr.Row() - 1, aAdr.Tab())))
    3162           0 :                 aRef.SetRowRel( true );     // RowName
    3163             :             else
    3164           0 :                 aRef.SetColRel( true );     // ColName
    3165           0 :             aRef.SetAddress(aAdr, aPos);
    3166             :         }
    3167             :     }
    3168           0 :     if ( bFound )
    3169             :     {
    3170           0 :         ScRawToken aToken;
    3171           0 :         aToken.SetSingleReference( aRef );
    3172           0 :         aToken.eOp = ocColRowName;
    3173           0 :         pRawToken = aToken.Clone();
    3174           0 :         return true;
    3175             :     }
    3176             :     else
    3177           0 :         return false;
    3178             : }
    3179             : 
    3180           0 : bool ScCompiler::IsBoolean( const OUString& rName )
    3181             : {
    3182           0 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) );
    3183           0 :     if( iLook != mxSymbols->getHashMap()->end() &&
    3184           0 :         ((*iLook).second == ocTrue ||
    3185           0 :          (*iLook).second == ocFalse) )
    3186             :     {
    3187           0 :         ScRawToken aToken;
    3188           0 :         aToken.SetOpCode( (*iLook).second );
    3189           0 :         pRawToken = aToken.Clone();
    3190           0 :         return true;
    3191             :     }
    3192             :     else
    3193           0 :         return false;
    3194             : }
    3195             : 
    3196           0 : bool ScCompiler::IsErrorConstant( const OUString& rName ) const
    3197             : {
    3198           0 :     sal_uInt16 nError = GetErrorConstant( rName);
    3199           0 :     if (nError)
    3200             :     {
    3201           0 :         ScRawToken aToken;
    3202           0 :         aToken.SetErrorConstant( nError);
    3203           0 :         pRawToken = aToken.Clone();
    3204           0 :         return true;
    3205             :     }
    3206             :     else
    3207           0 :         return false;
    3208             : }
    3209             : 
    3210           0 : void ScCompiler::AutoCorrectParsedSymbol()
    3211             : {
    3212           0 :     sal_Int32 nPos = aCorrectedSymbol.getLength();
    3213           0 :     if ( nPos )
    3214             :     {
    3215           0 :         nPos--;
    3216           0 :         const sal_Unicode cQuote = '\"';
    3217           0 :         const sal_Unicode cx = 'x';
    3218           0 :         const sal_Unicode cX = 'X';
    3219           0 :         sal_Unicode c1 = aCorrectedSymbol[0];
    3220           0 :         sal_Unicode c2 = aCorrectedSymbol[nPos];
    3221           0 :         sal_Unicode c2p = nPos > 0 ? aCorrectedSymbol[nPos-1] : 0;
    3222           0 :         if ( c1 == cQuote && c2 != cQuote  )
    3223             :         {   // "...
    3224             :             // What's not a word doesn't belong to it.
    3225             :             // Don't be pedantic: c < 128 should be sufficient here.
    3226           0 :             while ( nPos && ((aCorrectedSymbol[nPos] < 128) &&
    3227           0 :                     ((GetCharTableFlags(aCorrectedSymbol[nPos], aCorrectedSymbol[nPos-1]) &
    3228             :                     (SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_DONTCARE)) == 0)) )
    3229           0 :                 nPos--;
    3230           0 :             if ( nPos == MAXSTRLEN - 2 )
    3231           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAt( nPos, 1, OUString(cQuote) );   // '"' the 255th character
    3232             :             else
    3233           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAt( nPos + 1, 0, OUString(cQuote) );
    3234           0 :             bCorrected = true;
    3235             :         }
    3236           0 :         else if ( c1 != cQuote && c2 == cQuote )
    3237             :         {   // ..."
    3238           0 :             aCorrectedSymbol = OUString(cQuote) + aCorrectedSymbol;
    3239           0 :             bCorrected = true;
    3240             :         }
    3241           0 :         else if ( nPos == 0 && (c1 == cx || c1 == cX) )
    3242             :         {   // x => *
    3243           0 :             aCorrectedSymbol = mxSymbols->getSymbol(ocMul);
    3244           0 :             bCorrected = true;
    3245             :         }
    3246           0 :         else if ( (GetCharTableFlags( c1, 0 ) & SC_COMPILER_C_CHAR_VALUE)
    3247           0 :                && (GetCharTableFlags( c2, c2p ) & SC_COMPILER_C_CHAR_VALUE) )
    3248             :         {
    3249           0 :             if ( comphelper::string::getTokenCount(aCorrectedSymbol, cx) > 1 )
    3250             :             {   // x => *
    3251           0 :                 sal_Unicode c = mxSymbols->getSymbolChar(ocMul);
    3252           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAll(OUString(cx), OUString(c));
    3253           0 :                 bCorrected = true;
    3254             :             }
    3255           0 :             if ( comphelper::string::getTokenCount(aCorrectedSymbol, cX) > 1 )
    3256             :             {   // X => *
    3257           0 :                 sal_Unicode c = mxSymbols->getSymbolChar(ocMul);
    3258           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAll(OUString(cX), OUString(c));
    3259           0 :                 bCorrected = true;
    3260             :             }
    3261             :         }
    3262             :         else
    3263             :         {
    3264           0 :             OUString aSymbol( aCorrectedSymbol );
    3265           0 :             OUString aDoc;
    3266             :             sal_Int32 nPosition;
    3267           0 :             if ( aSymbol[0] == '\''
    3268           0 :               && ((nPosition = aSymbol.indexOf( "'#" )) != -1) )
    3269             :             {   // Split off 'Doc'#, may be d:\... or whatever
    3270           0 :                 aDoc = aSymbol.copy(0, nPosition + 2);
    3271           0 :                 aSymbol = aSymbol.copy(nPosition + 2);
    3272             :             }
    3273           0 :             sal_Int32 nRefs = comphelper::string::getTokenCount(aSymbol, ':');
    3274             :             bool bColons;
    3275           0 :             if ( nRefs > 2 )
    3276             :             {   // duplicated or too many ':'? B:2::C10 => B2:C10
    3277           0 :                 bColons = true;
    3278           0 :                 sal_Int32 nIndex = 0;
    3279           0 :                 OUString aTmp1( aSymbol.getToken( 0, ':', nIndex ) );
    3280           0 :                 sal_Int32 nLen1 = aTmp1.getLength();
    3281           0 :                 OUString aSym, aTmp2;
    3282             :                 bool bLastAlp, bNextNum;
    3283           0 :                 bLastAlp = bNextNum = true;
    3284           0 :                 sal_Int32 nStrip = 0;
    3285           0 :                 sal_Int32 nCount = nRefs;
    3286           0 :                 for ( sal_Int32 j=1; j<nCount; j++ )
    3287             :                 {
    3288           0 :                     aTmp2 = aSymbol.getToken( 0, ':', nIndex );
    3289           0 :                     sal_Int32 nLen2 = aTmp2.getLength();
    3290           0 :                     if ( nLen1 || nLen2 )
    3291             :                     {
    3292           0 :                         if ( nLen1 )
    3293             :                         {
    3294           0 :                             aSym += aTmp1;
    3295           0 :                             bLastAlp = CharClass::isAsciiAlpha( aTmp1 );
    3296             :                         }
    3297           0 :                         if ( nLen2 )
    3298             :                         {
    3299           0 :                             bNextNum = CharClass::isAsciiNumeric( aTmp2 );
    3300           0 :                             if ( bLastAlp == bNextNum && nStrip < 1 )
    3301             :                             {
    3302             :                                 // Must be alternating number/string, only
    3303             :                                 // strip within a reference.
    3304           0 :                                 nRefs--;
    3305           0 :                                 nStrip++;
    3306             :                             }
    3307             :                             else
    3308             :                             {
    3309           0 :                                 if ( !aSym.isEmpty() && !aSym.endsWith(":"))
    3310           0 :                                     aSym += ":";
    3311           0 :                                 nStrip = 0;
    3312             :                             }
    3313           0 :                             bLastAlp = !bNextNum;
    3314             :                         }
    3315             :                         else
    3316             :                         {   // ::
    3317           0 :                             nRefs--;
    3318           0 :                             if ( nLen1 )
    3319             :                             {   // B10::C10 ? append ':' on next round
    3320           0 :                                 if ( !bLastAlp && !CharClass::isAsciiNumeric( aTmp1 ) )
    3321           0 :                                     nStrip++;
    3322             :                             }
    3323           0 :                             bNextNum = !bLastAlp;
    3324             :                         }
    3325           0 :                         aTmp1 = aTmp2;
    3326           0 :                         nLen1 = nLen2;
    3327             :                     }
    3328             :                     else
    3329           0 :                         nRefs--;
    3330             :                 }
    3331           0 :                 aSymbol = aSym;
    3332           0 :                 aSymbol += aTmp1;
    3333             :             }
    3334             :             else
    3335           0 :                 bColons = false;
    3336           0 :             if ( nRefs && nRefs <= 2 )
    3337             :             {   // reference twisted? 4A => A4 etc.
    3338           0 :                 OUString aTab[2], aRef[2];
    3339           0 :                 const ScAddress::Details aDetails( pConv->meConv, aPos );
    3340           0 :                 if ( nRefs == 2 )
    3341             :                 {
    3342           0 :                     aRef[0] = aSymbol.getToken( 0, ':' );
    3343           0 :                     aRef[1] = aSymbol.getToken( 1, ':' );
    3344             :                 }
    3345             :                 else
    3346           0 :                     aRef[0] = aSymbol;
    3347             : 
    3348           0 :                 bool bChanged = false;
    3349           0 :                 bool bOk = true;
    3350           0 :                 sal_uInt16 nMask = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW;
    3351           0 :                 for ( int j=0; j<nRefs; j++ )
    3352             :                 {
    3353           0 :                     sal_Int32 nTmp = 0;
    3354           0 :                     sal_Int32 nDotPos = -1;
    3355           0 :                     while ( (nTmp = aRef[j].indexOf( '.', nTmp )) != -1 )
    3356           0 :                         nDotPos = nTmp++;      // the last one counts
    3357           0 :                     if ( nDotPos != -1 )
    3358             :                     {
    3359           0 :                         aTab[j] = aRef[j].copy( 0, nDotPos + 1 );  // with '.'
    3360           0 :                         aRef[j] = aRef[j].copy( nDotPos + 1 );
    3361             :                     }
    3362           0 :                     OUString aOld( aRef[j] );
    3363           0 :                     OUString aStr2;
    3364           0 :                     const sal_Unicode* p = aRef[j].getStr();
    3365           0 :                     while ( *p && CharClass::isAsciiNumeric( OUString(*p) ) )
    3366           0 :                         aStr2 += OUString(*p++);
    3367           0 :                     aRef[j] = OUString( p );
    3368           0 :                     aRef[j] += aStr2;
    3369           0 :                     if ( bColons || aRef[j] != aOld )
    3370             :                     {
    3371           0 :                         bChanged = true;
    3372           0 :                         ScAddress aAdr;
    3373           0 :                         bOk &= ((aAdr.Parse( aRef[j], pDoc, aDetails ) & nMask) == nMask);
    3374             :                     }
    3375           0 :                 }
    3376           0 :                 if ( bChanged && bOk )
    3377             :                 {
    3378           0 :                     aCorrectedSymbol = aDoc;
    3379           0 :                     aCorrectedSymbol += aTab[0];
    3380           0 :                     aCorrectedSymbol += aRef[0];
    3381           0 :                     if ( nRefs == 2 )
    3382             :                     {
    3383           0 :                         aCorrectedSymbol += ":";
    3384           0 :                         aCorrectedSymbol += aTab[1];
    3385           0 :                         aCorrectedSymbol += aRef[1];
    3386             :                     }
    3387           0 :                     bCorrected = true;
    3388           0 :                 }
    3389           0 :             }
    3390             :         }
    3391             :     }
    3392           0 : }
    3393             : 
    3394           0 : static inline bool lcl_UpperAsciiOrI18n( OUString& rUpper, const OUString& rOrg, FormulaGrammar::Grammar eGrammar )
    3395             : {
    3396           0 :     if (FormulaGrammar::isODFF( eGrammar ))
    3397             :     {
    3398             :         // ODFF has a defined set of English function names, avoid i18n
    3399             :         // overhead.
    3400           0 :         rUpper = rOrg.toAsciiUpperCase();
    3401           0 :         return true;
    3402             :     }
    3403             :     else
    3404             :     {
    3405           0 :         rUpper = ScGlobal::pCharClass->uppercase(rOrg);
    3406           0 :         return false;
    3407             :     }
    3408             : }
    3409             : 
    3410           0 : bool ScCompiler::NextNewToken( bool bInArray )
    3411             : {
    3412           0 :     bool bAllowBooleans = bInArray;
    3413           0 :     sal_Int32 nSpaces = NextSymbol(bInArray);
    3414             : 
    3415           0 :     if (!cSymbol[0])
    3416           0 :         return false;
    3417             : 
    3418           0 :     if( nSpaces )
    3419             :     {
    3420           0 :         ScRawToken aToken;
    3421           0 :         aToken.SetOpCode( ocSpaces );
    3422           0 :         aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces );
    3423           0 :         if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) )
    3424             :         {
    3425           0 :             SetError(errCodeOverflow);
    3426           0 :             return false;
    3427           0 :         }
    3428             :     }
    3429             : 
    3430             :     // Short cut for references when reading ODF to speedup things.
    3431           0 :     if (mnPredetectedReference)
    3432             :     {
    3433           0 :         OUString aStr( cSymbol);
    3434           0 :         if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr))
    3435             :         {
    3436             :             /* TODO: it would be nice to generate a #REF! error here, which
    3437             :              * would need an ocBad token with additional error value.
    3438             :              * FormulaErrorToken wouldn't do because we want to preserve the
    3439             :              * original string containing partial valid address
    3440             :              * information if not ODFF (in that case it was already handled).
    3441             :              * */
    3442           0 :             ScRawToken aToken;
    3443           0 :             svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aStr);
    3444           0 :             aToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3445           0 :             aToken.NewOpCode( ocBad );
    3446           0 :             pRawToken = aToken.Clone();
    3447             :         }
    3448           0 :         return true;
    3449             :     }
    3450             : 
    3451           0 :     if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 &&
    3452           0 :             !bAutoCorrect )
    3453             :     {   // special case to speed up broken [$]#REF documents
    3454             :         /* FIXME: ISERROR(#REF!) would be valid and true and the formula to
    3455             :          * be processed as usual. That would need some special treatment,
    3456             :          * also in NextSymbol() because of possible combinations of
    3457             :          * #REF!.#REF!#REF! parts. In case of reading ODF that is all
    3458             :          * handled by IsPredetectedReference(), this case here remains for
    3459             :          * manual/API input. */
    3460           0 :         OUString aBad( aFormula.copy( nSrcPos-1 ) );
    3461           0 :         eLastOp = pArr->AddBad( aBad )->GetOpCode();
    3462           0 :         return false;
    3463             :     }
    3464             : 
    3465           0 :     if( IsString() )
    3466           0 :         return true;
    3467             : 
    3468             :     bool bMayBeFuncName;
    3469             :     bool bAsciiNonAlnum;    // operators, separators, ...
    3470           0 :     if ( cSymbol[0] < 128 )
    3471             :     {
    3472           0 :         bMayBeFuncName = rtl::isAsciiAlpha( cSymbol[0] );
    3473           0 :         if (!bMayBeFuncName && (cSymbol[0] == '_' && cSymbol[1] == '_') )
    3474             :         {
    3475           0 :             SvtMiscOptions aOpt;
    3476           0 :             bMayBeFuncName = aOpt.IsExperimentalMode();
    3477             :         }
    3478             : 
    3479           0 :         bAsciiNonAlnum = !bMayBeFuncName && !rtl::isAsciiDigit( cSymbol[0] );
    3480             :     }
    3481             :     else
    3482             :     {
    3483           0 :         OUString aTmpStr( cSymbol[0] );
    3484           0 :         bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 );
    3485           0 :         bAsciiNonAlnum = false;
    3486             :     }
    3487           0 :     if ( bMayBeFuncName )
    3488             :     {
    3489             :         // a function name must be followed by a parenthesis
    3490           0 :         const sal_Unicode* p = aFormula.getStr() + nSrcPos;
    3491           0 :         while( *p == ' ' )
    3492           0 :             p++;
    3493           0 :         bMayBeFuncName = ( *p == '(' );
    3494             :     }
    3495             : 
    3496             :     // Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
    3497             :     // IsReference().
    3498             : 
    3499           0 :     OUString aUpper;
    3500             : 
    3501           0 :     do
    3502             :     {
    3503           0 :         mbRewind = false;
    3504           0 :         const OUString aOrg( cSymbol );
    3505             : 
    3506           0 :         if (bAsciiNonAlnum)
    3507             :         {
    3508           0 :             if (cSymbol[0] == '#')
    3509             :             {
    3510             :                 // This can be only an error constant, if any.
    3511           0 :                 lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3512           0 :                 if (IsErrorConstant( aUpper))
    3513           0 :                     return true;
    3514           0 :                 break;  // do; create ocBad token or set error.
    3515             :             }
    3516           0 :             if (IsOpCode( aOrg, bInArray ))
    3517           0 :                 return true;
    3518             :         }
    3519             : 
    3520           0 :         aUpper = "";
    3521           0 :         bool bAsciiUpper = false;
    3522           0 :         if (bMayBeFuncName)
    3523             :         {
    3524           0 :             bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3525           0 :             if (IsOpCode( aUpper, bInArray ))
    3526           0 :                 return true;
    3527             :         }
    3528             : 
    3529             :         // Column 'DM' ("Deutsche Mark", German currency) couldn't be
    3530             :         // referred => IsReference() before IsValue().
    3531             :         // Preserve case of file names in external references.
    3532           0 :         if (IsReference( aOrg ))
    3533             :         {
    3534           0 :             if (mbRewind)   // Range operator, but no direct reference.
    3535           0 :                 continue;   // do; up to range operator.
    3536             :             // If a syntactically correct reference was recognized but invalid
    3537             :             // e.g. because of non-existing sheet name => entire reference
    3538             :             // ocBad to preserve input instead of #REF!.A1
    3539           0 :             if (!pRawToken->IsValidReference())
    3540             :             {
    3541           0 :                 aUpper = aOrg;          // ensure for ocBad
    3542           0 :                 break;                  // do; create ocBad token or set error.
    3543             :             }
    3544           0 :             return true;
    3545             :         }
    3546             : 
    3547           0 :         if (aUpper.isEmpty())
    3548           0 :             bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3549             : 
    3550             :         // IsBoolean() before IsValue() to catch inline bools without the kludge
    3551             :         //    for inline arrays.
    3552           0 :         if (bAllowBooleans && IsBoolean( aUpper ))
    3553           0 :             return true;
    3554             : 
    3555           0 :         if (IsValue( aUpper ))
    3556           0 :             return true;
    3557             : 
    3558             :         // User defined names and such do need i18n upper also in ODF.
    3559           0 :         if (bAsciiUpper)
    3560           0 :             aUpper = ScGlobal::pCharClass->uppercase( aOrg );
    3561             : 
    3562           0 :         if (IsNamedRange( aUpper ))
    3563           0 :             return true;
    3564             :         // Preserve case of file names in external references.
    3565           0 :         if (IsExternalNamedRange( aOrg ))
    3566           0 :             return true;
    3567           0 :         if (IsDBRange( aUpper ))
    3568           0 :             return true;
    3569             :         // If followed by '(' (with or without space inbetween) it can not be a
    3570             :         // column/row label. Prevent arbitrary content detection.
    3571           0 :         if (!bMayBeFuncName && IsColRowName( aUpper ))
    3572           0 :             return true;
    3573           0 :         if (bMayBeFuncName && IsMacro( aUpper ))
    3574           0 :             return true;
    3575           0 :         if (bMayBeFuncName && IsOpCode2( aUpper ))
    3576           0 :             return true;
    3577             : 
    3578             :     } while (mbRewind);
    3579             : 
    3580           0 :     if ( meExtendedErrorDetection != EXTENDED_ERROR_DETECTION_NONE )
    3581             :     {
    3582             :         // set an error
    3583           0 :         SetError( errNoName );
    3584           0 :         if (meExtendedErrorDetection == EXTENDED_ERROR_DETECTION_NAME_BREAK)
    3585           0 :             return false;   // end compilation
    3586             :     }
    3587             : 
    3588             :     // Provide single token information and continue. Do not set an error, that
    3589             :     // would prematurely end compilation. Simple unknown names are handled by
    3590             :     // the interpreter.
    3591           0 :     aUpper = ScGlobal::pCharClass->lowercase( aUpper );
    3592           0 :     ScRawToken aToken;
    3593           0 :     svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aUpper);
    3594           0 :     aToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3595           0 :     aToken.NewOpCode( ocBad );
    3596           0 :     pRawToken = aToken.Clone();
    3597           0 :     if ( bAutoCorrect )
    3598           0 :         AutoCorrectParsedSymbol();
    3599           0 :     return true;
    3600             : }
    3601             : 
    3602           0 : void ScCompiler::CreateStringFromXMLTokenArray( OUString& rFormula, OUString& rFormulaNmsp )
    3603             : {
    3604           0 :     bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL;
    3605           0 :     sal_uInt16 nExpectedCount = bExternal ? 2 : 1;
    3606             :     OSL_ENSURE( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
    3607           0 :     if( pArr->GetLen() == nExpectedCount )
    3608             :     {
    3609           0 :         FormulaToken** ppTokens = pArr->GetArray();
    3610             :         // string tokens expected, GetString() will assert if token type is wrong
    3611           0 :         rFormula = ppTokens[0]->GetString().getString();
    3612           0 :         if( bExternal )
    3613           0 :             rFormulaNmsp = ppTokens[1]->GetString().getString();
    3614             :     }
    3615           0 : }
    3616             : 
    3617             : namespace {
    3618             : 
    3619           0 : class ExternalFileInserter : std::unary_function<sal_uInt16, void>
    3620             : {
    3621             :     ScAddress maPos;
    3622             :     ScExternalRefManager& mrRefMgr;
    3623             : public:
    3624           0 :     ExternalFileInserter(const ScAddress& rPos, ScExternalRefManager& rRefMgr) :
    3625           0 :         maPos(rPos), mrRefMgr(rRefMgr) {}
    3626             : 
    3627           0 :     void operator() (sal_uInt16 nFileId) const
    3628             :     {
    3629           0 :         mrRefMgr.insertRefCell(nFileId, maPos);
    3630           0 :     }
    3631             : };
    3632             : 
    3633             : }
    3634             : 
    3635           0 : ScTokenArray* ScCompiler::CompileString( const OUString& rFormula )
    3636             : {
    3637             :     OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
    3638           0 :     if( meGrammar == FormulaGrammar::GRAM_EXTERNAL )
    3639           0 :         SetGrammar( FormulaGrammar::GRAM_PODF );
    3640             : 
    3641           0 :     ScTokenArray aArr;
    3642           0 :     pArr = &aArr;
    3643           0 :     aFormula = comphelper::string::strip(rFormula, ' ');
    3644             : 
    3645           0 :     nSrcPos = 0;
    3646           0 :     bCorrected = false;
    3647           0 :     if ( bAutoCorrect )
    3648             :     {
    3649           0 :         aCorrectedFormula = "";
    3650           0 :         aCorrectedSymbol = "";
    3651             :     }
    3652           0 :     sal_uInt8 nForced = 0;   // ==formula forces recalc even if cell is not visible
    3653           0 :     if( nSrcPos < aFormula.getLength() && aFormula[nSrcPos] == '=' )
    3654             :     {
    3655           0 :         nSrcPos++;
    3656           0 :         nForced++;
    3657           0 :         if ( bAutoCorrect )
    3658           0 :             aCorrectedFormula += "=";
    3659             :     }
    3660           0 :     if( nSrcPos < aFormula.getLength() && aFormula[nSrcPos] == '=' )
    3661             :     {
    3662           0 :         nSrcPos++;
    3663           0 :         nForced++;
    3664           0 :         if ( bAutoCorrect )
    3665           0 :             aCorrectedFormula += "=";
    3666             :     }
    3667             :     struct FunctionStack
    3668             :     {
    3669             :         OpCode  eOp;
    3670             :         short   nSep;
    3671             :     };
    3672             :     // FunctionStack only used if PODF or OOXML!
    3673           0 :     bool bPODF = FormulaGrammar::isPODF( meGrammar);
    3674           0 :     bool bOOXML = FormulaGrammar::isOOXML( meGrammar);
    3675           0 :     bool bUseFunctionStack = (bPODF || bOOXML);
    3676           0 :     const size_t nAlloc = 512;
    3677             :     FunctionStack aFuncs[ nAlloc ];
    3678           0 :     FunctionStack* pFunctionStack = (bUseFunctionStack && static_cast<size_t>(rFormula.getLength()) > nAlloc ?
    3679           0 :          new FunctionStack[rFormula.getLength()] : &aFuncs[0]);
    3680           0 :     pFunctionStack[0].eOp = ocNone;
    3681           0 :     pFunctionStack[0].nSep = 0;
    3682           0 :     size_t nFunction = 0;
    3683           0 :     short nBrackets = 0;
    3684           0 :     bool bInArray = false;
    3685           0 :     eLastOp = ocOpen;
    3686           0 :     while( NextNewToken( bInArray ) )
    3687             :     {
    3688           0 :         const OpCode eOp = pRawToken->GetOpCode();
    3689           0 :         if (eOp == ocSkip)
    3690           0 :             continue;
    3691             : 
    3692           0 :         switch (eOp)
    3693             :         {
    3694             :             case ocOpen:
    3695             :             {
    3696           0 :                 ++nBrackets;
    3697           0 :                 if (bUseFunctionStack)
    3698             :                 {
    3699           0 :                     ++nFunction;
    3700           0 :                     pFunctionStack[ nFunction ].eOp = eLastOp;
    3701           0 :                     pFunctionStack[ nFunction ].nSep = 0;
    3702             :                 }
    3703             :             }
    3704           0 :             break;
    3705             :             case ocClose:
    3706             :             {
    3707           0 :                 if( !nBrackets )
    3708             :                 {
    3709           0 :                     SetError( errPairExpected );
    3710           0 :                     if ( bAutoCorrect )
    3711             :                     {
    3712           0 :                         bCorrected = true;
    3713           0 :                         aCorrectedSymbol = "";
    3714             :                     }
    3715             :                 }
    3716             :                 else
    3717           0 :                     nBrackets--;
    3718           0 :                 if (bUseFunctionStack && nFunction)
    3719           0 :                     --nFunction;
    3720             :             }
    3721           0 :             break;
    3722             :             case ocSep:
    3723             :             {
    3724           0 :                 if (bUseFunctionStack)
    3725           0 :                     ++pFunctionStack[ nFunction ].nSep;
    3726             :             }
    3727           0 :             break;
    3728             :             case ocArrayOpen:
    3729             :             {
    3730           0 :                 if( bInArray )
    3731           0 :                     SetError( errNestedArray );
    3732             :                 else
    3733           0 :                     bInArray = true;
    3734             :                 // Don't count following column separator as parameter separator.
    3735           0 :                 if (bUseFunctionStack)
    3736             :                 {
    3737           0 :                     ++nFunction;
    3738           0 :                     pFunctionStack[ nFunction ].eOp = eOp;
    3739           0 :                     pFunctionStack[ nFunction ].nSep = 0;
    3740             :                 }
    3741             :             }
    3742           0 :             break;
    3743             :             case ocArrayClose:
    3744             :             {
    3745           0 :                 if( bInArray )
    3746             :                 {
    3747           0 :                     bInArray = false;
    3748             :                 }
    3749             :                 else
    3750             :                 {
    3751           0 :                     SetError( errPairExpected );
    3752           0 :                     if ( bAutoCorrect )
    3753             :                     {
    3754           0 :                         bCorrected = true;
    3755           0 :                         aCorrectedSymbol = "";
    3756             :                     }
    3757             :                 }
    3758           0 :                 if (bUseFunctionStack && nFunction)
    3759           0 :                     --nFunction;
    3760             :             }
    3761             :             default:
    3762           0 :             break;
    3763             :         }
    3764           0 :         if( (eLastOp == ocSep ||
    3765           0 :              eLastOp == ocArrayRowSep ||
    3766           0 :              eLastOp == ocArrayColSep ||
    3767           0 :              eLastOp == ocArrayOpen) &&
    3768           0 :             (eOp == ocSep ||
    3769           0 :              eOp == ocClose ||
    3770           0 :              eOp == ocArrayRowSep ||
    3771           0 :              eOp == ocArrayColSep ||
    3772             :              eOp == ocArrayClose) )
    3773             :         {
    3774             :             // FIXME: should we check for known functions with optional empty
    3775             :             // args so the correction dialog can do better?
    3776           0 :             if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) )
    3777             :             {
    3778           0 :                 SetError(errCodeOverflow); break;
    3779             :             }
    3780             :         }
    3781           0 :         if (bOOXML)
    3782             :         {
    3783             :             // Append a parameter for CEILING, FLOOR and WEEKNUM, all 1.0
    3784             :             // Function is already closed, parameter count is nSep+1
    3785           0 :             size_t nFunc = nFunction + 1;
    3786           0 :             if (eOp == ocClose && (
    3787           0 :                     (pFunctionStack[ nFunc ].eOp == ocCeil &&   // 3rd Excel mode
    3788           0 :                      pFunctionStack[ nFunc ].nSep == 1) ||
    3789           0 :                     (pFunctionStack[ nFunc ].eOp == ocFloor &&  // 3rd Excel mode
    3790           0 :                      pFunctionStack[ nFunc ].nSep == 1) ||
    3791           0 :                     (pFunctionStack[ nFunc ].eOp == ocWeek &&   // 2nd week start
    3792           0 :                      pFunctionStack[ nFunc ].nSep == 0)))
    3793             :             {
    3794           0 :                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) ||
    3795           0 :                         !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
    3796             :                 {
    3797           0 :                     SetError(errCodeOverflow); break;
    3798             :                 }
    3799             :             }
    3800             :         }
    3801           0 :         else if (bPODF)
    3802             :         {
    3803             :             /* TODO: for now this is the only PODF adapter. If there were more,
    3804             :              * factor this out. */
    3805             :             // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
    3806           0 :             if (eOp == ocSep &&
    3807           0 :                     pFunctionStack[ nFunction ].eOp == ocAddress &&
    3808           0 :                     pFunctionStack[ nFunction ].nSep == 3)
    3809             :             {
    3810           0 :                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) ||
    3811           0 :                         !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
    3812             :                 {
    3813           0 :                     SetError(errCodeOverflow); break;
    3814             :                 }
    3815           0 :                 ++pFunctionStack[ nFunction ].nSep;
    3816             :             }
    3817             :         }
    3818           0 :         FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( pRawToken->CreateToken());
    3819           0 :         if (!pNewToken)
    3820             :         {
    3821           0 :             SetError(errCodeOverflow); break;
    3822             :         }
    3823           0 :         else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush &&
    3824           0 :                 pNewToken->GetType() == svSingleRef)
    3825           0 :             static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos);
    3826           0 :         eLastOp = pRawToken->GetOpCode();
    3827           0 :         if ( bAutoCorrect )
    3828           0 :             aCorrectedFormula += aCorrectedSymbol;
    3829             :     }
    3830           0 :     if ( mbCloseBrackets )
    3831             :     {
    3832           0 :         if( bInArray )
    3833             :         {
    3834           0 :             FormulaByteToken aToken( ocArrayClose );
    3835           0 :             if( !pArr->AddToken( aToken ) )
    3836             :             {
    3837           0 :                 SetError(errCodeOverflow);
    3838             :             }
    3839           0 :             else if ( bAutoCorrect )
    3840           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose);
    3841             :         }
    3842             : 
    3843           0 :         FormulaByteToken aToken( ocClose );
    3844           0 :         while( nBrackets-- )
    3845             :         {
    3846           0 :             if( !pArr->AddToken( aToken ) )
    3847             :             {
    3848           0 :                 SetError(errCodeOverflow); break;
    3849             :             }
    3850           0 :             if ( bAutoCorrect )
    3851           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocClose);
    3852           0 :         }
    3853             :     }
    3854           0 :     if ( nForced >= 2 )
    3855           0 :         pArr->SetRecalcModeForced();
    3856             : 
    3857           0 :     if (pFunctionStack != &aFuncs[0])
    3858           0 :         delete [] pFunctionStack;
    3859             : 
    3860             :     // remember pArr, in case a subsequent CompileTokenArray() is executed.
    3861           0 :     ScTokenArray* pNew = new ScTokenArray( aArr );
    3862           0 :     pNew->GenHash();
    3863           0 :     pArr = pNew;
    3864             : 
    3865           0 :     if (!maExternalFiles.empty())
    3866             :     {
    3867             :         // Remove duplicates, and register all external files found in this cell.
    3868           0 :         std::sort(maExternalFiles.begin(), maExternalFiles.end());
    3869           0 :         std::vector<sal_uInt16>::iterator itEnd = std::unique(maExternalFiles.begin(), maExternalFiles.end());
    3870           0 :         std::for_each(maExternalFiles.begin(), itEnd, ExternalFileInserter(aPos, *pDoc->GetExternalRefManager()));
    3871           0 :         maExternalFiles.erase(itEnd, maExternalFiles.end());
    3872             :     }
    3873             : 
    3874           0 :     return pNew;
    3875             : }
    3876             : 
    3877           0 : ScTokenArray* ScCompiler::CompileString( const OUString& rFormula, const OUString& rFormulaNmsp )
    3878             : {
    3879             :     OSL_ENSURE( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || rFormulaNmsp.isEmpty(),
    3880             :         "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
    3881           0 :     if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try
    3882             :     {
    3883           0 :         ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool();
    3884           0 :         uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW );
    3885           0 :         table::CellAddress aReferencePos;
    3886           0 :         ScUnoConversion::FillApiAddress( aReferencePos, aPos );
    3887           0 :         uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos );
    3888           0 :         ScTokenArray aTokenArray;
    3889           0 :         if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) )
    3890             :         {
    3891             :             // remember pArr, in case a subsequent CompileTokenArray() is executed.
    3892           0 :             ScTokenArray* pNew = new ScTokenArray( aTokenArray );
    3893           0 :             pArr = pNew;
    3894           0 :             return pNew;
    3895           0 :         }
    3896             :     }
    3897           0 :     catch( uno::Exception& )
    3898             :     {
    3899             :     }
    3900             :     // no success - fallback to some internal grammar and hope the best
    3901           0 :     return CompileString( rFormula );
    3902             : }
    3903             : 
    3904           0 : ScRangeData* ScCompiler::GetRangeData( const FormulaToken& rToken ) const
    3905             : {
    3906           0 :     ScRangeData* pRangeData = NULL;
    3907           0 :     bool bGlobal = rToken.IsGlobal();
    3908           0 :     if (bGlobal)
    3909             :         // global named range.
    3910           0 :         pRangeData = pDoc->GetRangeName()->findByIndex( rToken.GetIndex());
    3911             :     else
    3912             :     {
    3913             :         // sheet local named range.
    3914           0 :         const ScRangeName* pRN = pDoc->GetRangeName( aPos.Tab());
    3915           0 :         if (pRN)
    3916           0 :             pRangeData = pRN->findByIndex( rToken.GetIndex());
    3917             :     }
    3918           0 :     return pRangeData;
    3919             : }
    3920             : 
    3921           0 : bool ScCompiler::HandleRange()
    3922             : {
    3923           0 :     const ScRangeData* pRangeData = GetRangeData( *mpToken);
    3924           0 :     if (pRangeData)
    3925             :     {
    3926           0 :         sal_uInt16 nErr = pRangeData->GetErrCode();
    3927           0 :         if( nErr )
    3928           0 :             SetError( errNoName );
    3929           0 :         else if ( !bCompileForFAP )
    3930             :         {
    3931             :             ScTokenArray* pNew;
    3932             :             // put named formula into parentheses.
    3933             :             // But only if there aren't any yet, parenthetical
    3934             :             // ocSep doesn't work, e.g. SUM((...;...))
    3935             :             // or if not directly between ocSep/parenthesis,
    3936             :             // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
    3937             :             // in short: if it isn't a self-contained expression.
    3938           0 :             FormulaToken* p1 = pArr->PeekPrevNoSpaces();
    3939           0 :             FormulaToken* p2 = pArr->PeekNextNoSpaces();
    3940           0 :             OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) );
    3941           0 :             OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) );
    3942           0 :             bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
    3943           0 :             bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose);
    3944           0 :             bool bAddPair = !(bBorder1 && bBorder2);
    3945           0 :             if ( bAddPair )
    3946             :             {
    3947           0 :                 pNew = new ScTokenArray();
    3948           0 :                 pNew->AddOpCode( ocClose );
    3949           0 :                 PushTokenArray( pNew, true );
    3950           0 :                 pNew->Reset();
    3951             :             }
    3952           0 :             pNew = pRangeData->GetCode()->Clone();
    3953           0 :             PushTokenArray( pNew, true );
    3954           0 :             if( pRangeData->HasReferences() )
    3955             :             {
    3956           0 :                 SetRelNameReference();
    3957           0 :                 MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
    3958             :             }
    3959           0 :             pNew->Reset();
    3960           0 :             if ( bAddPair )
    3961             :             {
    3962           0 :                 pNew = new ScTokenArray();
    3963           0 :                 pNew->AddOpCode( ocOpen );
    3964           0 :                 PushTokenArray( pNew, true );
    3965           0 :                 pNew->Reset();
    3966             :             }
    3967           0 :             return GetToken();
    3968             :         }
    3969             :     }
    3970             :     else
    3971           0 :         SetError(errNoName);
    3972           0 :     return true;
    3973             : }
    3974             : 
    3975           0 : bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)
    3976             : {
    3977             :     // Handle external range names.
    3978           0 :     switch (_aToken.GetType())
    3979             :     {
    3980             :         case svExternalSingleRef:
    3981             :         case svExternalDoubleRef:
    3982           0 :             pArr->IncrementRefs();
    3983           0 :         break;
    3984             :         case svExternalName:
    3985             :         {
    3986           0 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    3987           0 :             const OUString* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex());
    3988           0 :             if (!pFile)
    3989             :             {
    3990           0 :                 SetError(errNoName);
    3991           0 :                 return true;
    3992             :             }
    3993             : 
    3994           0 :             OUString aName = _aToken.GetString().getString();
    3995             :             ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens(
    3996           0 :                 _aToken.GetIndex(), aName, &aPos);
    3997             : 
    3998           0 :             if (!xNew)
    3999             :             {
    4000           0 :                 SetError(errNoName);
    4001           0 :                 return true;
    4002             :             }
    4003             : 
    4004           0 :             ScTokenArray* pNew = xNew->Clone();
    4005           0 :             PushTokenArray( pNew, true);
    4006           0 :             if (pNew->GetNextReference() != NULL)
    4007             :             {
    4008           0 :                 SetRelNameReference();
    4009           0 :                 MoveRelWrap(MAXCOL, MAXROW);
    4010             :             }
    4011           0 :             pNew->Reset();
    4012           0 :             return GetToken();
    4013             :         }
    4014             :         default:
    4015             :             OSL_FAIL("Wrong type for external reference!");
    4016           0 :             return false;
    4017             :     }
    4018           0 :     return true;
    4019             : }
    4020             : 
    4021             : template< typename T, typename S >
    4022             : static S lcl_adjval( S& n, T pos, T max, bool bRel )
    4023             : {
    4024             :     max++;
    4025             :     if( bRel )
    4026             :         n = sal::static_int_cast<S>( n + pos );
    4027             :     if( n < 0 )
    4028             :         n = sal::static_int_cast<S>( n + max );
    4029             :     else if( n >= max )
    4030             :         n = sal::static_int_cast<S>( n - max );
    4031             :     if( bRel )
    4032             :         n = sal::static_int_cast<S>( n - pos );
    4033             :     return n;
    4034             : }
    4035             : 
    4036             : // reference of named range with relative references
    4037             : 
    4038           0 : void ScCompiler::SetRelNameReference()
    4039             : {
    4040           0 :     pArr->Reset();
    4041           0 :     for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t;
    4042           0 :                   t = static_cast<ScToken*>(pArr->GetNextReference()) )
    4043             :     {
    4044           0 :         ScSingleRefData& rRef1 = t->GetSingleRef();
    4045           0 :         if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
    4046           0 :             rRef1.SetRelName( true );
    4047           0 :         if ( t->GetType() == svDoubleRef )
    4048             :         {
    4049           0 :             ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
    4050           0 :             if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
    4051           0 :                 rRef2.SetRelName( true );
    4052             :         }
    4053             :     }
    4054           0 : }
    4055             : 
    4056             : // Wrap-adjust relative references of a RangeName to current position,
    4057             : // don't call for other token arrays!
    4058           0 : void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
    4059             : {
    4060           0 :     pArr->Reset();
    4061           0 :     for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t;
    4062           0 :                   t = static_cast<ScToken*>(pArr->GetNextReference()) )
    4063             :     {
    4064           0 :         if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
    4065           0 :             ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() );
    4066             :         else
    4067           0 :             ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, t->GetDoubleRef() );
    4068             :     }
    4069           0 : }
    4070             : 
    4071             : // Wrap-adjust relative references of a RangeName to current position,
    4072             : // don't call for other token arrays!
    4073           0 : void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos,
    4074             :                               SCCOL nMaxCol, SCROW nMaxRow )
    4075             : {
    4076           0 :     rArr.Reset();
    4077           0 :     for( ScToken* t = static_cast<ScToken*>(rArr.GetNextReference()); t;
    4078           0 :                   t = static_cast<ScToken*>(rArr.GetNextReference()) )
    4079             :     {
    4080           0 :         if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
    4081           0 :             ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() );
    4082             :         else
    4083           0 :             ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, t->GetDoubleRef() );
    4084             :     }
    4085           0 : }
    4086             : 
    4087           0 : bool ScCompiler::IsCharFlagAllConventions(
    4088             :     OUString const & rStr, sal_Int32 nPos, sal_uLong nFlags, bool bTestLetterNumeric )
    4089             : {
    4090           0 :     sal_Unicode c = rStr[ nPos ];
    4091           0 :     sal_Unicode cLast = nPos > 0 ? rStr[ nPos-1 ] : 0;
    4092           0 :     if (c < 128)
    4093             :     {
    4094           0 :         for ( int nConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
    4095             :                 ++nConv < formula::FormulaGrammar::CONV_LAST; )
    4096             :         {
    4097           0 :             if (pConventions[nConv] &&
    4098           0 :                     ((pConventions[nConv]->getCharTableFlags(c, cLast) & nFlags) != nFlags))
    4099           0 :                 return false;
    4100             :             // convention not known => assume valid
    4101             :         }
    4102           0 :         return true;
    4103             :     }
    4104           0 :     else if (bTestLetterNumeric)
    4105           0 :         return ScGlobal::pCharClass->isLetterNumeric( rStr, nPos );
    4106             :     else
    4107           0 :         return false;
    4108             : }
    4109             : 
    4110           0 : void ScCompiler::CreateStringFromExternal(OUStringBuffer& rBuffer, FormulaToken* pTokenP) const
    4111             : {
    4112           0 :     FormulaToken* t = pTokenP;
    4113           0 :     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    4114           0 :     const OUString* pFileName = pRefMgr->getExternalFileName(t->GetIndex());
    4115           0 :     if (!pFileName)
    4116           0 :         return;
    4117             : 
    4118           0 :     switch (t->GetType())
    4119             :     {
    4120             :         case svExternalName:
    4121           0 :             rBuffer.append(pConv->makeExternalNameStr(*pFileName, t->GetString().getString()));
    4122           0 :         break;
    4123             :         case svExternalSingleRef:
    4124             :             pConv->makeExternalRefStr(
    4125           0 :                    rBuffer, GetPos(), *pFileName, t->GetString().getString(),
    4126           0 :                    static_cast<ScToken*>(t)->GetSingleRef());
    4127           0 :         break;
    4128             :         case svExternalDoubleRef:
    4129             :         {
    4130           0 :             vector<OUString> aTabNames;
    4131           0 :             pRefMgr->getAllCachedTableNames(t->GetIndex(), aTabNames);
    4132           0 :             if (aTabNames.empty())
    4133           0 :                 return;
    4134             : 
    4135             :             pConv->makeExternalRefStr(
    4136           0 :                 rBuffer, GetPos(), *pFileName, aTabNames, t->GetString().getString(),
    4137           0 :                 static_cast<ScToken*>(t)->GetDoubleRef());
    4138             :         }
    4139           0 :         break;
    4140             :         default:
    4141             :             // warning, not error, otherwise we may end up with a never
    4142             :             // ending message box loop if this was the cursor cell to be redrawn.
    4143             :             OSL_FAIL("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
    4144             :     }
    4145             : }
    4146             : 
    4147           0 : void ScCompiler::CreateStringFromMatrix(
    4148             :     OUStringBuffer& rBuffer, FormulaToken* pTokenP) const
    4149             : {
    4150           0 :     const ScMatrix* pMatrix = static_cast<ScToken*>(pTokenP)->GetMatrix();
    4151             :     SCSIZE nC, nMaxC, nR, nMaxR;
    4152             : 
    4153           0 :     pMatrix->GetDimensions( nMaxC, nMaxR);
    4154             : 
    4155           0 :     rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) );
    4156           0 :     for( nR = 0 ; nR < nMaxR ; nR++)
    4157             :     {
    4158           0 :         if( nR > 0)
    4159             :         {
    4160           0 :             rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) );
    4161             :         }
    4162             : 
    4163           0 :         for( nC = 0 ; nC < nMaxC ; nC++)
    4164             :         {
    4165           0 :             if( nC > 0)
    4166             :             {
    4167           0 :                 rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) );
    4168             :             }
    4169             : 
    4170           0 :             if( pMatrix->IsValue( nC, nR ) )
    4171             :             {
    4172           0 :                 if (pMatrix->IsBoolean(nC, nR))
    4173           0 :                     AppendBoolean(rBuffer, pMatrix->GetDouble(nC, nR) != 0.0);
    4174             :                 else
    4175             :                 {
    4176           0 :                     sal_uInt16 nErr = pMatrix->GetError(nC, nR);
    4177           0 :                     if (nErr)
    4178           0 :                         rBuffer.append(ScGlobal::GetErrorString(nErr));
    4179             :                     else
    4180           0 :                         AppendDouble(rBuffer, pMatrix->GetDouble(nC, nR));
    4181             :                 }
    4182             :             }
    4183           0 :             else if( pMatrix->IsEmpty( nC, nR ) )
    4184             :                 ;
    4185           0 :             else if( pMatrix->IsString( nC, nR ) )
    4186           0 :                 AppendString( rBuffer, pMatrix->GetString(nC, nR).getString() );
    4187             :         }
    4188             :     }
    4189           0 :     rBuffer.append( mxSymbols->getSymbol(ocArrayClose) );
    4190           0 : }
    4191             : 
    4192           0 : void ScCompiler::CreateStringFromSingleRef(OUStringBuffer& rBuffer,FormulaToken* _pTokenP) const
    4193             : {
    4194           0 :     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
    4195           0 :     const OpCode eOp = _pTokenP->GetOpCode();
    4196           0 :     const ScSingleRefData& rRef = static_cast<const ScToken*>(_pTokenP)->GetSingleRef();
    4197             :     ScComplexRefData aRef;
    4198           0 :     aRef.Ref1 = aRef.Ref2 = rRef;
    4199           0 :     if ( eOp == ocColRowName )
    4200             :     {
    4201           0 :         ScAddress aAbs = rRef.toAbs(aPos);
    4202           0 :         if (pDoc->HasStringData(aAbs.Col(), aAbs.Row(), aAbs.Tab()))
    4203             :         {
    4204           0 :             OUString aStr = pDoc->GetString(aAbs);
    4205           0 :             EnQuote( aStr );
    4206           0 :             rBuffer.append(aStr);
    4207             :         }
    4208             :         else
    4209             :         {
    4210           0 :             rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
    4211           0 :             pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef, maTabNames, aRef, true);
    4212             :         }
    4213             :     }
    4214             :     else
    4215           0 :         pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef, maTabNames, aRef, true);
    4216           0 : }
    4217             : 
    4218           0 : void ScCompiler::CreateStringFromDoubleRef(OUStringBuffer& rBuffer,FormulaToken* _pTokenP) const
    4219             : {
    4220           0 :     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
    4221           0 :     pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef, maTabNames, static_cast<ScToken*>(_pTokenP)->GetDoubleRef(), false);
    4222           0 : }
    4223             : 
    4224           0 : void ScCompiler::CreateStringFromIndex(OUStringBuffer& rBuffer,FormulaToken* _pTokenP) const
    4225             : {
    4226           0 :     const OpCode eOp = _pTokenP->GetOpCode();
    4227           0 :     OUStringBuffer aBuffer;
    4228           0 :     switch ( eOp )
    4229             :     {
    4230             :         case ocName:
    4231             :         {
    4232           0 :             const ScRangeData* pData = GetRangeData( *_pTokenP);
    4233           0 :             if (pData)
    4234           0 :                 aBuffer.append(pData->GetName());
    4235             :         }
    4236           0 :         break;
    4237             :         case ocDBArea:
    4238             :         {
    4239           0 :             const ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(_pTokenP->GetIndex());
    4240           0 :             if (pDBData)
    4241           0 :                 aBuffer.append(pDBData->GetName());
    4242             :         }
    4243           0 :         break;
    4244             :         default:
    4245             :             ;   // nothing
    4246             :     }
    4247           0 :     if ( !aBuffer.isEmpty() )
    4248           0 :         rBuffer.append(aBuffer.makeStringAndClear());
    4249             :     else
    4250           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
    4251           0 : }
    4252             : 
    4253           0 : void ScCompiler::LocalizeString( OUString& rName ) const
    4254             : {
    4255           0 :     ScGlobal::GetAddInCollection()->LocalizeString( rName );
    4256           0 : }
    4257             : 
    4258             : // Put quotes around string if non-alphanumeric characters are contained,
    4259             : // quote characters contained within are escaped by '\\'.
    4260           0 : bool ScCompiler::EnQuote( OUString& rStr )
    4261             : {
    4262           0 :     sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.getLength() );
    4263           0 :     if ( !CharClass::isNumericType( nType )
    4264           0 :             && CharClass::isAlphaNumericType( nType ) )
    4265           0 :         return false;
    4266             : 
    4267           0 :     sal_Int32 nPos = 0;
    4268           0 :     while ( (nPos = rStr.indexOf( '\'', nPos)) != -1 )
    4269             :     {
    4270           0 :         rStr = rStr.replaceAt( nPos, 0, "\\" );
    4271           0 :         nPos += 2;
    4272             :     }
    4273           0 :     rStr = "'" + rStr + "'";
    4274           0 :     return true;
    4275             : }
    4276             : 
    4277           0 : sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const
    4278             : {
    4279           0 :     return pConv->getSpecialSymbol(eType);
    4280             : }
    4281             : 
    4282           0 : void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const
    4283             : {
    4284             :     // All known AddIn functions.
    4285           0 :     sheet::FormulaOpCodeMapEntry aEntry;
    4286           0 :     aEntry.Token.OpCode = ocExternal;
    4287             : 
    4288           0 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
    4289           0 :     const long nCount = pColl->GetFuncCount();
    4290           0 :     for (long i=0; i < nCount; ++i)
    4291             :     {
    4292           0 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
    4293           0 :         if (pFuncData)
    4294             :         {
    4295           0 :             if ( _bIsEnglish )
    4296             :             {
    4297           0 :                 OUString aName;
    4298           0 :                 if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
    4299           0 :                     aEntry.Name = aName;
    4300             :                 else
    4301           0 :                     aEntry.Name = pFuncData->GetUpperName();
    4302             :             }
    4303             :             else
    4304           0 :                 aEntry.Name = pFuncData->GetUpperLocal();
    4305           0 :             aEntry.Token.Data <<= OUString( pFuncData->GetOriginalName());
    4306           0 :             _rVec.push_back( aEntry);
    4307             :         }
    4308           0 :     }
    4309             :     // FIXME: what about those old non-UNO AddIns?
    4310           0 : }
    4311             : 
    4312           0 : bool ScCompiler::HandleSingleRef()
    4313             : {
    4314           0 :     ScSingleRefData& rRef = static_cast<ScToken*>(mpToken.get())->GetSingleRef();
    4315           0 :     ScAddress aAbs = rRef.toAbs(aPos);
    4316           0 :     if (!ValidAddress(aAbs))
    4317             :     {
    4318           0 :         SetError( errNoRef );
    4319           0 :         return true;
    4320             :     }
    4321           0 :     SCCOL nCol = aAbs.Col();
    4322           0 :     SCROW nRow = aAbs.Row();
    4323           0 :     SCTAB nTab = aAbs.Tab();
    4324           0 :     ScAddress aLook = aAbs;
    4325           0 :     bool bColName = rRef.IsColRel();
    4326           0 :     SCCOL nMyCol = aPos.Col();
    4327           0 :     SCROW nMyRow = aPos.Row();
    4328           0 :     bool bInList = false;
    4329           0 :     bool bValidName = false;
    4330             :     ScRangePairList* pRL = (bColName ?
    4331           0 :         pDoc->GetColNameRanges() : pDoc->GetRowNameRanges());
    4332           0 :     ScRange aRange;
    4333           0 :     for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4334             :     {
    4335           0 :         ScRangePair* pR = (*pRL)[i];
    4336           0 :         if ( pR->GetRange(0).In( aLook ) )
    4337             :         {
    4338           0 :             bInList = bValidName = true;
    4339           0 :             aRange = pR->GetRange(1);
    4340           0 :             if ( bColName )
    4341             :             {
    4342           0 :                 aRange.aStart.SetCol( nCol );
    4343           0 :                 aRange.aEnd.SetCol( nCol );
    4344             :             }
    4345             :             else
    4346             :             {
    4347           0 :                 aRange.aStart.SetRow( nRow );
    4348           0 :                 aRange.aEnd.SetRow( nRow );
    4349             :             }
    4350           0 :             break;  // for
    4351             :         }
    4352             :     }
    4353           0 :     if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
    4354             :     {   // automagically or created by copying and NamePos isn't in list
    4355           0 :         ScRefCellValue aCell;
    4356           0 :         aCell.assign(*pDoc, aLook);
    4357           0 :         bool bString = aCell.hasString();
    4358           0 :         if (!bString && aCell.isEmpty())
    4359           0 :             bString = true;     // empty cell is ok
    4360           0 :         if ( bString )
    4361             :         {   //! coresponds with ScInterpreter::ScColRowNameAuto()
    4362           0 :             bValidName = true;
    4363           0 :             if ( bColName )
    4364             :             {   // ColName
    4365           0 :                 SCROW nStartRow = nRow + 1;
    4366           0 :                 if ( nStartRow > MAXROW )
    4367           0 :                     nStartRow = MAXROW;
    4368           0 :                 SCROW nMaxRow = MAXROW;
    4369           0 :                 if ( nMyCol == nCol )
    4370             :                 {   // formula cell in same column
    4371           0 :                     if ( nMyRow == nStartRow )
    4372             :                     {   // take remainder under name cell
    4373           0 :                         nStartRow++;
    4374           0 :                         if ( nStartRow > MAXROW )
    4375           0 :                             nStartRow = MAXROW;
    4376             :                     }
    4377           0 :                     else if ( nMyRow > nStartRow )
    4378             :                     {   // from name cell down to formula cell
    4379           0 :                         nMaxRow = nMyRow - 1;
    4380             :                     }
    4381             :                 }
    4382           0 :                 for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4383             :                 {   // next defined ColNameRange below limits row
    4384           0 :                     ScRangePair* pR = (*pRL)[i];
    4385           0 :                     const ScRange& rRange = pR->GetRange(1);
    4386           0 :                     if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() )
    4387             :                     {   // identical column range
    4388           0 :                         SCROW nTmp = rRange.aStart.Row();
    4389           0 :                         if ( nStartRow < nTmp && nTmp <= nMaxRow )
    4390           0 :                             nMaxRow = nTmp - 1;
    4391             :                     }
    4392             :                 }
    4393           0 :                 aRange.aStart.Set( nCol, nStartRow, nTab );
    4394           0 :                 aRange.aEnd.Set( nCol, nMaxRow, nTab );
    4395             :             }
    4396             :             else
    4397             :             {   // RowName
    4398           0 :                 SCCOL nStartCol = nCol + 1;
    4399           0 :                 if ( nStartCol > MAXCOL )
    4400           0 :                     nStartCol = MAXCOL;
    4401           0 :                 SCCOL nMaxCol = MAXCOL;
    4402           0 :                 if ( nMyRow == nRow )
    4403             :                 {   // formula cell in same row
    4404           0 :                     if ( nMyCol == nStartCol )
    4405             :                     {   // take remainder right from name cell
    4406           0 :                         nStartCol++;
    4407           0 :                         if ( nStartCol > MAXCOL )
    4408           0 :                             nStartCol = MAXCOL;
    4409             :                     }
    4410           0 :                     else if ( nMyCol > nStartCol )
    4411             :                     {   // from name cell right to formula cell
    4412           0 :                         nMaxCol = nMyCol - 1;
    4413             :                     }
    4414             :                 }
    4415           0 :                 for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4416             :                 {   // next defined RowNameRange to the right limits column
    4417           0 :                     ScRangePair* pR = (*pRL)[i];
    4418           0 :                     const ScRange& rRange = pR->GetRange(1);
    4419           0 :                     if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() )
    4420             :                     {   // identical row range
    4421           0 :                         SCCOL nTmp = rRange.aStart.Col();
    4422           0 :                         if ( nStartCol < nTmp && nTmp <= nMaxCol )
    4423           0 :                             nMaxCol = nTmp - 1;
    4424             :                     }
    4425             :                 }
    4426           0 :                 aRange.aStart.Set( nStartCol, nRow, nTab );
    4427           0 :                 aRange.aEnd.Set( nMaxCol, nRow, nTab );
    4428             :             }
    4429           0 :         }
    4430             :     }
    4431           0 :     if ( bValidName )
    4432             :     {
    4433             :         // And now the magic to distinguish between a range and a single
    4434             :         // cell thereof, which is picked position-dependent of the formula
    4435             :         // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
    4436             :         // SingleRef matching the column/row of the formula cell is
    4437             :         // generated. A ocColRowName or ocIntersect as a neighbor results
    4438             :         // in a range. Special case: if label is valid for a single cell, a
    4439             :         // position independent SingleRef is generated.
    4440           0 :         bool bSingle = (aRange.aStart == aRange.aEnd);
    4441             :         bool bFound;
    4442           0 :         if ( bSingle )
    4443           0 :             bFound = true;
    4444             :         else
    4445             :         {
    4446           0 :             FormulaToken* p1 = pArr->PeekPrevNoSpaces();
    4447           0 :             FormulaToken* p2 = pArr->PeekNextNoSpaces();
    4448             :             // begin/end of a formula => single
    4449           0 :             OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd );
    4450           0 :             OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd );
    4451           0 :             if ( eOp1 != ocColRowName && eOp1 != ocIntersect
    4452           0 :                 && eOp2 != ocColRowName && eOp2 != ocIntersect )
    4453             :             {
    4454           0 :                 if (    (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) ||
    4455           0 :                         (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP))
    4456           0 :                     bSingle = true;
    4457             :             }
    4458           0 :             if ( bSingle )
    4459             :             {   // column and/or row must match range
    4460           0 :                 if ( bColName )
    4461             :                 {
    4462           0 :                     bFound = (aRange.aStart.Row() <= nMyRow
    4463           0 :                         && nMyRow <= aRange.aEnd.Row());
    4464           0 :                     if ( bFound )
    4465           0 :                         aRange.aStart.SetRow( nMyRow );
    4466             :                 }
    4467             :                 else
    4468             :                 {
    4469           0 :                     bFound = (aRange.aStart.Col() <= nMyCol
    4470           0 :                         && nMyCol <= aRange.aEnd.Col());
    4471           0 :                     if ( bFound )
    4472           0 :                         aRange.aStart.SetCol( nMyCol );
    4473             :                 }
    4474             :             }
    4475             :             else
    4476           0 :                 bFound = true;
    4477             :         }
    4478           0 :         if ( !bFound )
    4479           0 :             SetError(errNoRef);
    4480           0 :         else if ( !bCompileForFAP )
    4481             :         {
    4482           0 :             ScTokenArray* pNew = new ScTokenArray();
    4483           0 :             if ( bSingle )
    4484             :             {
    4485             :                 ScSingleRefData aRefData;
    4486           0 :                 aRefData.InitAddress( aRange.aStart );
    4487           0 :                 if ( bColName )
    4488           0 :                     aRefData.SetColRel( true );
    4489             :                 else
    4490           0 :                     aRefData.SetRowRel( true );
    4491           0 :                 aRefData.SetAddress(aRange.aStart, aPos);
    4492           0 :                 pNew->AddSingleReference( aRefData );
    4493             :             }
    4494             :             else
    4495             :             {
    4496             :                 ScComplexRefData aRefData;
    4497           0 :                 aRefData.InitRange( aRange );
    4498           0 :                 if ( bColName )
    4499             :                 {
    4500           0 :                     aRefData.Ref1.SetColRel( true );
    4501           0 :                     aRefData.Ref2.SetColRel( true );
    4502             :                 }
    4503             :                 else
    4504             :                 {
    4505           0 :                     aRefData.Ref1.SetRowRel( true );
    4506           0 :                     aRefData.Ref2.SetRowRel( true );
    4507             :                 }
    4508           0 :                 aRefData.SetRange(aRange, aPos);
    4509           0 :                 if ( bInList )
    4510           0 :                     pNew->AddDoubleReference( aRefData );
    4511             :                 else
    4512             :                 {   // automagically
    4513           0 :                     pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) );
    4514             :                 }
    4515             :             }
    4516           0 :             PushTokenArray( pNew, true );
    4517           0 :             pNew->Reset();
    4518           0 :             return GetToken();
    4519             :         }
    4520             :     }
    4521             :     else
    4522           0 :         SetError(errNoName);
    4523           0 :     return true;
    4524             : }
    4525             : 
    4526           0 : bool ScCompiler::HandleDbData()
    4527             : {
    4528           0 :     ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(mpToken->GetIndex());
    4529           0 :     if ( !pDBData )
    4530           0 :         SetError(errNoName);
    4531           0 :     else if ( !bCompileForFAP )
    4532             :     {
    4533             :         ScComplexRefData aRefData;
    4534           0 :         aRefData.InitFlags();
    4535           0 :         ScRange aRange;
    4536           0 :         pDBData->GetArea(aRange);
    4537           0 :         aRange.aEnd.SetTab(aRange.aStart.Tab());
    4538           0 :         aRefData.SetRange(aRange, aPos);
    4539           0 :         ScTokenArray* pNew = new ScTokenArray();
    4540           0 :         pNew->AddDoubleReference( aRefData );
    4541           0 :         PushTokenArray( pNew, true );
    4542           0 :         pNew->Reset();
    4543           0 :         return GetToken();
    4544             :     }
    4545           0 :     return true;
    4546             : }
    4547             : 
    4548           0 : FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef )
    4549             : {
    4550           0 :     return ScToken::ExtendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef );
    4551             : }
    4552             : 
    4553             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10