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