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