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