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 28 : void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap,FormulaGrammar::Grammar _eGrammar ) const
109 : {
110 : size_t nSymbolOffset;
111 28 : switch( _eGrammar )
112 : {
113 : case FormulaGrammar::GRAM_PODF:
114 6 : nSymbolOffset = offsetof( AddInMap, pUpper);
115 6 : break;
116 : default:
117 : case FormulaGrammar::GRAM_ODFF:
118 16 : nSymbolOffset = offsetof( AddInMap, pODFF);
119 16 : break;
120 : case FormulaGrammar::GRAM_ENGLISH:
121 6 : nSymbolOffset = offsetof( AddInMap, pEnglish);
122 6 : break;
123 : }
124 28 : const AddInMap* pMap = GetAddInMap();
125 28 : const AddInMap* const pStop = pMap + GetAddInMapCount();
126 3080 : for ( ; pMap < pStop; ++pMap)
127 : {
128 : char const * const * ppSymbol =
129 : reinterpret_cast< char const * const * >(
130 3052 : reinterpret_cast< char const * >(pMap) + nSymbolOffset);
131 : xMap->putExternal( rtl::OUString::createFromAscii( *ppSymbol),
132 3052 : rtl::OUString::createFromAscii( pMap->pOriginal));
133 : }
134 28 : }
135 :
136 22 : void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const
137 : {
138 22 : ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
139 22 : long nCount = pColl->GetFuncCount();
140 916 : for (long i=0; i < nCount; ++i)
141 : {
142 894 : const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
143 894 : if (pFuncData)
144 654 : xMap->putExternalSoftly( pFuncData->GetUpperName(),
145 1308 : pFuncData->GetOriginalName());
146 : }
147 22 : }
148 :
149 6 : void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const
150 : {
151 6 : ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
152 6 : long nCount = pColl->GetFuncCount();
153 304 : for (long i=0; i < nCount; ++i)
154 : {
155 298 : const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
156 298 : if (pFuncData)
157 : {
158 218 : ::rtl::OUString aName;
159 218 : if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
160 218 : xMap->putExternalSoftly( aName, pFuncData->GetOriginalName());
161 : else
162 0 : xMap->putExternalSoftly( pFuncData->GetUpperName(),
163 0 : pFuncData->GetOriginalName());
164 : }
165 : }
166 6 : }
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 18 : void ScCompiler::InitCharClassEnglish()
204 : {
205 18 : ::com::sun::star::lang::Locale aLocale( "en", "US", "");
206 : pCharClassEnglish = new CharClass(
207 18 : ::comphelper::getProcessComponentContext(), LanguageTag( aLocale));
208 18 : }
209 :
210 :
211 8754 : void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
212 : {
213 : OSL_ENSURE( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED");
214 8754 : if (eGrammar == GetGrammar())
215 8808 : return; // nothing to be done
216 :
217 8700 : 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 8700 : FormulaGrammar::Grammar eMyGrammar = eGrammar;
225 8700 : const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar);
226 8700 : OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage);
227 : OSL_ENSURE( xMap, "ScCompiler::SetGrammar: unknown formula language");
228 8700 : 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 8700 : FormulaGrammar::Grammar eOldGrammar = GetGrammar();
236 : // This also sets the grammar associated with the map!
237 8700 : SetFormulaLanguage( xMap);
238 :
239 : // Override if necessary.
240 8700 : if (eMyGrammar != GetGrammar())
241 5334 : SetGrammarAndRefConvention( eMyGrammar, eOldGrammar);
242 : }
243 : }
244 :
245 8 : ScCompiler::EncodeUrlMode ScCompiler::GetEncodeUrlMode() const
246 : {
247 8 : return meEncodeUrlMode;
248 : }
249 :
250 8816 : void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap )
251 : {
252 8816 : if (xMap.get())
253 : {
254 8816 : mxSymbols = xMap;
255 8816 : if (mxSymbols->isEnglish())
256 : {
257 2088 : if (!pCharClassEnglish)
258 18 : InitCharClassEnglish();
259 2088 : pCharClass = pCharClassEnglish;
260 : }
261 : else
262 6728 : pCharClass = ScGlobal::pCharClass;
263 8816 : SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar());
264 : }
265 8816 : }
266 :
267 :
268 14150 : void ScCompiler::SetGrammarAndRefConvention(
269 : const FormulaGrammar::Grammar eNewGrammar, const FormulaGrammar::Grammar eOldGrammar )
270 : {
271 14150 : meGrammar = eNewGrammar; //! SetRefConvention needs the new grammar set!
272 14150 : FormulaGrammar::AddressConvention eConv = FormulaGrammar::extractRefConvention( meGrammar);
273 14150 : if (eConv == FormulaGrammar::CONV_UNSPECIFIED && eOldGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
274 : {
275 23556 : if (pDoc)
276 11778 : SetRefConvention( pDoc->GetAddressConvention());
277 : else
278 0 : SetRefConvention( pConvOOO_A1);
279 : }
280 : else
281 2372 : SetRefConvention( eConv );
282 14150 : }
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 170 : ScCompiler::Convention::~Convention()
293 : {
294 170 : delete [] mpCharTable;
295 170 : mpCharTable = NULL;
296 170 : }
297 :
298 170 : ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv )
299 : :
300 170 : meConv( eConv )
301 : {
302 : int i;
303 170 : sal_uLong *t= new sal_uLong [128];
304 :
305 170 : ScCompiler::pConventions[ meConv ] = this;
306 170 : mpCharTable = t;
307 :
308 21930 : for (i = 0; i < 128; i++)
309 21760 : t[i] = SC_COMPILER_C_ILLEGAL;
310 :
311 170 : /* */ t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
312 170 : /* ! */ t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
313 170 : if (FormulaGrammar::CONV_ODF == meConv)
314 34 : /* ! */ t[33] |= SC_COMPILER_C_ODF_LABEL_OP;
315 170 : /* " */ t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP;
316 170 : /* # */ t[35] = SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_CHAR_ERRCONST;
317 170 : /* $ */ t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT;
318 170 : if (FormulaGrammar::CONV_ODF == meConv)
319 34 : /* $ */ t[36] |= SC_COMPILER_C_ODF_NAME_MARKER;
320 170 : /* % */ t[37] = SC_COMPILER_C_VALUE;
321 170 : /* & */ t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
322 170 : /* ' */ t[39] = SC_COMPILER_C_NAME_SEP;
323 170 : /* ( */ t[40] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
324 170 : /* ) */ t[41] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
325 170 : /* * */ t[42] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
326 170 : /* + */ t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
327 170 : /* , */ t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE;
328 170 : /* - */ t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
329 170 : /* . */ t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
330 170 : /* / */ t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
331 :
332 1870 : for (i = 48; i < 58; i++)
333 1700 : /* 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 170 : /* : */ t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD;
336 170 : /* ; */ t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
337 170 : /* < */ t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
338 170 : /* = */ t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
339 170 : /* > */ t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
340 170 : /* ? */ t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME;
341 : /* @ */ // FREE
342 :
343 4590 : for (i = 65; i < 91; i++)
344 4420 : /* 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 170 : if (FormulaGrammar::CONV_ODF == meConv)
347 : {
348 34 : /* [ */ t[91] = SC_COMPILER_C_ODF_LBRACKET;
349 : /* \ */ // FREE
350 34 : /* ] */ t[93] = SC_COMPILER_C_ODF_RBRACKET;
351 : }
352 : else
353 : {
354 : /* [ */ // FREE
355 : /* \ */ // FREE
356 : /* ] */ // FREE
357 : }
358 170 : /* ^ */ t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
359 170 : /* _ */ 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 4590 : for (i = 97; i < 123; i++)
363 4420 : /* 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 170 : /* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open
366 170 : /* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific)
367 170 : /* } */ t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close
368 170 : /* ~ */ t[126] = SC_COMPILER_C_CHAR; // OOo specific
369 : /* 127 */ // FREE
370 :
371 170 : if( FormulaGrammar::CONV_XL_A1 == meConv || FormulaGrammar::CONV_XL_R1C1 == meConv || FormulaGrammar::CONV_XL_OOX == meConv )
372 : {
373 102 : /* */ t[32] |= SC_COMPILER_C_WORD;
374 102 : /* ! */ t[33] |= SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD;
375 102 : /* " */ t[34] |= SC_COMPILER_C_WORD;
376 102 : /* # */ t[35] &= (~SC_COMPILER_C_WORD_SEP);
377 102 : /* # */ t[35] |= SC_COMPILER_C_WORD;
378 102 : /* % */ t[37] |= SC_COMPILER_C_WORD;
379 102 : /* ' */ t[39] |= SC_COMPILER_C_WORD;
380 :
381 102 : /* % */ t[37] |= SC_COMPILER_C_WORD;
382 102 : /* & */ t[38] |= SC_COMPILER_C_WORD;
383 102 : /* ' */ t[39] |= SC_COMPILER_C_WORD;
384 102 : /* ( */ t[40] |= SC_COMPILER_C_WORD;
385 102 : /* ) */ t[41] |= SC_COMPILER_C_WORD;
386 102 : /* * */ t[42] |= SC_COMPILER_C_WORD;
387 102 : /* + */ 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 102 : /* , */ t[44] |= SC_COMPILER_C_WORD;
392 : #endif
393 102 : /* - */ t[45] |= SC_COMPILER_C_WORD;
394 :
395 102 : /* ; */ t[59] |= SC_COMPILER_C_WORD;
396 102 : /* < */ t[60] |= SC_COMPILER_C_WORD;
397 102 : /* = */ t[61] |= SC_COMPILER_C_WORD;
398 102 : /* > */ t[62] |= SC_COMPILER_C_WORD;
399 : /* ? */ // question really is not permitted in sheet name
400 102 : /* @ */ t[64] |= SC_COMPILER_C_WORD;
401 102 : /* [ */ t[91] |= SC_COMPILER_C_WORD;
402 102 : /* ] */ t[93] |= SC_COMPILER_C_WORD;
403 102 : /* { */ t[123]|= SC_COMPILER_C_WORD;
404 102 : /* | */ t[124]|= SC_COMPILER_C_WORD;
405 102 : /* } */ t[125]|= SC_COMPILER_C_WORD;
406 102 : /* ~ */ t[126]|= SC_COMPILER_C_WORD;
407 :
408 102 : if( FormulaGrammar::CONV_XL_R1C1 == meConv )
409 : {
410 34 : /* [ */ t[91] |= SC_COMPILER_C_IDENT;
411 34 : /* ] */ t[93] |= SC_COMPILER_C_IDENT;
412 : }
413 102 : if( FormulaGrammar::CONV_XL_OOX == meConv )
414 : {
415 34 : /* [ */ t[91] |= SC_COMPILER_C_CHAR_IDENT;
416 34 : /* ] */ t[93] |= SC_COMPILER_C_IDENT;
417 : }
418 : }
419 170 : }
420 :
421 : //-----------------------------------------------------------------------------
422 :
423 508 : 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 508 : if (rFormula.GetChar(nSrcPos) == '\'')
430 : {
431 210 : xub_StrLen nPos = nSrcPos+1;
432 3068 : while (nPos < rFormula.Len())
433 : {
434 2858 : if (rFormula.GetChar(nPos) == '\'')
435 : {
436 210 : if ( (nPos+1 == rFormula.Len()) || (rFormula.GetChar(nPos+1) != '\'') )
437 : {
438 210 : rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
439 210 : rRes.EndPos = nPos+1;
440 210 : return true;
441 : }
442 0 : ++nPos;
443 : }
444 2648 : ++nPos;
445 : }
446 : }
447 :
448 298 : return false;
449 : }
450 :
451 20 : 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 20 : const sal_Unicode* const pStart = rSymbol.GetBuffer();
462 20 : const sal_Unicode* p = pStart;
463 20 : xub_StrLen nLen = rSymbol.Len();
464 20 : sal_Unicode cPrev = 0;
465 20 : String aTmpFile, aTmpName;
466 20 : xub_StrLen i = 0;
467 20 : bool bInName = false;
468 20 : if (cSep == '!')
469 : {
470 : // For XL use existing parser that resolves bracketed and quoted and
471 : // indexed external document names.
472 6 : ScRange aRange;
473 6 : String aStartTabName, aEndTabName;
474 6 : sal_uInt16 nFlags = 0;
475 : p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName,
476 6 : aEndTabName, nFlags, true, pExternalLinks );
477 6 : if (!p || p == pStart)
478 6 : return false;
479 0 : i = xub_StrLen(p - pStart);
480 0 : cPrev = *(p-1);
481 : }
482 108 : for ( ; i < nLen; ++i, ++p)
483 : {
484 94 : sal_Unicode c = *p;
485 94 : if (i == 0)
486 : {
487 14 : if (c == '.' || c == cSep)
488 0 : return false;
489 :
490 14 : 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 94 : 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 94 : 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 94 : if (CharClass::isAsciiAlphaNumeric(c))
574 : // allowed.
575 94 : 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 94 : aTmpFile.Append(c);
598 : }
599 : }
600 94 : cPrev = c;
601 : }
602 :
603 14 : if (!bInName)
604 : {
605 : // No name found - most likely the symbol has no '!'s.
606 14 : 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 136 : struct Convention_A1 : public ScCompiler::Convention
688 : {
689 136 : 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 508 : ParseResult parseAnyToken( const String& rFormula,
694 : xub_StrLen nSrcPos,
695 : const CharClass* pCharClass) const
696 : {
697 508 : ParseResult aRet;
698 508 : if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
699 210 : 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 298 : static const String aAddAllowed(rtl::OUString("?#"));
706 : return pCharClass->parseAnyToken( rFormula,
707 298 : nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
708 : }
709 :
710 21622 : virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode /*cLast*/ ) const
711 : {
712 21622 : return mpCharTable[static_cast<sal_uInt8>(c)];
713 : }
714 : };
715 :
716 680 : void Convention_A1::MakeColStr( rtl::OUStringBuffer& rBuffer, SCCOL nCol )
717 : {
718 680 : if ( !ValidCol( nCol) )
719 0 : rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
720 : else
721 680 : ::ScColToAlpha( rBuffer, nCol);
722 680 : }
723 :
724 680 : void Convention_A1::MakeRowStr( rtl::OUStringBuffer& rBuffer, SCROW nRow )
725 : {
726 680 : if ( !ValidRow(nRow) )
727 0 : rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
728 : else
729 680 : rBuffer.append(sal_Int32(nRow + 1));
730 680 : }
731 :
732 : //-----------------------------------------------------------------------------
733 :
734 68 : struct ConventionOOO_A1 : public Convention_A1
735 : {
736 34 : ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO) { }
737 34 : ConventionOOO_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1 (eConv) { }
738 370 : static String MakeTabStr( const ScCompiler& rComp, SCTAB nTab, String& aDoc )
739 : {
740 370 : String aString;
741 370 : OUString aTmp;
742 370 : if (!rComp.GetDoc()->GetName( nTab, aTmp ))
743 0 : aString = ScGlobal::GetRscString(STR_NO_REF_TABLE);
744 : else
745 : {
746 370 : aString = aTmp;
747 : // "'Doc'#Tab"
748 370 : xub_StrLen nPos = ScCompiler::GetDocTabPos( aString );
749 370 : 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 370 : aDoc.Erase();
758 370 : ScCompiler::CheckTabQuotes( aString, FormulaGrammar::CONV_OOO );
759 : }
760 370 : aString += '.';
761 370 : return aString;
762 : }
763 :
764 :
765 672 : void MakeOneRefStrImpl( rtl::OUStringBuffer& rBuffer,
766 : const ScCompiler& rComp,
767 : const ScSingleRefData& rRef,
768 : bool bForceTab,
769 : bool bODF ) const
770 : {
771 672 : if( rRef.IsFlag3D() || bForceTab )
772 : {
773 370 : 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 370 : String aDoc;
783 370 : String aRefStr( MakeTabStr( rComp, rRef.nTab, aDoc ) );
784 370 : rBuffer.append(aDoc);
785 370 : if (!rRef.IsTabRel())
786 368 : rBuffer.append(sal_Unicode('$'));
787 370 : rBuffer.append(aRefStr);
788 : }
789 : }
790 302 : else if (bODF)
791 0 : rBuffer.append(sal_Unicode('.'));
792 672 : if (!rRef.IsColRel())
793 562 : rBuffer.append(sal_Unicode('$'));
794 672 : if ( rRef.IsColDeleted() )
795 0 : rBuffer.append( rComp.GetCurrentOpCodeMap()->getSymbol( ocErrRef));
796 : else
797 672 : MakeColStr(rBuffer, rRef.nCol );
798 672 : if (!rRef.IsRowRel())
799 564 : rBuffer.append(sal_Unicode('$'));
800 672 : if ( rRef.IsRowDeleted() )
801 0 : rBuffer.append( rComp.GetCurrentOpCodeMap()->getSymbol( ocErrRef));
802 : else
803 672 : MakeRowStr( rBuffer, rRef.nRow );
804 672 : }
805 :
806 :
807 484 : void MakeRefStrImpl( rtl::OUStringBuffer& rBuffer,
808 : const ScCompiler& rComp,
809 : const ScComplexRefData& rRef,
810 : bool bSingleRef,
811 : bool bODF ) const
812 : {
813 484 : if (bODF)
814 0 : rBuffer.append(sal_Unicode('['));
815 484 : ScComplexRefData aRef( rRef );
816 : // In case absolute/relative positions weren't separately available:
817 : // transform relative to absolute!
818 484 : aRef.Ref1.CalcAbsIfRel( rComp.GetPos() );
819 484 : if( !bSingleRef )
820 188 : aRef.Ref2.CalcAbsIfRel( rComp.GetPos() );
821 484 : 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 484 : MakeOneRefStrImpl( rBuffer, rComp, aRef.Ref1, false, bODF);
831 484 : if (!bSingleRef)
832 : {
833 188 : rBuffer.append(sal_Unicode(':'));
834 188 : MakeOneRefStrImpl( rBuffer, rComp, aRef.Ref2, (aRef.Ref2.nTab != aRef.Ref1.nTab), bODF);
835 : }
836 : }
837 484 : if (bODF)
838 0 : rBuffer.append(sal_Unicode(']'));
839 484 : }
840 :
841 484 : void MakeRefStr( rtl::OUStringBuffer& rBuffer,
842 : const ScCompiler& rComp,
843 : const ScComplexRefData& rRef,
844 : bool bSingleRef ) const
845 : {
846 484 : MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, false);
847 484 : }
848 :
849 15212 : virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const
850 : {
851 15212 : switch (eSymType)
852 : {
853 : case ScCompiler::Convention::ABS_SHEET_PREFIX:
854 7606 : return '$';
855 : case ScCompiler::Convention::SHEET_SEPARATOR:
856 7606 : return '.';
857 : }
858 :
859 0 : return sal_Unicode(0);
860 : }
861 :
862 14 : 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 14 : 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 8 : 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 8 : if (bDisplayTabName)
880 : {
881 8 : String aFile;
882 8 : const OUString* p = pRefMgr->getExternalFileName(nFileId);
883 8 : if (p)
884 : {
885 8 : if (bEncodeUrl)
886 0 : aFile = *p;
887 : else
888 8 : aFile = INetURLObject::decode(*p, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS);
889 : }
890 8 : aFile.SearchAndReplaceAllAscii("'", rtl::OUString("''"));
891 :
892 8 : rBuffer.append(sal_Unicode('\''));
893 8 : rBuffer.append(aFile);
894 8 : rBuffer.append(sal_Unicode('\''));
895 8 : rBuffer.append(sal_Unicode('#'));
896 :
897 8 : if (!rRef.IsTabRel())
898 8 : rBuffer.append(sal_Unicode('$'));
899 8 : ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
900 :
901 8 : rBuffer.append(sal_Unicode('.'));
902 : }
903 :
904 8 : if (!rRef.IsColRel())
905 4 : rBuffer.append(sal_Unicode('$'));
906 8 : MakeColStr( rBuffer, rRef.nCol);
907 8 : if (!rRef.IsRowRel())
908 6 : rBuffer.append(sal_Unicode('$'));
909 8 : MakeRowStr( rBuffer, rRef.nRow);
910 :
911 8 : return true;
912 : }
913 :
914 8 : 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 8 : ScSingleRefData aRef(rRef);
919 8 : aRef.CalcAbsIfRel(rCompiler.GetPos());
920 :
921 8 : if (bODF)
922 0 : rBuffer.append( sal_Unicode('['));
923 :
924 8 : bool bEncodeUrl = true;
925 8 : switch (rCompiler.GetEncodeUrlMode())
926 : {
927 : case ScCompiler::ENCODE_BY_GRAMMAR:
928 8 : bEncodeUrl = bODF;
929 8 : 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 8 : makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true, bEncodeUrl);
940 8 : if (bODF)
941 0 : rBuffer.append( sal_Unicode(']'));
942 8 : }
943 :
944 8 : 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 8 : makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false);
949 8 : }
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 34 : static const ConventionOOO_A1 ConvOOO_A1;
1021 : const ScCompiler::Convention * const ScCompiler::pConvOOO_A1 = &ConvOOO_A1;
1022 :
1023 : //-----------------------------------------------------------------------------
1024 :
1025 34 : struct ConventionOOO_A1_ODF : public ConventionOOO_A1
1026 : {
1027 34 : 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 34 : static const ConventionOOO_A1_ODF ConvOOO_A1_ODF;
1057 : const ScCompiler::Convention * const ScCompiler::pConvOOO_A1_ODF = &ConvOOO_A1_ODF;
1058 :
1059 : //-----------------------------------------------------------------------------
1060 :
1061 102 : 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 1444 : static sal_Unicode getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType )
1142 : {
1143 1444 : switch (eSymType)
1144 : {
1145 : case ScCompiler::Convention::ABS_SHEET_PREFIX:
1146 722 : return sal_Unicode(0);
1147 : case ScCompiler::Convention::SHEET_SEPARATOR:
1148 722 : return '!';
1149 : }
1150 0 : return sal_Unicode(0);
1151 : }
1152 :
1153 6 : 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 6 : 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 68 : struct ConventionXL_A1 : public Convention_A1, public ConventionXL
1270 : {
1271 34 : ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1 ) { }
1272 34 : 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 744 : virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const
1363 : {
1364 744 : return ConventionXL::getSpecialSymbol(eSymType);
1365 : }
1366 :
1367 6 : 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 6 : 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 34 : static const ConventionXL_A1 ConvXL_A1;
1436 : const ScCompiler::Convention * const ScCompiler::pConvXL_A1 = &ConvXL_A1;
1437 :
1438 :
1439 34 : struct ConventionXL_OOX : public ConventionXL_A1
1440 : {
1441 34 : ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
1442 : };
1443 :
1444 34 : 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 34 : struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
1484 : {
1485 34 : 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 700 : virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const
1569 : {
1570 700 : 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 1638 : virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode cLast ) const
1669 : {
1670 1638 : sal_uLong nFlags = mpCharTable[static_cast<sal_uInt8>(c)];
1671 1638 : if (c == '-' && cLast == '[')
1672 : // '-' can occur within a reference string only after '[' e.g. R[-1]C.
1673 152 : nFlags |= SC_COMPILER_C_IDENT;
1674 1638 : return nFlags;
1675 : }
1676 : };
1677 :
1678 34 : static const ConventionXL_R1C1 ConvXL_R1C1;
1679 : const ScCompiler::Convention * const ScCompiler::pConvXL_R1C1 = &ConvXL_R1C1;
1680 :
1681 : //-----------------------------------------------------------------------------
1682 7568 : 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 7568 : mbRewind( false )
1694 : {
1695 7568 : nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
1696 7568 : }
1697 :
1698 1132 : 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 1132 : mbRewind( false )
1710 : {
1711 1132 : nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
1712 1132 : }
1713 :
1714 430 : void ScCompiler::CheckTabQuotes( String& rString,
1715 : const FormulaGrammar::AddressConvention eConv )
1716 : {
1717 : using namespace ::com::sun::star::i18n;
1718 430 : sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE;
1719 430 : sal_Int32 nContFlags = nStartFlags;
1720 : ParseResult aRes = ScGlobal::pCharClass->parsePredefinedToken(
1721 430 : KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_STRING, nContFlags, EMPTY_STRING);
1722 430 : bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.Len());
1723 :
1724 430 : 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 430 : if( bNeedsQuote )
1734 : {
1735 304 : const rtl::OUString one_quote(static_cast<sal_Unicode>('\''));
1736 304 : const rtl::OUString two_quote("''");
1737 : // escape embedded quotes
1738 304 : rString.SearchAndReplaceAll( one_quote, two_quote );
1739 : }
1740 430 : break;
1741 : }
1742 :
1743 430 : if ( !bNeedsQuote && CharClass::isAsciiNumeric( rString ) )
1744 : {
1745 : // Prevent any possible confusion resulting from pure numeric sheet names.
1746 0 : bNeedsQuote = true;
1747 : }
1748 :
1749 430 : if( bNeedsQuote )
1750 : {
1751 304 : rString.Insert( '\'', 0 );
1752 304 : rString += '\'';
1753 430 : }
1754 430 : }
1755 :
1756 :
1757 372 : xub_StrLen ScCompiler::GetDocTabPos( const String& rString )
1758 : {
1759 372 : if (rString.GetChar(0) != '\'')
1760 372 : 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 14266 : void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv )
1771 : {
1772 14266 : switch ( eConv ) {
1773 : case FormulaGrammar::CONV_UNSPECIFIED :
1774 116 : break;
1775 : default :
1776 11980 : case FormulaGrammar::CONV_OOO : SetRefConvention( pConvOOO_A1 ); break;
1777 1814 : case FormulaGrammar::CONV_ODF : SetRefConvention( pConvOOO_A1_ODF ); break;
1778 8 : case FormulaGrammar::CONV_XL_A1 : SetRefConvention( pConvXL_A1 ); break;
1779 232 : case FormulaGrammar::CONV_XL_R1C1 : SetRefConvention( pConvXL_R1C1 ); break;
1780 116 : case FormulaGrammar::CONV_XL_OOX : SetRefConvention( pConvXL_OOX ); break;
1781 : }
1782 14266 : }
1783 :
1784 14150 : void ScCompiler::SetRefConvention( const ScCompiler::Convention *pConvP )
1785 : {
1786 14150 : pConv = pConvP;
1787 14150 : meGrammar = FormulaGrammar::mergeToGrammar( meGrammar, pConv->meConv);
1788 : OSL_ENSURE( FormulaGrammar::isSupported( meGrammar),
1789 : "ScCompiler::SetRefConvention: unsupported grammar resulting");
1790 14150 : }
1791 :
1792 1470 : void ScCompiler::SetError(sal_uInt16 nError)
1793 : {
1794 1470 : if( !pArr->GetCodeError() )
1795 736 : pArr->SetCodeError( nError);
1796 1470 : }
1797 :
1798 :
1799 210 : static sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub_StrLen nMax )
1800 : {
1801 210 : const sal_Unicode* const pStop = pDst + nMax;
1802 5320 : while ( *pSrc && pDst < pStop )
1803 : {
1804 4900 : *pDst++ = *pSrc++;
1805 : }
1806 210 : *pDst = 0;
1807 210 : 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 8328 : xub_StrLen ScCompiler::NextSymbol(bool bInArray)
1848 : {
1849 8328 : cSymbol[MAXSTRLEN-1] = 0; // Stopper
1850 8328 : sal_Unicode* pSym = cSymbol;
1851 8328 : const sal_Unicode* const pStart = aFormula.GetBuffer();
1852 8328 : const sal_Unicode* pSrc = pStart + nSrcPos;
1853 8328 : bool bi18n = false;
1854 8328 : sal_Unicode c = *pSrc;
1855 8328 : sal_Unicode cLast = 0;
1856 8328 : bool bQuote = false;
1857 8328 : mnRangeOpPosInSymbol = -1;
1858 8328 : ScanState eState = ssGetChar;
1859 8328 : xub_StrLen nSpaces = 0;
1860 8328 : sal_Unicode cSep = mxSymbols->getSymbol( ocSep).GetChar(0);
1861 8328 : sal_Unicode cArrayColSep = mxSymbols->getSymbol( ocArrayColSep).GetChar(0);
1862 8328 : sal_Unicode cArrayRowSep = mxSymbols->getSymbol( ocArrayRowSep).GetChar(0);
1863 8328 : sal_Unicode cDecSep = (mxSymbols->isEnglish() ? '.' :
1864 8328 : ScGlobal::pLocaleData->getNumDecimalSep()[0]);
1865 :
1866 : // special symbols specific to address convention used
1867 8328 : sal_Unicode cSheetPrefix = pConv->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX);
1868 8328 : sal_Unicode cSheetSep = pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
1869 :
1870 8328 : int nDecSeps = 0;
1871 8328 : bool bAutoIntersection = false;
1872 8328 : int nRefInName = 0;
1873 8328 : bool bErrorConstantHadSlash = false;
1874 8328 : mnPredetectedReference = 0;
1875 : // try to parse simple tokens before calling i18n parser
1876 37906 : while ((c != 0) && (eState != ssStop) )
1877 : {
1878 21250 : pSrc++;
1879 21250 : 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 21250 : if (c == cSep || (bInArray && (c == cArrayColSep || c == cArrayRowSep)))
1884 : {
1885 1270 : 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 1270 : if (eState == ssGetChar)
1895 720 : *pSym++ = c;
1896 : else
1897 550 : pSrc--;
1898 1270 : eState = ssStop;
1899 : }
1900 : }
1901 : Label_MaskStateMachine:
1902 21250 : switch (eState)
1903 : {
1904 : case ssGetChar :
1905 : {
1906 : // Order is important!
1907 6040 : 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 6040 : 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 6040 : else if( nMask & SC_COMPILER_C_CHAR )
1953 : {
1954 2456 : *pSym++ = c;
1955 2456 : eState = ssStop;
1956 : }
1957 3584 : else if( nMask & SC_COMPILER_C_ODF_LBRACKET )
1958 : {
1959 : // eaten, not added to pSym
1960 296 : eState = ssGetReference;
1961 296 : mnPredetectedReference = 1;
1962 : }
1963 3288 : else if( nMask & SC_COMPILER_C_CHAR_BOOL )
1964 : {
1965 14 : *pSym++ = c;
1966 14 : eState = ssGetBool;
1967 : }
1968 3274 : else if( nMask & SC_COMPILER_C_CHAR_VALUE )
1969 : {
1970 870 : *pSym++ = c;
1971 870 : eState = ssGetValue;
1972 : }
1973 2404 : else if( nMask & SC_COMPILER_C_CHAR_STRING )
1974 : {
1975 202 : *pSym++ = c;
1976 202 : eState = ssGetString;
1977 : }
1978 2202 : else if( nMask & SC_COMPILER_C_CHAR_ERRCONST )
1979 : {
1980 0 : *pSym++ = c;
1981 0 : eState = ssGetErrorConstant;
1982 : }
1983 2202 : else if( nMask & SC_COMPILER_C_CHAR_DONTCARE )
1984 : {
1985 68 : nSpaces++;
1986 : }
1987 2134 : 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 2076 : *pSym++ = c;
1991 2076 : eState = ssGetIdent;
1992 : }
1993 : else
1994 : {
1995 58 : bi18n = true;
1996 58 : eState = ssStop;
1997 : }
1998 : }
1999 6040 : break;
2000 : case ssGetIdent:
2001 : {
2002 10198 : if ( nMask & SC_COMPILER_C_IDENT )
2003 : { // This catches also $Sheet1.A$1, for example.
2004 8530 : if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
2005 : {
2006 0 : SetError(errStringOverflow);
2007 0 : eState = ssStop;
2008 : }
2009 : else
2010 8530 : *pSym++ = c;
2011 : }
2012 1668 : 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 204 : mnRangeOpPosInSymbol = pSym - &cSymbol[0];
2017 408 : if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
2018 : {
2019 0 : SetError(errStringOverflow);
2020 0 : eState = ssStop;
2021 : }
2022 : else
2023 204 : *pSym++ = c;
2024 : }
2025 1464 : 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 152 : bi18n = true;
2030 152 : eState = ssStop;
2031 : }
2032 : else
2033 : {
2034 1312 : pSrc--;
2035 1312 : eState = ssStop;
2036 : }
2037 : }
2038 10198 : break;
2039 : case ssGetBool :
2040 : {
2041 14 : if( nMask & SC_COMPILER_C_BOOL )
2042 : {
2043 12 : *pSym++ = c;
2044 12 : eState = ssStop;
2045 : }
2046 : else
2047 : {
2048 2 : pSrc--;
2049 2 : eState = ssStop;
2050 : }
2051 : }
2052 14 : break;
2053 : case ssGetValue :
2054 : {
2055 748 : if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
2056 : {
2057 0 : SetError(errStringOverflow);
2058 0 : eState = ssStop;
2059 : }
2060 748 : else if (c == cDecSep)
2061 : {
2062 28 : 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 28 : *pSym++ = c;
2070 : }
2071 720 : else if( nMask & SC_COMPILER_C_VALUE )
2072 230 : *pSym++ = c;
2073 490 : else if( nMask & SC_COMPILER_C_VALUE_SEP )
2074 : {
2075 474 : pSrc--;
2076 474 : eState = ssStop;
2077 : }
2078 16 : 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 16 : else if( nMask & SC_COMPILER_C_VALUE_SIGN )
2090 : {
2091 16 : 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 16 : pSrc--;
2099 16 : eState = ssStop;
2100 : }
2101 : }
2102 : else
2103 : {
2104 : // reparse with i18n
2105 0 : bi18n = true;
2106 0 : eState = ssStop;
2107 : }
2108 : }
2109 748 : break;
2110 : case ssGetString :
2111 : {
2112 1020 : if( nMask & SC_COMPILER_C_STRING_SEP )
2113 : {
2114 202 : if ( !bQuote )
2115 : {
2116 202 : if ( *pSrc == '"' )
2117 0 : bQuote = true; // "" => literal "
2118 : else
2119 202 : eState = ssStop;
2120 : }
2121 : else
2122 0 : bQuote = false;
2123 : }
2124 1020 : if ( !bQuote )
2125 : {
2126 1020 : if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
2127 : {
2128 0 : SetError(errStringOverflow);
2129 0 : eState = ssSkipString;
2130 : }
2131 : else
2132 1020 : *pSym++ = c;
2133 : }
2134 : }
2135 1020 : 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 1960 : 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 1960 : bool bAddToSymbol = true;
2236 1960 : 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 296 : bAddToSymbol = false;
2243 296 : eState = ssStop;
2244 : }
2245 1664 : else if (cSheetSep == c && nRefInName == 0)
2246 : {
2247 : // eat it, no sheet name [.A1]
2248 368 : bAddToSymbol = false;
2249 368 : nRefInName |= kPast;
2250 736 : if ('$' == pSrc[0] && '$' == pSrc[1])
2251 0 : nRefInName |= kMarkAhead;
2252 : }
2253 1296 : else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName)))
2254 : {
2255 : // Not in col/row yet.
2256 :
2257 528 : if (SC_COMPILER_FILE_TAB_SEP == c && (nRefInName & kFileSep))
2258 0 : nRefInName = 0;
2259 264 : 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 264 : else if (cSheetPrefix == c && nRefInName == 0)
2283 0 : nRefInName |= kDollar;
2284 264 : 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 264 : else if ('#' == c && nRefInName == 0)
2325 0 : nRefInName |= kRefErr;
2326 264 : else if (cSheetSep == c && !(nRefInName & kOpen))
2327 : {
2328 : // unquoted sheet name separator
2329 24 : nRefInName |= kPast;
2330 48 : if ('$' == pSrc[0] && '$' == pSrc[1])
2331 0 : nRefInName |= kMarkAhead;
2332 : }
2333 240 : 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 240 : else if (!(nRefInName & kName))
2341 : {
2342 : // start unquoted name
2343 24 : nRefInName |= kName;
2344 : }
2345 : }
2346 1032 : else if (':' == c)
2347 : {
2348 : // range operator
2349 96 : nRefInName = 0;
2350 96 : ++mnPredetectedReference;
2351 : }
2352 1960 : if (bAddToSymbol && eState != ssSkipReference)
2353 1296 : *pSym++ = c; // everything is part of reference
2354 : }
2355 1960 : break;
2356 : case ssStop:
2357 : ; // nothing, prevent warning
2358 1270 : break;
2359 : }
2360 21250 : cLast = c;
2361 21250 : c = *pSrc;
2362 : }
2363 8328 : if ( bi18n )
2364 : {
2365 210 : nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces );
2366 210 : String aSymbol;
2367 210 : mnRangeOpPosInSymbol = -1;
2368 210 : sal_uInt16 nErr = 0;
2369 508 : do
2370 : {
2371 508 : bi18n = false;
2372 : // special case (e.g. $'sheetname' in OOO A1)
2373 508 : if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' )
2374 152 : aSymbol += pStart[nSrcPos++];
2375 :
2376 508 : ParseResult aRes = pConv->parseAnyToken( aFormula, nSrcPos, pCharClass );
2377 :
2378 508 : if ( !aRes.TokenType )
2379 0 : SetError( nErr = errIllegalChar ); // parsed chars as string
2380 508 : if ( aRes.EndPos <= nSrcPos )
2381 : { // ?!?
2382 0 : SetError( nErr = errIllegalChar );
2383 0 : nSrcPos = aFormula.Len();
2384 0 : aSymbol.Erase();
2385 : }
2386 : else
2387 : {
2388 508 : aSymbol.Append( pStart + nSrcPos, (xub_StrLen)aRes.EndPos - nSrcPos );
2389 508 : nSrcPos = (xub_StrLen) aRes.EndPos;
2390 508 : c = pStart[nSrcPos];
2391 508 : if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME )
2392 : { // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
2393 210 : bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP);
2394 : }
2395 : // One range operator restarts parsing for second reference.
2396 508 : if (c == ':' && mnRangeOpPosInSymbol < 0)
2397 : {
2398 88 : mnRangeOpPosInSymbol = aSymbol.Len();
2399 88 : bi18n = true;
2400 : }
2401 508 : if ( bi18n )
2402 298 : aSymbol += pStart[nSrcPos++];
2403 508 : }
2404 : } while ( bi18n && !nErr );
2405 210 : xub_StrLen nLen = aSymbol.Len();
2406 210 : if ( nLen >= MAXSTRLEN )
2407 : {
2408 0 : SetError( errStringOverflow );
2409 0 : nLen = MAXSTRLEN-1;
2410 : }
2411 210 : lcl_UnicodeStrNCpy( cSymbol, aSymbol.GetBuffer(), nLen );
2412 210 : pSym = &cSymbol[nLen];
2413 : }
2414 : else
2415 : {
2416 8118 : nSrcPos = sal::static_int_cast<xub_StrLen>( pSrc - pStart );
2417 8118 : *pSym = 0;
2418 : }
2419 8328 : 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 8328 : if ( bAutoCorrect )
2428 0 : aCorrectedSymbol = cSymbol;
2429 8328 : if (bAutoIntersection && nSpaces > 1)
2430 0 : --nSpaces; // replace '!!' with only one space
2431 8328 : return nSpaces;
2432 : }
2433 :
2434 : //---------------------------------------------------------------------------
2435 : // Convert symbol to token
2436 : //---------------------------------------------------------------------------
2437 :
2438 4602 : bool ScCompiler::IsOpCode( const String& rName, bool bInArray )
2439 : {
2440 4602 : OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
2441 4602 : bool bFound = (iLook != mxSymbols->getHashMap()->end());
2442 4602 : if (bFound)
2443 : {
2444 4254 : ScRawToken aToken;
2445 4254 : OpCode eOp = iLook->second;
2446 4254 : if (bInArray)
2447 : {
2448 38 : if (rName.Equals(mxSymbols->getSymbol(ocArrayColSep)))
2449 24 : eOp = ocArrayColSep;
2450 14 : else if (rName.Equals(mxSymbols->getSymbol(ocArrayRowSep)))
2451 4 : eOp = ocArrayRowSep;
2452 : }
2453 4254 : aToken.SetOpCode(eOp);
2454 4254 : pRawToken = aToken.Clone();
2455 : }
2456 348 : 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 200 : for (size_t i=0; i<nOdffAliases; ++i)
2479 : {
2480 150 : 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 4602 : if (!bFound)
2491 : {
2492 348 : String aIntName;
2493 348 : if (mxSymbols->hasExternals())
2494 : {
2495 : // If symbols are set by filters get mapping to exact name.
2496 : ExternalHashMap::const_iterator iExt(
2497 64 : mxSymbols->getExternalHashMap()->find( rName));
2498 64 : if (iExt != mxSymbols->getExternalHashMap()->end())
2499 : {
2500 0 : if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt).second))
2501 0 : aIntName = (*iExt).second;
2502 : }
2503 64 : 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 64 : return false;
2510 : }
2511 : }
2512 284 : if (!aIntName.Len())
2513 : {
2514 : // Old (deprecated) addins first for legacy.
2515 284 : 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 284 : rName, !mxSymbols->isEnglish());
2526 : }
2527 284 : 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 348 : }
2534 : }
2535 : OpCode eOp;
2536 4538 : 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 172 : eLastOp == ocArrayColSep || eLastOp == ocArrayRowSep);
2543 172 : if (bShouldBeNegSub && eOp == ocSub)
2544 118 : pRawToken->NewOpCode( ocNegSub );
2545 : //! if ocNegSub had ForceArray we'd have to set it here
2546 54 : else if (!bShouldBeNegSub && eOp == ocNegSub)
2547 2 : pRawToken->NewOpCode( ocSub );
2548 : }
2549 4538 : return bFound;
2550 : }
2551 :
2552 2 : bool ScCompiler::IsOpCode2( const String& rName )
2553 : {
2554 2 : bool bFound = false;
2555 : sal_uInt16 i;
2556 :
2557 4 : for( i = ocInternalBegin; i <= ocInternalEnd && !bFound; i++ )
2558 2 : bFound = rName.EqualsAscii( pInternal[ i-ocInternalBegin ] );
2559 :
2560 2 : if (bFound)
2561 : {
2562 0 : ScRawToken aToken;
2563 0 : aToken.SetOpCode( (OpCode) --i );
2564 0 : pRawToken = aToken.Clone();
2565 : }
2566 2 : return bFound;
2567 : }
2568 :
2569 972 : bool ScCompiler::IsValue( const String& rSym )
2570 : {
2571 : double fVal;
2572 972 : sal_uInt32 nIndex = ( mxSymbols->isEnglish() ?
2573 972 : pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US ) : 0 );
2574 :
2575 972 : if (pDoc->GetFormatTable()->IsNumberFormat( rSym, nIndex, fVal ) )
2576 : {
2577 870 : 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 870 : if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE))
2585 0 : return false;
2586 :
2587 870 : 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 870 : if( nType == NUMBERFORMAT_TEXT )
2597 : // HACK: number too big!
2598 0 : SetError( errIllegalArgument );
2599 870 : ScRawToken aToken;
2600 870 : aToken.SetDouble( fVal );
2601 870 : pRawToken = aToken.Clone();
2602 870 : return true;
2603 : }
2604 : else
2605 102 : return false;
2606 : }
2607 :
2608 6396 : bool ScCompiler::IsString()
2609 : {
2610 6396 : register const sal_Unicode* p = cSymbol;
2611 33902 : while ( *p )
2612 21110 : p++;
2613 6396 : xub_StrLen nLen = sal::static_int_cast<xub_StrLen>( p - cSymbol - 1 );
2614 6396 : bool bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"'));
2615 6396 : if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1)
2616 : {
2617 0 : SetError(errStringOverflow);
2618 0 : return false;
2619 : }
2620 6396 : if ( bQuote )
2621 : {
2622 202 : cSymbol[nLen] = '\0';
2623 202 : ScRawToken aToken;
2624 202 : aToken.SetString( cSymbol+1 );
2625 202 : pRawToken = aToken.Clone();
2626 202 : return true;
2627 : }
2628 6194 : return false;
2629 : }
2630 :
2631 :
2632 296 : bool ScCompiler::IsPredetectedReference( const String& rName )
2633 : {
2634 : // Speedup documents with lots of broken references, e.g. sheet deleted.
2635 296 : xub_StrLen nPos = rName.SearchAscii( "#REF!");
2636 296 : 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 296 : switch (mnPredetectedReference)
2680 : {
2681 : case 1:
2682 200 : return IsSingleReference( rName);
2683 : case 2:
2684 96 : return IsDoubleReference( rName);
2685 : }
2686 0 : return false;
2687 : }
2688 :
2689 :
2690 388 : bool ScCompiler::IsDoubleReference( const String& rName )
2691 : {
2692 388 : ScRange aRange( aPos, aPos );
2693 388 : const ScAddress::Details aDetails( pConv->meConv, aPos );
2694 388 : ScAddress::ExternalInfo aExtInfo;
2695 388 : sal_uInt16 nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
2696 388 : if( nFlags & SCA_VALID )
2697 : {
2698 388 : ScRawToken aToken;
2699 : ScComplexRefData aRef;
2700 388 : aRef.InitRange( aRange );
2701 388 : aRef.Ref1.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
2702 388 : aRef.Ref1.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
2703 388 : aRef.Ref1.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
2704 388 : if ( !(nFlags & SCA_VALID_TAB) )
2705 0 : aRef.Ref1.SetTabDeleted( true ); // #REF!
2706 388 : aRef.Ref1.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
2707 388 : aRef.Ref2.SetColRel( (nFlags & SCA_COL2_ABSOLUTE) == 0 );
2708 388 : aRef.Ref2.SetRowRel( (nFlags & SCA_ROW2_ABSOLUTE) == 0 );
2709 388 : aRef.Ref2.SetTabRel( (nFlags & SCA_TAB2_ABSOLUTE) == 0 );
2710 388 : if ( !(nFlags & SCA_VALID_TAB2) )
2711 0 : aRef.Ref2.SetTabDeleted( true ); // #REF!
2712 388 : aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
2713 388 : aRef.CalcRelFromAbs( aPos );
2714 388 : if (aExtInfo.mbExternal)
2715 : {
2716 12 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
2717 12 : const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
2718 : aToken.SetExternalDoubleRef(
2719 12 : aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
2720 : }
2721 : else
2722 : {
2723 376 : aToken.SetDoubleReference(aRef);
2724 : }
2725 388 : pRawToken = aToken.Clone();
2726 : }
2727 :
2728 388 : return ( nFlags & SCA_VALID ) != 0;
2729 : }
2730 :
2731 :
2732 1270 : bool ScCompiler::IsSingleReference( const String& rName )
2733 : {
2734 1270 : ScAddress aAddr( aPos );
2735 1270 : const ScAddress::Details aDetails( pConv->meConv, aPos );
2736 1270 : ScAddress::ExternalInfo aExtInfo;
2737 1270 : 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 1270 : if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) )
2741 : {
2742 876 : ScRawToken aToken;
2743 : ScSingleRefData aRef;
2744 876 : aRef.InitAddress( aAddr );
2745 876 : aRef.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
2746 876 : aRef.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
2747 876 : aRef.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
2748 876 : aRef.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
2749 : // the reference is really invalid
2750 876 : 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 876 : aRef.CalcRelFromAbs( aPos );
2761 :
2762 876 : if (aExtInfo.mbExternal)
2763 : {
2764 46 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
2765 46 : const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
2766 : aToken.SetExternalSingleRef(
2767 46 : aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
2768 : }
2769 : else
2770 830 : aToken.SetSingleReference(aRef);
2771 876 : pRawToken = aToken.Clone();
2772 : }
2773 :
2774 1270 : return ( nFlags & SCA_VALID ) != 0;
2775 : }
2776 :
2777 :
2778 1940 : bool ScCompiler::IsReference( const String& rName )
2779 : {
2780 : // Has to be called before IsValue
2781 1940 : sal_Unicode ch1 = rName.GetChar(0);
2782 1940 : sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' :
2783 1940 : ScGlobal::pLocaleData->getNumDecimalSep()[0] );
2784 1940 : if ( ch1 == cDecSep )
2785 0 : return false;
2786 : // Who was that imbecile introducing '.' as the sheet name separator!?!
2787 1940 : 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 870 : const xub_StrLen nPos = ScGlobal::FindUnquoted( rName, '.');
2796 870 : if ( nPos == STRING_NOTFOUND )
2797 : {
2798 842 : if (ScGlobal::FindUnquoted( rName, ':') != STRING_NOTFOUND)
2799 0 : break; // may be 3:3, continue as usual
2800 842 : return false;
2801 : }
2802 28 : sal_Unicode const * const pTabSep = rName.GetBuffer() + nPos;
2803 28 : sal_Unicode ch2 = pTabSep[1]; // maybe a column identifier
2804 28 : if ( !(ch2 == '$' || CharClass::isAsciiAlpha( ch2 )) )
2805 28 : 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 1070 : if (IsSingleReference( rName))
2830 676 : 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 394 : if (mnRangeOpPosInSymbol > 0) // ":foo" would be nonsense
2836 : {
2837 292 : if (IsDoubleReference( rName))
2838 292 : 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 102 : switch (pConv->meConv)
2856 : {
2857 : case FormulaGrammar::CONV_XL_A1:
2858 : case FormulaGrammar::CONV_XL_R1C1:
2859 : case FormulaGrammar::CONV_XL_OOX:
2860 26 : if (rName.GetChar(0) == '\'' && IsDoubleReference( rName))
2861 0 : return true;
2862 26 : break;
2863 : default:
2864 : ; // nothing
2865 : }
2866 : }
2867 102 : return false;
2868 : }
2869 :
2870 2 : bool ScCompiler::IsMacro( const String& rName )
2871 : {
2872 : #ifdef DISABLE_SCRIPTING
2873 : (void) rName;
2874 :
2875 : return false;
2876 : #else
2877 2 : String aName( rName);
2878 2 : StarBASIC* pObj = 0;
2879 2 : SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
2880 :
2881 2 : SfxApplication* pSfxApp = SFX_APP();
2882 :
2883 2 : if( pDocSh )//XXX
2884 2 : 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 2 : if (FormulaGrammar::isODFF( GetGrammar()) && aName.EqualsIgnoreCaseAscii( "USER.", 0, 5))
2893 0 : aName.Erase( 0, 5);
2894 :
2895 2 : SbxMethod* pMeth = (SbxMethod*) pObj->Find( aName, SbxCLASS_METHOD );
2896 2 : if( !pMeth )
2897 : {
2898 2 : 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 102 : 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 102 : bool bGlobal = false;
2921 102 : ScRangeName* pRangeName = pDoc->GetRangeName(aPos.Tab());
2922 102 : const ScRangeData* pData = NULL;
2923 102 : if (pRangeName)
2924 100 : pData = pRangeName->findByUpperName(rUpperName);
2925 102 : if (!pData)
2926 : {
2927 72 : pRangeName = pDoc->GetRangeName();
2928 72 : if (pRangeName)
2929 72 : pData = pRangeName->findByUpperName(rUpperName);
2930 72 : if (pData)
2931 52 : bGlobal = true;
2932 : }
2933 :
2934 102 : if (pData)
2935 : {
2936 82 : ScRawToken aToken;
2937 82 : aToken.SetName(bGlobal, pData->GetIndex());
2938 82 : pRawToken = aToken.Clone();
2939 82 : return true;
2940 : }
2941 : else
2942 20 : return false;
2943 : }
2944 :
2945 20 : 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 20 : if (!pConv)
2954 0 : return false;
2955 :
2956 20 : String aFile, aName;
2957 20 : if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks))
2958 20 : 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 20 : bool ScCompiler::IsDBRange( const String& rName )
2980 : {
2981 20 : 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 20 : ScDBCollection::NamedDBs& rDBs = pDoc->GetDBCollection()->getNamedDBs();
2994 20 : const ScDBData* p = rDBs.findByUpperName(rName);
2995 20 : if (!p)
2996 16 : return false;
2997 :
2998 4 : ScRawToken aToken;
2999 4 : aToken.SetName(true, p->GetIndex()); // DB range is always global.
3000 4 : aToken.eOp = ocDBArea;
3001 4 : pRawToken = aToken.Clone();
3002 4 : return true;
3003 : }
3004 :
3005 16 : bool ScCompiler::IsColRowName( const String& rName )
3006 : {
3007 16 : bool bInList = false;
3008 16 : bool bFound = false;
3009 : ScSingleRefData aRef;
3010 16 : String aName( rName );
3011 16 : DeQuote( aName );
3012 16 : SCTAB nThisTab = aPos.Tab();
3013 48 : for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- )
3014 : { // first check ranges on this sheet, in case of duplicated names
3015 96 : for ( short jRow=0; jRow<2 && !bInList; jRow++ )
3016 : {
3017 : ScRangePairList* pRL;
3018 64 : if ( !jRow )
3019 32 : pRL = pDoc->GetColNameRanges();
3020 : else
3021 32 : pRL = pDoc->GetRowNameRanges();
3022 64 : 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 16 : if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
3086 : { // search in current sheet
3087 10 : long nDistance = 0, nMax = 0;
3088 10 : long nMyCol = (long) aPos.Col();
3089 10 : long nMyRow = (long) aPos.Row();
3090 10 : bool bTwo = false;
3091 10 : ScAddress aOne( 0, 0, aPos.Tab() );
3092 10 : ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() );
3093 :
3094 10 : ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache();
3095 10 : 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 8 : 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 8 : ScAutoNameAddresses::const_iterator aEnd(rAddresses.end());
3106 8 : 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 2 : ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) );
3160 24 : for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
3161 : {
3162 22 : if ( bFound )
3163 : { // stop if everything else is further away
3164 0 : if ( nMax < (long)aIter.GetCol() )
3165 0 : break; // aIter
3166 : }
3167 22 : CellType eType = pCell->GetCellType();
3168 : bool bOk = ( (eType == CELLTYPE_FORMULA ?
3169 18 : ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0
3170 10 : && ((ScFormulaCell*)pCell)->aPos != aPos // noIter
3171 50 : : true ) );
3172 22 : 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 10 : 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 16 : 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 16 : return false;
3290 : }
3291 :
3292 38 : bool ScCompiler::IsBoolean( const String& rName )
3293 : {
3294 38 : OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) );
3295 38 : 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 38 : 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 2036 : static inline bool lcl_UpperAsciiOrI18n( String& rUpper, const String& rOrg, FormulaGrammar::Grammar eGrammar )
3519 : {
3520 2036 : if (FormulaGrammar::isODFF( eGrammar ))
3521 : {
3522 : // ODFF has a defined set of English function names, avoid i18n
3523 : // overhead.
3524 1446 : rUpper = rOrg;
3525 1446 : rUpper.ToUpperAscii();
3526 1446 : return true;
3527 : }
3528 : else
3529 : {
3530 590 : rUpper = ScGlobal::pCharClass->uppercase( rOrg );
3531 590 : return false;
3532 : }
3533 : }
3534 :
3535 8328 : bool ScCompiler::NextNewToken( bool bInArray )
3536 : {
3537 8328 : bool bAllowBooleans = bInArray;
3538 8328 : xub_StrLen nSpaces = NextSymbol(bInArray);
3539 :
3540 8328 : if (!cSymbol[0])
3541 1636 : return false;
3542 :
3543 6692 : if( nSpaces )
3544 : {
3545 68 : ScRawToken aToken;
3546 68 : aToken.SetOpCode( ocSpaces );
3547 68 : aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces );
3548 68 : if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) )
3549 : {
3550 0 : SetError(errCodeOverflow);
3551 0 : return false;
3552 68 : }
3553 : }
3554 :
3555 : // Short cut for references when reading ODF to speedup things.
3556 6692 : if (mnPredetectedReference)
3557 : {
3558 296 : rtl::OUString aStr( cSymbol);
3559 296 : if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr))
3560 : {
3561 : /* TODO: it would be nice to generate a #REF! error here, which
3562 : * would need an ocBad token with additional error value.
3563 : * FormulaErrorToken wouldn't do because we want to preserve the
3564 : * original string containing partial valid address
3565 : * information if not ODFF (in that case it was already handled).
3566 : * */
3567 0 : ScRawToken aToken;
3568 0 : aToken.SetString( aStr.getStr() );
3569 0 : aToken.NewOpCode( ocBad );
3570 0 : pRawToken = aToken.Clone();
3571 : }
3572 296 : return true;
3573 : }
3574 :
3575 6396 : if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 &&
3576 0 : !bAutoCorrect )
3577 : { // special case to speed up broken [$]#REF documents
3578 : /* FIXME: ISERROR(#REF!) would be valid and true and the formula to
3579 : * be processed as usual. That would need some special treatment,
3580 : * also in NextSymbol() because of possible combinations of
3581 : * #REF!.#REF!#REF! parts. In case of reading ODF that is all
3582 : * handled by IsPredetectedReference(), this case here remains for
3583 : * manual/API input. */
3584 0 : String aBad( aFormula.Copy( nSrcPos-1 ) );
3585 0 : eLastOp = pArr->AddBad( aBad )->GetOpCode();
3586 0 : return false;
3587 : }
3588 :
3589 6396 : if( IsString() )
3590 202 : return true;
3591 :
3592 : bool bMayBeFuncName;
3593 : bool bAsciiNonAlnum; // operators, separators, ...
3594 6194 : if ( cSymbol[0] < 128 )
3595 : {
3596 6194 : bMayBeFuncName = CharClass::isAsciiAlpha( cSymbol[0] );
3597 6194 : bAsciiNonAlnum = !bMayBeFuncName && !CharClass::isAsciiDigit( cSymbol[0] );
3598 : }
3599 : else
3600 : {
3601 0 : rtl::OUString aTmpStr( cSymbol[0] );
3602 0 : bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 );
3603 0 : bAsciiNonAlnum = false;
3604 : }
3605 6194 : if ( bMayBeFuncName )
3606 : {
3607 : // a function name must be followed by a parenthesis
3608 1788 : const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos;
3609 3576 : while( *p == ' ' )
3610 0 : p++;
3611 1788 : bMayBeFuncName = ( *p == '(' );
3612 : }
3613 :
3614 : // Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
3615 : // IsReference().
3616 :
3617 6194 : String aUpper;
3618 :
3619 16 : do
3620 : {
3621 6194 : mbRewind = false;
3622 6194 : const rtl::OUString aOrg( cSymbol );
3623 :
3624 6194 : if (bAsciiNonAlnum)
3625 : {
3626 3536 : if (cSymbol[0] == '#')
3627 : {
3628 : // This can be only an error constant, if any.
3629 0 : lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
3630 0 : if (IsErrorConstant( aUpper))
3631 0 : return true;
3632 : break; // do; create ocBad token or set error.
3633 : }
3634 3536 : if (IsOpCode( aOrg, bInArray ))
3635 3190 : return true;
3636 : }
3637 :
3638 3004 : aUpper.Erase();
3639 3004 : bool bAsciiUpper = false;
3640 3004 : if (bMayBeFuncName)
3641 : {
3642 1066 : bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
3643 1066 : if (IsOpCode( aUpper, bInArray ))
3644 1064 : return true;
3645 : }
3646 :
3647 : // Column 'DM' ("Deutsche Mark", German currency) couldn't be
3648 : // referred => IsReference() before IsValue().
3649 : // Preserve case of file names in external references.
3650 1940 : if (IsReference( aOrg ))
3651 : {
3652 968 : if (mbRewind) // Range operator, but no direct reference.
3653 0 : continue; // do; up to range operator.
3654 : // If a syntactically correct reference was recognized but invalid
3655 : // e.g. because of non-existing sheet name => entire reference
3656 : // ocBad to preserve input instead of #REF!.A1
3657 968 : if (!pRawToken->IsValidReference())
3658 : {
3659 0 : aUpper = aOrg; // ensure for ocBad
3660 : break; // do; create ocBad token or set error.
3661 : }
3662 968 : return true;
3663 : }
3664 :
3665 972 : if (!aUpper.Len())
3666 970 : bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
3667 :
3668 : // IsBoolean() before IsValue() to catch inline bools without the kludge
3669 : // for inline arrays.
3670 972 : if (bAllowBooleans && IsBoolean( aUpper ))
3671 0 : return true;
3672 :
3673 972 : if (IsValue( aUpper ))
3674 870 : return true;
3675 :
3676 : // User defined names and such do need i18n upper also in ODF.
3677 102 : if (bAsciiUpper)
3678 70 : aUpper = ScGlobal::pCharClass->uppercase( aOrg );
3679 :
3680 102 : if (IsNamedRange( aUpper ))
3681 82 : return true;
3682 : // Preserve case of file names in external references.
3683 20 : if (IsExternalNamedRange( aOrg ))
3684 0 : return true;
3685 20 : if (IsDBRange( aUpper ))
3686 4 : return true;
3687 16 : if (IsColRowName( aUpper ))
3688 0 : return true;
3689 16 : if (bMayBeFuncName && IsMacro( aUpper ))
3690 0 : return true;
3691 16 : if (bMayBeFuncName && IsOpCode2( aUpper ))
3692 0 : return true;
3693 :
3694 : } while (mbRewind);
3695 :
3696 16 : if ( meExtendedErrorDetection != EXTENDED_ERROR_DETECTION_NONE )
3697 : {
3698 : // set an error
3699 2 : SetError( errNoName );
3700 2 : if (meExtendedErrorDetection == EXTENDED_ERROR_DETECTION_NAME_BREAK)
3701 0 : return false; // end compilation
3702 : }
3703 :
3704 : // Provide single token information and continue. Do not set an error, that
3705 : // would prematurely end compilation. Simple unknown names are handled by
3706 : // the interpreter.
3707 16 : aUpper = ScGlobal::pCharClass->lowercase( aUpper );
3708 16 : ScRawToken aToken;
3709 16 : aToken.SetString( aUpper.GetBuffer() );
3710 16 : aToken.NewOpCode( ocBad );
3711 16 : pRawToken = aToken.Clone();
3712 16 : if ( bAutoCorrect )
3713 0 : AutoCorrectParsedSymbol();
3714 16 : return true;
3715 : }
3716 :
3717 734 : void ScCompiler::CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp )
3718 : {
3719 734 : bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL;
3720 734 : sal_uInt16 nExpectedCount = bExternal ? 2 : 1;
3721 : OSL_ENSURE( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
3722 734 : if( pArr->GetLen() == nExpectedCount )
3723 : {
3724 734 : FormulaToken** ppTokens = pArr->GetArray();
3725 : // string tokens expected, GetString() will assert if token type is wrong
3726 734 : rFormula = ppTokens[ 0 ]->GetString();
3727 734 : if( bExternal )
3728 0 : rFormulaNmsp = ppTokens[ 1 ]->GetString();
3729 : }
3730 734 : }
3731 :
3732 734 : void ScCompiler::CreateStringFromXMLTokenArray( rtl::OUString& rFormula, rtl::OUString& rFormulaNmsp )
3733 : {
3734 734 : String sFormula, aFormulaNmsp;
3735 734 : CreateStringFromXMLTokenArray(sFormula, aFormulaNmsp);
3736 734 : rFormula = sFormula;
3737 734 : rFormulaNmsp = aFormulaNmsp;
3738 734 : }
3739 :
3740 1636 : ScTokenArray* ScCompiler::CompileString( const String& rFormula )
3741 : {
3742 : OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
3743 1636 : if( meGrammar == FormulaGrammar::GRAM_EXTERNAL )
3744 0 : SetGrammar( FormulaGrammar::GRAM_PODF );
3745 :
3746 1636 : ScTokenArray aArr;
3747 1636 : pArr = &aArr;
3748 1636 : aFormula = comphelper::string::strip(rFormula, ' ');
3749 :
3750 1636 : nSrcPos = 0;
3751 1636 : bCorrected = false;
3752 1636 : if ( bAutoCorrect )
3753 : {
3754 0 : aCorrectedFormula.Erase();
3755 0 : aCorrectedSymbol.Erase();
3756 : }
3757 1636 : sal_uInt8 nForced = 0; // ==formula forces recalc even if cell is not visible
3758 1636 : if( aFormula.GetChar(nSrcPos) == '=' )
3759 : {
3760 1184 : nSrcPos++;
3761 1184 : nForced++;
3762 1184 : if ( bAutoCorrect )
3763 0 : aCorrectedFormula += '=';
3764 : }
3765 1636 : if( aFormula.GetChar(nSrcPos) == '=' )
3766 : {
3767 0 : nSrcPos++;
3768 0 : nForced++;
3769 0 : if ( bAutoCorrect )
3770 0 : aCorrectedFormula += '=';
3771 : }
3772 : struct FunctionStack
3773 : {
3774 : OpCode eOp;
3775 : short nPar;
3776 : };
3777 : // FunctionStack only used if PODF!
3778 1636 : bool bPODF = FormulaGrammar::isPODF( meGrammar);
3779 1636 : const size_t nAlloc = 512;
3780 : FunctionStack aFuncs[ nAlloc ];
3781 32 : FunctionStack* pFunctionStack = (bPODF && rFormula.Len() > nAlloc ?
3782 1668 : new FunctionStack[ rFormula.Len() ] : &aFuncs[0]);
3783 1636 : pFunctionStack[0].eOp = ocNone;
3784 1636 : pFunctionStack[0].nPar = 0;
3785 1636 : size_t nFunction = 0;
3786 1636 : short nBrackets = 0;
3787 1636 : bool bInArray = false;
3788 1636 : eLastOp = ocOpen;
3789 9964 : while( NextNewToken( bInArray ) )
3790 : {
3791 6692 : const OpCode eOp = pRawToken->GetOpCode();
3792 6692 : if (eOp == ocSkip)
3793 0 : continue;
3794 :
3795 6692 : switch (eOp)
3796 : {
3797 : case ocOpen:
3798 : {
3799 1066 : ++nBrackets;
3800 1066 : if (bPODF)
3801 : {
3802 0 : ++nFunction;
3803 0 : pFunctionStack[ nFunction ].eOp = eLastOp;
3804 0 : pFunctionStack[ nFunction ].nPar = 0;
3805 : }
3806 : }
3807 1066 : break;
3808 : case ocClose:
3809 : {
3810 1064 : if( !nBrackets )
3811 : {
3812 0 : SetError( errPairExpected );
3813 0 : if ( bAutoCorrect )
3814 : {
3815 0 : bCorrected = true;
3816 0 : aCorrectedSymbol.Erase();
3817 : }
3818 : }
3819 : else
3820 1064 : nBrackets--;
3821 1064 : if (bPODF && nFunction)
3822 0 : --nFunction;
3823 : }
3824 1064 : break;
3825 : case ocSep:
3826 : {
3827 692 : if (bPODF)
3828 0 : ++pFunctionStack[ nFunction ].nPar;
3829 : }
3830 692 : break;
3831 : case ocArrayOpen:
3832 : {
3833 10 : if( bInArray )
3834 0 : SetError( errNestedArray );
3835 : else
3836 10 : bInArray = true;
3837 : // Don't count following column separator as parameter separator.
3838 10 : if (bPODF)
3839 : {
3840 0 : ++nFunction;
3841 0 : pFunctionStack[ nFunction ].eOp = eOp;
3842 0 : pFunctionStack[ nFunction ].nPar = 0;
3843 : }
3844 : }
3845 10 : break;
3846 : case ocArrayClose:
3847 : {
3848 10 : if( bInArray )
3849 : {
3850 10 : bInArray = false;
3851 : }
3852 : else
3853 : {
3854 0 : SetError( errPairExpected );
3855 0 : if ( bAutoCorrect )
3856 : {
3857 0 : bCorrected = true;
3858 0 : aCorrectedSymbol.Erase();
3859 : }
3860 : }
3861 10 : if (bPODF && nFunction)
3862 0 : --nFunction;
3863 : }
3864 : default:
3865 3860 : break;
3866 : }
3867 6692 : if( (eLastOp == ocSep ||
3868 : eLastOp == ocArrayRowSep ||
3869 : eLastOp == ocArrayColSep ||
3870 : eLastOp == ocArrayOpen) &&
3871 : (eOp == ocSep ||
3872 : eOp == ocClose ||
3873 : eOp == ocArrayRowSep ||
3874 : eOp == ocArrayColSep ||
3875 : eOp == ocArrayClose) )
3876 : {
3877 : // FIXME: should we check for known functions with optional empty
3878 : // args so the correction dialog can do better?
3879 12 : if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) )
3880 : {
3881 0 : SetError(errCodeOverflow); break;
3882 : }
3883 : }
3884 6692 : if (bPODF)
3885 : {
3886 : /* TODO: for now this is the only PODF adapter. If there were more,
3887 : * factor this out. */
3888 : // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
3889 32 : if (eOp == ocSep &&
3890 0 : pFunctionStack[ nFunction ].eOp == ocAddress &&
3891 0 : pFunctionStack[ nFunction ].nPar == 3)
3892 : {
3893 0 : if (!static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep,ocSep)) ||
3894 0 : !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
3895 : {
3896 0 : SetError(errCodeOverflow); break;
3897 : }
3898 0 : ++pFunctionStack[ nFunction ].nPar;
3899 : }
3900 : }
3901 6692 : FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( pRawToken->CreateToken());
3902 6692 : if (!pNewToken)
3903 : {
3904 0 : SetError(errCodeOverflow); break;
3905 : }
3906 6692 : else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush &&
3907 0 : pNewToken->GetType() == svSingleRef)
3908 0 : static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos);
3909 6692 : eLastOp = pRawToken->GetOpCode();
3910 6692 : if ( bAutoCorrect )
3911 0 : aCorrectedFormula += aCorrectedSymbol;
3912 : }
3913 1636 : if ( mbCloseBrackets )
3914 : {
3915 1636 : if( bInArray )
3916 : {
3917 0 : FormulaByteToken aToken( ocArrayClose );
3918 0 : if( !pArr->AddToken( aToken ) )
3919 : {
3920 0 : SetError(errCodeOverflow);
3921 : }
3922 0 : else if ( bAutoCorrect )
3923 0 : aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose);
3924 : }
3925 :
3926 1636 : FormulaByteToken aToken( ocClose );
3927 3274 : while( nBrackets-- )
3928 : {
3929 2 : if( !pArr->AddToken( aToken ) )
3930 : {
3931 0 : SetError(errCodeOverflow); break;
3932 : }
3933 2 : if ( bAutoCorrect )
3934 0 : aCorrectedFormula += mxSymbols->getSymbol(ocClose);
3935 1636 : }
3936 : }
3937 1636 : if ( nForced >= 2 )
3938 0 : pArr->SetRecalcModeForced();
3939 :
3940 1636 : if (pFunctionStack != &aFuncs[0])
3941 0 : delete [] pFunctionStack;
3942 :
3943 : // remember pArr, in case a subsequent CompileTokenArray() is executed.
3944 1636 : ScTokenArray* pNew = new ScTokenArray( aArr );
3945 1636 : pArr = pNew;
3946 1636 : return pNew;
3947 : }
3948 :
3949 :
3950 792 : ScTokenArray* ScCompiler::CompileString( const String& rFormula, const String& rFormulaNmsp )
3951 : {
3952 : OSL_ENSURE( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || (rFormulaNmsp.Len() == 0),
3953 : "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
3954 792 : if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try
3955 : {
3956 0 : ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool();
3957 0 : uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW );
3958 0 : table::CellAddress aReferencePos;
3959 0 : ScUnoConversion::FillApiAddress( aReferencePos, aPos );
3960 0 : uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos );
3961 0 : ScTokenArray aTokenArray;
3962 0 : if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) )
3963 : {
3964 : // remember pArr, in case a subsequent CompileTokenArray() is executed.
3965 0 : ScTokenArray* pNew = new ScTokenArray( aTokenArray );
3966 0 : pArr = pNew;
3967 0 : return pNew;
3968 0 : }
3969 : }
3970 0 : catch( uno::Exception& )
3971 : {
3972 : }
3973 : // no success - fallback to some internal grammar and hope the best
3974 792 : return CompileString( rFormula );
3975 : }
3976 :
3977 :
3978 370 : ScRangeData* ScCompiler::GetRangeData( const FormulaToken& rToken ) const
3979 : {
3980 370 : ScRangeData* pRangeData = NULL;
3981 370 : bool bGlobal = rToken.IsGlobal();
3982 370 : if (bGlobal)
3983 : // global named range.
3984 314 : pRangeData = pDoc->GetRangeName()->findByIndex( rToken.GetIndex());
3985 : else
3986 : {
3987 : // sheet local named range.
3988 56 : const ScRangeName* pRN = pDoc->GetRangeName( aPos.Tab());
3989 56 : if (pRN)
3990 56 : pRangeData = pRN->findByIndex( rToken.GetIndex());
3991 : }
3992 370 : return pRangeData;
3993 : }
3994 :
3995 :
3996 318 : bool ScCompiler::HandleRange()
3997 : {
3998 318 : const ScRangeData* pRangeData = GetRangeData( *mpToken);
3999 318 : if (pRangeData)
4000 : {
4001 318 : sal_uInt16 nErr = pRangeData->GetErrCode();
4002 318 : if( nErr )
4003 0 : SetError( errNoName );
4004 318 : else if ( !bCompileForFAP )
4005 : {
4006 : ScTokenArray* pNew;
4007 : // put named formula into parentheses.
4008 : // But only if there aren't any yet, parenthetical
4009 : // ocSep doesn't work, e.g. SUM((...;...))
4010 : // or if not directly between ocSep/parenthesis,
4011 : // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
4012 : // in short: if it isn't a self-contained expression.
4013 318 : FormulaToken* p1 = pArr->PeekPrevNoSpaces();
4014 318 : FormulaToken* p2 = pArr->PeekNextNoSpaces();
4015 318 : OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) );
4016 318 : OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) );
4017 318 : bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
4018 318 : bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose);
4019 318 : bool bAddPair = !(bBorder1 && bBorder2);
4020 318 : if ( bAddPair )
4021 : {
4022 20 : pNew = new ScTokenArray();
4023 20 : pNew->AddOpCode( ocClose );
4024 20 : PushTokenArray( pNew, true );
4025 20 : pNew->Reset();
4026 : }
4027 318 : pNew = pRangeData->GetCode()->Clone();
4028 318 : PushTokenArray( pNew, true );
4029 318 : if( pRangeData->HasReferences() )
4030 : {
4031 306 : SetRelNameReference();
4032 306 : MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
4033 : }
4034 318 : pNew->Reset();
4035 318 : if ( bAddPair )
4036 : {
4037 20 : pNew = new ScTokenArray();
4038 20 : pNew->AddOpCode( ocOpen );
4039 20 : PushTokenArray( pNew, true );
4040 20 : pNew->Reset();
4041 : }
4042 318 : return GetToken();
4043 : }
4044 : }
4045 : else
4046 0 : SetError(errNoName);
4047 0 : return true;
4048 : }
4049 : // -----------------------------------------------------------------------------
4050 68 : bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)
4051 : {
4052 : // Handle external range names.
4053 68 : switch (_aToken.GetType())
4054 : {
4055 : case svExternalSingleRef:
4056 : case svExternalDoubleRef:
4057 68 : pArr->IncrementRefs();
4058 68 : break;
4059 : case svExternalName:
4060 : {
4061 0 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
4062 0 : const OUString* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex());
4063 0 : if (!pFile)
4064 : {
4065 0 : SetError(errNoName);
4066 0 : return true;
4067 : }
4068 :
4069 0 : const String& rName = _aToken.GetString();
4070 : ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens(
4071 0 : _aToken.GetIndex(), rName, &aPos);
4072 :
4073 0 : if (!xNew)
4074 : {
4075 0 : SetError(errNoName);
4076 0 : return true;
4077 : }
4078 :
4079 0 : ScTokenArray* pNew = xNew->Clone();
4080 0 : PushTokenArray( pNew, true);
4081 0 : if (pNew->GetNextReference() != NULL)
4082 : {
4083 0 : SetRelNameReference();
4084 0 : MoveRelWrap(MAXCOL, MAXROW);
4085 : }
4086 0 : pNew->Reset();
4087 0 : return GetToken();
4088 : }
4089 : default:
4090 : OSL_FAIL("Wrong type for external reference!");
4091 0 : return false;
4092 : }
4093 68 : return true;
4094 : }
4095 :
4096 :
4097 : //---------------------------------------------------------------------------
4098 :
4099 :
4100 : //---------------------------------------------------------------------------
4101 : // Append token to RPN code
4102 : //---------------------------------------------------------------------------
4103 :
4104 :
4105 : //-----------------------------------------------------------------------------
4106 :
4107 : //---------------------------------------------------------------------------
4108 : // RPN creation by recursion
4109 : //---------------------------------------------------------------------------
4110 :
4111 :
4112 :
4113 : //-----------------------------------------------------------------------------
4114 :
4115 42 : bool ScCompiler::HasModifiedRange()
4116 : {
4117 42 : pArr->Reset();
4118 122 : for ( FormulaToken* t = pArr->Next(); t; t = pArr->Next() )
4119 : {
4120 80 : OpCode eOpCode = t->GetOpCode();
4121 80 : if ( eOpCode == ocName )
4122 : {
4123 12 : const ScRangeData* pRangeData = GetRangeData( *t);
4124 12 : if (pRangeData && pRangeData->IsModified())
4125 0 : return true;
4126 : }
4127 68 : else if ( eOpCode == ocDBArea )
4128 : {
4129 0 : ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(t->GetIndex());
4130 0 : if (pDBData && pDBData->IsModified())
4131 0 : return true;
4132 : }
4133 : }
4134 42 : return false;
4135 : }
4136 :
4137 :
4138 : //---------------------------------------------------------------------------
4139 :
4140 : template< typename T, typename S >
4141 : static S lcl_adjval( S& n, T pos, T max, bool bRel )
4142 : {
4143 : max++;
4144 : if( bRel )
4145 : n = sal::static_int_cast<S>( n + pos );
4146 : if( n < 0 )
4147 : n = sal::static_int_cast<S>( n + max );
4148 : else if( n >= max )
4149 : n = sal::static_int_cast<S>( n - max );
4150 : if( bRel )
4151 : n = sal::static_int_cast<S>( n - pos );
4152 : return n;
4153 : }
4154 :
4155 : // reference of named range with relative references
4156 :
4157 306 : void ScCompiler::SetRelNameReference()
4158 : {
4159 306 : pArr->Reset();
4160 844 : for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t;
4161 538 : t = static_cast<ScToken*>(pArr->GetNextReference()) )
4162 : {
4163 538 : ScSingleRefData& rRef1 = t->GetSingleRef();
4164 538 : if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
4165 406 : rRef1.SetRelName( true );
4166 538 : if ( t->GetType() == svDoubleRef )
4167 : {
4168 10 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
4169 10 : if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
4170 0 : rRef2.SetRelName( true );
4171 : }
4172 : }
4173 306 : }
4174 :
4175 : // Wrap-adjust relative references of a RangeName to current position,
4176 : // don't call for other token arrays!
4177 336 : void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
4178 : {
4179 336 : pArr->Reset();
4180 904 : for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t;
4181 568 : t = static_cast<ScToken*>(pArr->GetNextReference()) )
4182 : {
4183 568 : if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
4184 546 : ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() );
4185 : else
4186 22 : ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, t->GetDoubleRef() );
4187 : }
4188 336 : }
4189 :
4190 : // Wrap-adjust relative references of a RangeName to current position,
4191 : // don't call for other token arrays!
4192 0 : void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos,
4193 : SCCOL nMaxCol, SCROW nMaxRow )
4194 : {
4195 0 : rArr.Reset();
4196 0 : for( ScToken* t = static_cast<ScToken*>(rArr.GetNextReference()); t;
4197 0 : t = static_cast<ScToken*>(rArr.GetNextReference()) )
4198 : {
4199 0 : if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
4200 0 : ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() );
4201 : else
4202 0 : ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, t->GetDoubleRef() );
4203 : }
4204 0 : }
4205 :
4206 42 : ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode,
4207 : const ScAddress& rOldPos, const ScRange& r,
4208 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
4209 : bool& rChanged, bool& rRefSizeChanged )
4210 : {
4211 42 : rChanged = rRefSizeChanged = false;
4212 42 : if ( eUpdateRefMode == URM_COPY )
4213 : { // Normally nothing has to be done here since RelRefs are used, also
4214 : // SharedFormulas don't need any special handling, except if they
4215 : // wrapped around sheet borders.
4216 : // But ColRowName tokens pointing to a ColRow header which was
4217 : // copied along with this formula need to be updated to point to the
4218 : // copied header instead of the old position's new intersection.
4219 : ScToken* t;
4220 34 : pArr->Reset();
4221 68 : while( (t = static_cast<ScToken*>(pArr->GetNextColRowName())) != NULL )
4222 : {
4223 0 : ScSingleRefData& rRef = t->GetSingleRef();
4224 0 : rRef.CalcAbsIfRel( rOldPos );
4225 0 : ScAddress aNewRef( rRef.nCol + nDx, rRef.nRow + nDy, rRef.nTab + nDz );
4226 0 : if ( r.In( aNewRef ) )
4227 : { // yes, this is URM_MOVE
4228 0 : if ( ScRefUpdate::Update( pDoc, URM_MOVE, aPos,
4229 : r, nDx, nDy, nDz,
4230 0 : SingleDoubleRefModifier( rRef ).Ref() )
4231 : != UR_NOTHING
4232 : )
4233 0 : rChanged = true;
4234 : }
4235 : }
4236 : // Check for SharedFormulas.
4237 34 : ScRangeData* pRangeData = NULL;
4238 34 : pArr->Reset();
4239 46 : for( FormulaToken* j = pArr->GetNextName(); j && !pRangeData;
4240 12 : j = pArr->GetNextName() )
4241 : {
4242 12 : if( j->GetOpCode() == ocName )
4243 : {
4244 12 : ScRangeData* pName = GetRangeData( *j);
4245 12 : if (pName && pName->HasType(RT_SHARED))
4246 0 : pRangeData = pName;
4247 : }
4248 : }
4249 : // Check SharedFormulas for wraps.
4250 34 : if (pRangeData)
4251 : {
4252 0 : ScRangeData* pName = pRangeData;
4253 0 : pRangeData = NULL;
4254 0 : pArr->Reset();
4255 0 : for( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()); t && !pRangeData;
4256 0 : t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) )
4257 : {
4258 0 : bool bRelName = (t->GetType() == svSingleRef ?
4259 0 : t->GetSingleRef().IsRelName() :
4260 0 : (t->GetDoubleRef().Ref1.IsRelName() ||
4261 0 : t->GetDoubleRef().Ref2.IsRelName()));
4262 0 : if (bRelName)
4263 : {
4264 0 : t->CalcAbsIfRel( rOldPos);
4265 0 : bool bValid = (t->GetType() == svSingleRef ?
4266 0 : t->GetSingleRef().Valid() :
4267 0 : t->GetDoubleRef().Valid());
4268 : // If the reference isn't valid, copying the formula
4269 : // wrapped it. Replace SharedFormula.
4270 0 : if (!bValid)
4271 : {
4272 0 : pRangeData = pName;
4273 0 : rChanged = true;
4274 : }
4275 : }
4276 : }
4277 : }
4278 34 : return pRangeData;
4279 : }
4280 : else
4281 : {
4282 : /*
4283 : * Set SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE to 1 if we wanted to preserve as
4284 : * many shared formulas as possible instead of replacing them with direct code.
4285 : * Note that this may produce shared formula usage Excel doesn't understand,
4286 : * which would have to be adapted for in the export filter. Advisable as a long
4287 : * term goal, since it could decrease memory footprint.
4288 : */
4289 : #define SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 0
4290 8 : ScRangeData* pRangeData = NULL;
4291 : ScToken* t;
4292 8 : pArr->Reset();
4293 24 : while( (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL )
4294 : {
4295 8 : if( t->GetOpCode() == ocName )
4296 : {
4297 0 : ScRangeData* pName = GetRangeData( *t);
4298 0 : if (pName && pName->HasType(RT_SHAREDMOD))
4299 : {
4300 0 : pRangeData = pName; // maybe need a replacement of shared with own code
4301 : #if ! SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4302 0 : rChanged = true;
4303 : #endif
4304 : }
4305 : }
4306 8 : else if( t->GetType() != svIndex ) // it may be a DB area!!!
4307 : {
4308 8 : t->CalcAbsIfRel( rOldPos );
4309 8 : switch (t->GetType())
4310 : {
4311 : case svExternalSingleRef:
4312 : case svExternalDoubleRef:
4313 : // External references never change their positioning
4314 : // nor point to parts that will be removed or expanded.
4315 : // In fact, calling ScRefUpdate::Update() for URM_MOVE
4316 : // may have negative side effects. Simply adapt
4317 : // relative references to the new position.
4318 0 : t->CalcRelFromAbs( aPos);
4319 0 : break;
4320 : case svSingleRef:
4321 : {
4322 16 : if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
4323 : aPos, r, nDx, nDy, nDz,
4324 : SingleDoubleRefModifier(
4325 16 : t->GetSingleRef()).Ref())
4326 : != UR_NOTHING)
4327 4 : rChanged = true;
4328 : }
4329 8 : break;
4330 : default:
4331 : {
4332 0 : ScComplexRefData& rRef = t->GetDoubleRef();
4333 0 : SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol;
4334 0 : SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow;
4335 0 : SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab;
4336 0 : if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
4337 : aPos, r, nDx, nDy, nDz,
4338 0 : t->GetDoubleRef()) != UR_NOTHING)
4339 : {
4340 0 : rChanged = true;
4341 0 : if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols ||
4342 : rRef.Ref2.nRow - rRef.Ref1.nRow != nRows ||
4343 : rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs)
4344 0 : rRefSizeChanged = true;
4345 : }
4346 : }
4347 : }
4348 : }
4349 : }
4350 : #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4351 : bool bEasyShared, bPosInRange;
4352 : if ( !pRangeData )
4353 : bEasyShared = bPosInRange = false;
4354 : else
4355 : {
4356 : bEasyShared = true;
4357 : bPosInRange = r.In( eUpdateRefMode == URM_MOVE ? aPos : rOldPos );
4358 : }
4359 : #endif
4360 8 : pArr->Reset();
4361 24 : while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
4362 : {
4363 8 : if ( t->GetRef() != 1 )
4364 : {
4365 : #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4366 : bEasyShared = false;
4367 : #endif
4368 : }
4369 : else
4370 : { // if nRefCnt>1 it's already updated in token code
4371 0 : if ( t->GetType() == svSingleRef )
4372 : {
4373 0 : ScSingleRefData& rRef = t->GetSingleRef();
4374 0 : SingleDoubleRefModifier aMod( rRef );
4375 0 : if ( rRef.IsRelName() )
4376 : {
4377 0 : ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, aMod.Ref() );
4378 0 : rChanged = true;
4379 : }
4380 : else
4381 : {
4382 0 : aMod.Ref().CalcAbsIfRel( rOldPos );
4383 0 : if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
4384 0 : r, nDx, nDy, nDz, aMod.Ref() )
4385 : != UR_NOTHING
4386 : )
4387 0 : rChanged = true;
4388 0 : }
4389 : #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4390 : if ( bEasyShared )
4391 : {
4392 : const ScSingleRefData& rSRD = aMod.Ref().Ref1;
4393 : ScAddress aRef( rSRD.nCol, rSRD.nRow, rSRD.nTab );
4394 : if ( r.In( aRef ) != bPosInRange )
4395 : bEasyShared = false;
4396 : }
4397 : #endif
4398 : }
4399 : else
4400 : {
4401 0 : ScComplexRefData& rRef = t->GetDoubleRef();
4402 0 : SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol;
4403 0 : SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow;
4404 0 : SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab;
4405 0 : if ( rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName() )
4406 : {
4407 0 : ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, rRef );
4408 0 : rChanged = true;
4409 : }
4410 : else
4411 : {
4412 0 : if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
4413 0 : r, nDx, nDy, nDz, rRef )
4414 : != UR_NOTHING
4415 : )
4416 : {
4417 0 : rChanged = true;
4418 0 : if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols ||
4419 : rRef.Ref2.nRow - rRef.Ref1.nRow != nRows ||
4420 : rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs)
4421 : {
4422 0 : rRefSizeChanged = true;
4423 : #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4424 : bEasyShared = false;
4425 : #endif
4426 : }
4427 : }
4428 : }
4429 : #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4430 : if ( bEasyShared )
4431 : {
4432 : ScRange aRef( rRef.Ref1.nCol, rRef.Ref1.nRow,
4433 : rRef.Ref1.nTab, rRef.Ref2.nCol, rRef.Ref2.nRow,
4434 : rRef.Ref2.nTab );
4435 : if ( r.In( aRef ) != bPosInRange )
4436 : bEasyShared = false;
4437 : }
4438 : #endif
4439 : }
4440 : }
4441 : }
4442 : #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4443 : if ( pRangeData )
4444 : {
4445 : if ( bEasyShared )
4446 : pRangeData = 0;
4447 : else
4448 : rChanged = true;
4449 : }
4450 : #endif
4451 : #undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4452 8 : return pRangeData;
4453 : }
4454 : }
4455 :
4456 2 : bool ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode,
4457 : const ScRange& r,
4458 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
4459 : bool& rChanged, bool bSharedFormula, bool bLocal)
4460 : {
4461 2 : bool bRelRef = false; // set if relative reference
4462 2 : rChanged = false;
4463 2 : pArr->Reset();
4464 : ScToken* t;
4465 6 : while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL )
4466 : {
4467 2 : SingleDoubleRefModifier aMod( *t );
4468 2 : ScComplexRefData& rRef = aMod.Ref();
4469 4 : bRelRef = rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() ||
4470 4 : rRef.Ref1.IsTabRel();
4471 2 : if (!bRelRef && t->GetType() == svDoubleRef)
4472 0 : bRelRef = rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() ||
4473 0 : rRef.Ref2.IsTabRel();
4474 2 : bool bUpdate = !rRef.Ref1.IsColRel() || !rRef.Ref1.IsRowRel() ||
4475 2 : !rRef.Ref1.IsTabRel();
4476 2 : if (!bUpdate && t->GetType() == svDoubleRef)
4477 0 : bUpdate = !rRef.Ref2.IsColRel() || !rRef.Ref2.IsRowRel() ||
4478 0 : !rRef.Ref2.IsTabRel();
4479 2 : if (!bSharedFormula && !bLocal)
4480 : {
4481 : // We cannot update names with sheet-relative references, they may
4482 : // be used on other sheets as well and the resulting reference
4483 : // would be wrong. This is a dilemma if col/row would need to be
4484 : // updated for the current usage.
4485 0 : bUpdate = bUpdate && !rRef.Ref1.IsTabRel() && !rRef.Ref2.IsTabRel();
4486 : }
4487 2 : if (bUpdate)
4488 : {
4489 2 : rRef.CalcAbsIfRel( aPos);
4490 2 : if (ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, r,
4491 2 : nDx, nDy, nDz, rRef, ScRefUpdate::ABSOLUTE)
4492 : != UR_NOTHING )
4493 0 : rChanged = true;
4494 : }
4495 2 : }
4496 2 : return bRelRef;
4497 : }
4498 :
4499 :
4500 0 : void ScCompiler::UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode,
4501 : const ScAddress& rOldPos, const ScRange& r,
4502 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
4503 : {
4504 0 : if ( eUpdateRefMode == URM_COPY )
4505 0 : return ;
4506 : else
4507 : {
4508 : ScToken* t;
4509 0 : pArr->Reset();
4510 0 : while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL )
4511 : {
4512 0 : if( t->GetType() != svIndex ) // it may be a DB area!!!
4513 : {
4514 0 : t->CalcAbsIfRel( rOldPos );
4515 : // Absolute references have been already adjusted in the named
4516 : // shared formula itself prior to breaking the shared formula
4517 : // and calling this function. Don't readjust them again.
4518 0 : SingleDoubleRefModifier aMod( *t );
4519 0 : ScComplexRefData& rRef = aMod.Ref();
4520 0 : ScComplexRefData aBkp = rRef;
4521 : ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
4522 0 : r, nDx, nDy, nDz, rRef );
4523 : // restore absolute parts
4524 0 : if ( !aBkp.Ref1.IsColRel() )
4525 : {
4526 0 : rRef.Ref1.nCol = aBkp.Ref1.nCol;
4527 0 : rRef.Ref1.nRelCol = aBkp.Ref1.nRelCol;
4528 0 : rRef.Ref1.SetColDeleted( aBkp.Ref1.IsColDeleted() );
4529 : }
4530 0 : if ( !aBkp.Ref1.IsRowRel() )
4531 : {
4532 0 : rRef.Ref1.nRow = aBkp.Ref1.nRow;
4533 0 : rRef.Ref1.nRelRow = aBkp.Ref1.nRelRow;
4534 0 : rRef.Ref1.SetRowDeleted( aBkp.Ref1.IsRowDeleted() );
4535 : }
4536 0 : if ( !aBkp.Ref1.IsTabRel() )
4537 : {
4538 0 : rRef.Ref1.nTab = aBkp.Ref1.nTab;
4539 0 : rRef.Ref1.nRelTab = aBkp.Ref1.nRelTab;
4540 0 : rRef.Ref1.SetTabDeleted( aBkp.Ref1.IsTabDeleted() );
4541 : }
4542 0 : if ( t->GetType() == svDoubleRef )
4543 : {
4544 0 : if ( !aBkp.Ref2.IsColRel() )
4545 : {
4546 0 : rRef.Ref2.nCol = aBkp.Ref2.nCol;
4547 0 : rRef.Ref2.nRelCol = aBkp.Ref2.nRelCol;
4548 0 : rRef.Ref2.SetColDeleted( aBkp.Ref2.IsColDeleted() );
4549 : }
4550 0 : if ( !aBkp.Ref2.IsRowRel() )
4551 : {
4552 0 : rRef.Ref2.nRow = aBkp.Ref2.nRow;
4553 0 : rRef.Ref2.nRelRow = aBkp.Ref2.nRelRow;
4554 0 : rRef.Ref2.SetRowDeleted( aBkp.Ref2.IsRowDeleted() );
4555 : }
4556 0 : if ( !aBkp.Ref2.IsTabRel() )
4557 : {
4558 0 : rRef.Ref2.nTab = aBkp.Ref2.nTab;
4559 0 : rRef.Ref2.nRelTab = aBkp.Ref2.nRelTab;
4560 0 : rRef.Ref2.SetTabDeleted( aBkp.Ref2.IsTabDeleted() );
4561 : }
4562 0 : }
4563 : }
4564 : }
4565 : }
4566 : }
4567 :
4568 :
4569 20 : ScRangeData* ScCompiler::UpdateInsertTab( SCTAB nTable, bool bIsName , SCTAB nNewSheets)
4570 : {
4571 20 : ScRangeData* pRangeData = NULL;
4572 20 : SCTAB nPosTab = aPos.Tab(); // _after_ incremented!
4573 20 : SCTAB nOldPosTab = ((nPosTab > nTable) ? (nPosTab - nNewSheets) : nPosTab);
4574 20 : bool bIsRel = false;
4575 : ScToken* t;
4576 20 : pArr->Reset();
4577 20 : if (bIsName)
4578 8 : t = static_cast<ScToken*>(pArr->GetNextReference());
4579 : else
4580 12 : t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
4581 72 : while( t )
4582 : {
4583 32 : if( t->GetOpCode() == ocName )
4584 : {
4585 0 : if (!bIsName)
4586 : {
4587 0 : ScRangeData* pName = GetRangeData( *t);
4588 0 : if (pName && pName->HasType(RT_SHAREDMOD))
4589 0 : pRangeData = pName;
4590 : }
4591 : }
4592 32 : else if( t->GetType() != svIndex ) // it may be a DB area!!!
4593 : {
4594 32 : if ( !(bIsName && t->GetSingleRef().IsTabRel()) )
4595 : { // of names only adjust absolute references
4596 30 : ScSingleRefData& rRef = t->GetSingleRef();
4597 30 : if ( rRef.IsTabRel() )
4598 : {
4599 24 : rRef.nTab = rRef.nRelTab + nOldPosTab;
4600 24 : if ( rRef.nTab < 0 )
4601 0 : rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap
4602 : }
4603 30 : if (nTable <= rRef.nTab)
4604 30 : rRef.nTab += nNewSheets;
4605 30 : rRef.nRelTab = rRef.nTab - nPosTab;
4606 : }
4607 : else
4608 2 : bIsRel = true;
4609 32 : if ( t->GetType() == svDoubleRef )
4610 : {
4611 0 : if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) )
4612 : { // of names only adjust absolute references
4613 0 : ScSingleRefData& rRef = t->GetDoubleRef().Ref2;
4614 0 : if ( rRef.IsTabRel() )
4615 : {
4616 0 : rRef.nTab = rRef.nRelTab + nOldPosTab;
4617 0 : if ( rRef.nTab < 0 )
4618 0 : rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap
4619 : }
4620 0 : if (nTable <= rRef.nTab)
4621 0 : rRef.nTab += nNewSheets;
4622 0 : rRef.nRelTab = rRef.nTab - nPosTab;
4623 : }
4624 : else
4625 0 : bIsRel = true;
4626 : }
4627 32 : if ( bIsName && bIsRel )
4628 2 : pRangeData = (ScRangeData*) this; // not dereferenced in rangenam
4629 : }
4630 32 : if (bIsName)
4631 8 : t = static_cast<ScToken*>(pArr->GetNextReference());
4632 : else
4633 24 : t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
4634 : }
4635 20 : if ( !bIsName )
4636 : {
4637 12 : pArr->Reset();
4638 48 : while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
4639 : {
4640 24 : if ( t->GetRef() == 1 )
4641 : {
4642 0 : ScSingleRefData& rRef1 = t->GetSingleRef();
4643 0 : if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) )
4644 : { // of names only adjust absolute references
4645 0 : if ( rRef1.IsTabRel() )
4646 : {
4647 0 : rRef1.nTab = rRef1.nRelTab + nOldPosTab;
4648 0 : if ( rRef1.nTab < 0 )
4649 0 : rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + pDoc->GetTableCount() ); // was a wrap
4650 : }
4651 0 : if (nTable <= rRef1.nTab)
4652 0 : rRef1.nTab += nNewSheets;
4653 0 : rRef1.nRelTab = rRef1.nTab - nPosTab;
4654 : }
4655 0 : if ( t->GetType() == svDoubleRef )
4656 : {
4657 0 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
4658 0 : if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) )
4659 : { // of names only adjust absolute references
4660 0 : if ( rRef2.IsTabRel() )
4661 : {
4662 0 : rRef2.nTab = rRef2.nRelTab + nOldPosTab;
4663 0 : if ( rRef2.nTab < 0 )
4664 0 : rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + pDoc->GetTableCount() ); // was a wrap
4665 : }
4666 0 : if (nTable <= rRef2.nTab)
4667 0 : rRef2.nTab += nNewSheets;
4668 0 : rRef2.nRelTab = rRef2.nTab - nPosTab;
4669 : }
4670 : }
4671 : }
4672 : }
4673 : }
4674 20 : return pRangeData;
4675 : }
4676 :
4677 140 : ScRangeData* ScCompiler::UpdateDeleteTab(SCTAB nTable, bool /* bIsMove */, bool bIsName,
4678 : bool& rChanged, SCTAB nSheets)
4679 : {
4680 140 : ScRangeData* pRangeData = NULL;
4681 : SCTAB nTab, nTab2;
4682 140 : SCTAB nPosTab = aPos.Tab(); // _after_ decremented!
4683 140 : SCTAB nOldPosTab = ((nPosTab >= nTable) ? (nPosTab + nSheets) : nPosTab);
4684 140 : rChanged = false;
4685 140 : bool bIsRel = false;
4686 : ScToken* t;
4687 140 : pArr->Reset();
4688 140 : if (bIsName)
4689 22 : t = static_cast<ScToken*>(pArr->GetNextReference());
4690 : else
4691 118 : t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
4692 514 : while( t )
4693 : {
4694 234 : if( t->GetOpCode() == ocName )
4695 : {
4696 16 : if (!bIsName)
4697 : {
4698 16 : ScRangeData* pName = GetRangeData( *t);
4699 16 : if (pName && pName->HasType(RT_SHAREDMOD))
4700 0 : pRangeData = pName;
4701 : }
4702 16 : rChanged = true;
4703 : }
4704 218 : else if( t->GetType() != svIndex ) // it may be a DB area!!!
4705 : {
4706 218 : if ( !(bIsName && t->GetSingleRef().IsTabRel()) )
4707 : { // of names only adjust absolute references
4708 218 : ScSingleRefData& rRef = t->GetSingleRef();
4709 218 : if ( rRef.IsTabRel() )
4710 172 : nTab = rRef.nTab = rRef.nRelTab + nOldPosTab;
4711 : else
4712 46 : nTab = rRef.nTab;
4713 218 : if ( nTable < nTab )
4714 : {
4715 44 : rRef.nTab = nTab - nSheets;
4716 44 : rChanged = true;
4717 : }
4718 174 : else if ( nTable == nTab )
4719 : {
4720 30 : if ( t->GetType() == svDoubleRef )
4721 : {
4722 0 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
4723 0 : if ( rRef2.IsTabRel() )
4724 0 : nTab2 = rRef2.nRelTab + nOldPosTab;
4725 : else
4726 0 : nTab2 = rRef2.nTab;
4727 0 : if ( nTab == nTab2
4728 0 : || (nTab+nSheets) >= pDoc->GetTableCount() )
4729 : {
4730 0 : rRef.nTab = MAXTAB+1;
4731 0 : rRef.SetTabDeleted( true );
4732 : }
4733 : // else: nTab later points to what's nTable+1 now
4734 : // => area shrunk
4735 : }
4736 : else
4737 : {
4738 30 : rRef.nTab = MAXTAB+1;
4739 30 : rRef.SetTabDeleted( true );
4740 : }
4741 30 : rChanged = true;
4742 : }
4743 218 : rRef.nRelTab = rRef.nTab - nPosTab;
4744 : }
4745 : else
4746 0 : bIsRel = true;
4747 218 : if ( t->GetType() == svDoubleRef )
4748 : {
4749 16 : if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) )
4750 : { // of names only adjust absolute references
4751 16 : ScSingleRefData& rRef = t->GetDoubleRef().Ref2;
4752 16 : if ( rRef.IsTabRel() )
4753 16 : nTab = rRef.nTab = rRef.nRelTab + nOldPosTab;
4754 : else
4755 0 : nTab = rRef.nTab;
4756 16 : if ( nTable < nTab )
4757 : {
4758 2 : rRef.nTab = nTab - nSheets;
4759 2 : rChanged = true;
4760 : }
4761 14 : else if ( nTable == nTab )
4762 : {
4763 0 : if ( !t->GetDoubleRef().Ref1.IsTabDeleted() )
4764 0 : rRef.nTab = nTab - nSheets; // shrink area
4765 : else
4766 : {
4767 0 : rRef.nTab = MAXTAB+1;
4768 0 : rRef.SetTabDeleted( true );
4769 : }
4770 0 : rChanged = true;
4771 : }
4772 16 : rRef.nRelTab = rRef.nTab - nPosTab;
4773 : }
4774 : else
4775 0 : bIsRel = true;
4776 : }
4777 218 : if ( bIsName && bIsRel )
4778 0 : pRangeData = (ScRangeData*) this; // not dereferenced in rangenam
4779 : }
4780 234 : if (bIsName)
4781 22 : t = static_cast<ScToken*>(pArr->GetNextReference());
4782 : else
4783 212 : t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
4784 : }
4785 140 : if ( !bIsName )
4786 : {
4787 118 : pArr->Reset();
4788 448 : while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
4789 : {
4790 212 : if ( t->GetRef() == 1 )
4791 : {
4792 16 : ScSingleRefData& rRef1 = t->GetSingleRef();
4793 16 : if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) )
4794 : { // of names only adjust absolute references
4795 16 : if ( rRef1.IsTabRel() )
4796 0 : nTab = rRef1.nTab = rRef1.nRelTab + nOldPosTab;
4797 : else
4798 16 : nTab = rRef1.nTab;
4799 16 : if ( nTable < nTab )
4800 : {
4801 4 : rRef1.nTab = nTab - nSheets;
4802 4 : rChanged = true;
4803 : }
4804 12 : else if ( nTable == nTab )
4805 : {
4806 0 : if ( t->GetType() == svDoubleRef )
4807 : {
4808 0 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
4809 0 : if ( rRef2.IsTabRel() )
4810 0 : nTab2 = rRef2.nRelTab + nOldPosTab;
4811 : else
4812 0 : nTab2 = rRef2.nTab;
4813 0 : if ( nTab == nTab2
4814 0 : || (nTab+1) >= pDoc->GetTableCount() )
4815 : {
4816 0 : rRef1.nTab = MAXTAB+1;
4817 0 : rRef1.SetTabDeleted( true );
4818 : }
4819 : // else: nTab later points to what's nTable+1 now
4820 : // => area shrunk
4821 : }
4822 : else
4823 : {
4824 0 : rRef1.nTab = MAXTAB+1;
4825 0 : rRef1.SetTabDeleted( true );
4826 : }
4827 0 : rChanged = true;
4828 : }
4829 16 : rRef1.nRelTab = rRef1.nTab - nPosTab;
4830 : }
4831 16 : if ( t->GetType() == svDoubleRef )
4832 : {
4833 0 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
4834 0 : if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) )
4835 : { // of names only adjust absolute references
4836 0 : if ( rRef2.IsTabRel() )
4837 0 : nTab = rRef2.nTab = rRef2.nRelTab + nOldPosTab;
4838 : else
4839 0 : nTab = rRef2.nTab;
4840 0 : if ( nTable < nTab )
4841 : {
4842 0 : rRef2.nTab = nTab - nSheets;
4843 0 : rChanged = true;
4844 : }
4845 0 : else if ( nTable == nTab )
4846 : {
4847 0 : if ( !rRef1.IsTabDeleted() )
4848 0 : rRef2.nTab = nTab - nSheets; // shrink area
4849 : else
4850 : {
4851 0 : rRef2.nTab = MAXTAB+1;
4852 0 : rRef2.SetTabDeleted( true );
4853 : }
4854 0 : rChanged = true;
4855 : }
4856 0 : rRef2.nRelTab = rRef2.nTab - nPosTab;
4857 : }
4858 : }
4859 : }
4860 : }
4861 : }
4862 140 : return pRangeData;
4863 : }
4864 :
4865 : // aPos.Tab() must be already adjusted!
4866 2 : ScRangeData* ScCompiler::UpdateMoveTab( SCTAB nOldTab, SCTAB nNewTab,
4867 : bool bIsName )
4868 : {
4869 2 : ScRangeData* pRangeData = NULL;
4870 : SCsTAB nTab;
4871 :
4872 : SCTAB nStart, nEnd;
4873 : short nDir; // direction in which others move
4874 2 : if ( nOldTab < nNewTab )
4875 : {
4876 0 : nDir = -1;
4877 0 : nStart = nOldTab;
4878 0 : nEnd = nNewTab;
4879 : }
4880 : else
4881 : {
4882 2 : nDir = 1;
4883 2 : nStart = nNewTab;
4884 2 : nEnd = nOldTab;
4885 : }
4886 2 : SCTAB nPosTab = aPos.Tab(); // current sheet
4887 : SCTAB nOldPosTab; // previously it was this one
4888 2 : if ( nPosTab == nNewTab )
4889 2 : nOldPosTab = nOldTab; // look, it's me!
4890 0 : else if ( nPosTab < nStart || nEnd < nPosTab )
4891 0 : nOldPosTab = nPosTab; // wasn't moved
4892 : else
4893 0 : nOldPosTab = nPosTab - nDir; // moved by one
4894 :
4895 2 : bool bIsRel = false;
4896 : ScToken* t;
4897 2 : pArr->Reset();
4898 2 : if (bIsName)
4899 2 : t = static_cast<ScToken*>(pArr->GetNextReference());
4900 : else
4901 0 : t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
4902 6 : while( t )
4903 : {
4904 2 : if( t->GetOpCode() == ocName )
4905 : {
4906 0 : if (!bIsName)
4907 : {
4908 0 : ScRangeData* pName = GetRangeData( *t);
4909 0 : if (pName && pName->HasType(RT_SHAREDMOD))
4910 0 : pRangeData = pName;
4911 : }
4912 : }
4913 2 : else if( t->GetType() != svIndex ) // it may be a DB area!!!
4914 : {
4915 2 : ScSingleRefData& rRef1 = t->GetSingleRef();
4916 2 : if ( !(bIsName && rRef1.IsTabRel()) )
4917 : { // of names only adjust absolute references
4918 2 : if ( rRef1.IsTabRel() )
4919 0 : nTab = rRef1.nRelTab + nOldPosTab;
4920 : else
4921 2 : nTab = rRef1.nTab;
4922 2 : if ( nTab == nOldTab )
4923 0 : rRef1.nTab = nNewTab;
4924 2 : else if ( nStart <= nTab && nTab <= nEnd )
4925 2 : rRef1.nTab = nTab + nDir;
4926 2 : rRef1.nRelTab = rRef1.nTab - nPosTab;
4927 : }
4928 : else
4929 0 : bIsRel = true;
4930 2 : if ( t->GetType() == svDoubleRef )
4931 : {
4932 2 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
4933 2 : if ( !(bIsName && rRef2.IsTabRel()) )
4934 : { // of names only adjust absolute references
4935 2 : if ( rRef2.IsTabRel() )
4936 0 : nTab = rRef2.nRelTab + nOldPosTab;
4937 : else
4938 2 : nTab = rRef2.nTab;
4939 2 : if ( nTab == nOldTab )
4940 0 : rRef2.nTab = nNewTab;
4941 2 : else if ( nStart <= nTab && nTab <= nEnd )
4942 2 : rRef2.nTab = nTab + nDir;
4943 2 : rRef2.nRelTab = rRef2.nTab - nPosTab;
4944 : }
4945 : else
4946 0 : bIsRel = true;
4947 : SCsTAB nTab1, nTab2;
4948 2 : if ( rRef1.IsTabRel() )
4949 0 : nTab1 = rRef1.nRelTab + nPosTab;
4950 : else
4951 2 : nTab1 = rRef1.nTab;
4952 2 : if ( rRef2.IsTabRel() )
4953 0 : nTab2 = rRef2.nRelTab + nPosTab;
4954 : else
4955 2 : nTab2 = rRef1.nTab;
4956 2 : if ( nTab2 < nTab1 )
4957 : { // PutInOrder
4958 0 : rRef1.nTab = nTab2;
4959 0 : rRef2.nTab = nTab1;
4960 0 : rRef1.nRelTab = rRef1.nTab - nPosTab;
4961 0 : rRef2.nRelTab = rRef2.nTab - nPosTab;
4962 : }
4963 : }
4964 2 : if ( bIsName && bIsRel )
4965 0 : pRangeData = (ScRangeData*) this; // not dereferenced in rangenam
4966 : }
4967 2 : if (bIsName)
4968 2 : t = static_cast<ScToken*>(pArr->GetNextReference());
4969 : else
4970 0 : t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
4971 : }
4972 2 : if ( !bIsName )
4973 : {
4974 0 : SCsTAB nMaxTabMod = (SCsTAB) pDoc->GetTableCount();
4975 0 : pArr->Reset();
4976 0 : while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
4977 : {
4978 0 : if ( t->GetRef() == 1 )
4979 : {
4980 0 : ScSingleRefData& rRef1 = t->GetSingleRef();
4981 0 : if ( rRef1.IsRelName() && rRef1.IsTabRel() )
4982 : { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
4983 0 : nTab = rRef1.nRelTab + nPosTab;
4984 0 : if ( nTab < 0 )
4985 0 : nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod );
4986 0 : else if ( nTab > nMaxTab )
4987 0 : nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod );
4988 0 : rRef1.nRelTab = nTab - nPosTab;
4989 : }
4990 : else
4991 : {
4992 0 : if ( rRef1.IsTabRel() )
4993 0 : nTab = rRef1.nRelTab + nOldPosTab;
4994 : else
4995 0 : nTab = rRef1.nTab;
4996 0 : if ( nTab == nOldTab )
4997 0 : rRef1.nTab = nNewTab;
4998 0 : else if ( nStart <= nTab && nTab <= nEnd )
4999 0 : rRef1.nTab = nTab + nDir;
5000 0 : rRef1.nRelTab = rRef1.nTab - nPosTab;
5001 : }
5002 0 : if( t->GetType() == svDoubleRef )
5003 : {
5004 0 : ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
5005 0 : if ( rRef2.IsRelName() && rRef2.IsTabRel() )
5006 : { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
5007 0 : nTab = rRef2.nRelTab + nPosTab;
5008 0 : if ( nTab < 0 )
5009 0 : nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod );
5010 0 : else if ( nTab > nMaxTab )
5011 0 : nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod );
5012 0 : rRef2.nRelTab = nTab - nPosTab;
5013 : }
5014 : else
5015 : {
5016 0 : if ( rRef2.IsTabRel() )
5017 0 : nTab = rRef2.nRelTab + nOldPosTab;
5018 : else
5019 0 : nTab = rRef2.nTab;
5020 0 : if ( nTab == nOldTab )
5021 0 : rRef2.nTab = nNewTab;
5022 0 : else if ( nStart <= nTab && nTab <= nEnd )
5023 0 : rRef2.nTab = nTab + nDir;
5024 0 : rRef2.nRelTab = rRef2.nTab - nPosTab;
5025 : }
5026 : SCsTAB nTab1, nTab2;
5027 0 : if ( rRef1.IsTabRel() )
5028 0 : nTab1 = rRef1.nRelTab + nPosTab;
5029 : else
5030 0 : nTab1 = rRef1.nTab;
5031 0 : if ( rRef2.IsTabRel() )
5032 0 : nTab2 = rRef2.nRelTab + nPosTab;
5033 : else
5034 0 : nTab2 = rRef1.nTab;
5035 0 : if ( nTab2 < nTab1 )
5036 : { // PutInOrder
5037 0 : rRef1.nTab = nTab2;
5038 0 : rRef2.nTab = nTab1;
5039 0 : rRef1.nRelTab = rRef1.nTab - nPosTab;
5040 0 : rRef2.nRelTab = rRef2.nTab - nPosTab;
5041 : }
5042 : }
5043 : }
5044 : }
5045 : }
5046 2 : return pRangeData;
5047 : }
5048 :
5049 :
5050 8 : void ScCompiler::CreateStringFromExternal(rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP)
5051 : {
5052 8 : FormulaToken* t = pTokenP;
5053 8 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
5054 8 : switch (t->GetType())
5055 : {
5056 : case svExternalName:
5057 : {
5058 0 : const OUString *pStr = pRefMgr->getExternalFileName(t->GetIndex());
5059 0 : OUString aFileName = pStr ? *pStr : OUString(ScGlobal::GetRscString(STR_NO_NAME_REF));
5060 0 : rBuffer.append(pConv->makeExternalNameStr( aFileName, t->GetString()));
5061 : }
5062 0 : break;
5063 : case svExternalSingleRef:
5064 : pConv->makeExternalRefStr(
5065 8 : rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetSingleRef(), pRefMgr);
5066 8 : break;
5067 : case svExternalDoubleRef:
5068 : pConv->makeExternalRefStr(
5069 0 : rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetDoubleRef(), pRefMgr);
5070 0 : break;
5071 : default:
5072 : // warning, not error, otherwise we may end up with a never
5073 : // ending message box loop if this was the cursor cell to be redrawn.
5074 : OSL_FAIL("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
5075 : }
5076 8 : }
5077 :
5078 0 : void ScCompiler::CreateStringFromMatrix( rtl::OUStringBuffer& rBuffer,
5079 : FormulaToken* pTokenP)
5080 : {
5081 0 : const ScMatrix* pMatrix = static_cast<ScToken*>(pTokenP)->GetMatrix();
5082 : SCSIZE nC, nMaxC, nR, nMaxR;
5083 :
5084 0 : pMatrix->GetDimensions( nMaxC, nMaxR);
5085 :
5086 0 : rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) );
5087 0 : for( nR = 0 ; nR < nMaxR ; nR++)
5088 : {
5089 0 : if( nR > 0)
5090 : {
5091 0 : rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) );
5092 : }
5093 :
5094 0 : for( nC = 0 ; nC < nMaxC ; nC++)
5095 : {
5096 0 : if( nC > 0)
5097 : {
5098 0 : rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) );
5099 : }
5100 :
5101 0 : if( pMatrix->IsValue( nC, nR ) )
5102 : {
5103 0 : if (pMatrix->IsBoolean(nC, nR))
5104 0 : AppendBoolean(rBuffer, pMatrix->GetDouble(nC, nR) != 0.0);
5105 : else
5106 : {
5107 0 : sal_uInt16 nErr = pMatrix->GetError(nC, nR);
5108 0 : if (nErr)
5109 0 : rBuffer.append(ScGlobal::GetErrorString(nErr));
5110 : else
5111 0 : AppendDouble(rBuffer, pMatrix->GetDouble(nC, nR));
5112 : }
5113 : }
5114 0 : else if( pMatrix->IsEmpty( nC, nR ) )
5115 : ;
5116 0 : else if( pMatrix->IsString( nC, nR ) )
5117 0 : AppendString( rBuffer, pMatrix->GetString( nC, nR ) );
5118 : }
5119 : }
5120 0 : rBuffer.append( mxSymbols->getSymbol(ocArrayClose) );
5121 0 : }
5122 :
5123 296 : void ScCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
5124 : {
5125 296 : const OpCode eOp = _pTokenP->GetOpCode();
5126 296 : ScSingleRefData& rRef = static_cast<ScToken*>(_pTokenP)->GetSingleRef();
5127 : ScComplexRefData aRef;
5128 296 : aRef.Ref1 = aRef.Ref2 = rRef;
5129 296 : if ( eOp == ocColRowName )
5130 : {
5131 0 : rRef.CalcAbsIfRel( aPos );
5132 0 : if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) )
5133 : {
5134 0 : String aStr;
5135 0 : pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr );
5136 0 : EnQuote( aStr );
5137 0 : rBuffer.append(aStr);
5138 : }
5139 : else
5140 : {
5141 0 : rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
5142 0 : pConv->MakeRefStr (rBuffer, *this, aRef, true );
5143 : }
5144 : }
5145 : else
5146 296 : pConv->MakeRefStr( rBuffer, *this, aRef, true );
5147 296 : }
5148 : // -----------------------------------------------------------------------------
5149 188 : void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
5150 : {
5151 188 : pConv->MakeRefStr( rBuffer, *this, static_cast<ScToken*>(_pTokenP)->GetDoubleRef(), false );
5152 188 : }
5153 : // -----------------------------------------------------------------------------
5154 12 : void ScCompiler::CreateStringFromIndex(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
5155 : {
5156 12 : const OpCode eOp = _pTokenP->GetOpCode();
5157 12 : rtl::OUStringBuffer aBuffer;
5158 12 : switch ( eOp )
5159 : {
5160 : case ocName:
5161 : {
5162 12 : ScRangeData* pData = GetRangeData( *_pTokenP);
5163 12 : if (pData)
5164 : {
5165 12 : if (pData->HasType(RT_SHARED))
5166 0 : pData->UpdateSymbol( aBuffer, aPos, GetGrammar());
5167 : else
5168 12 : aBuffer.append(pData->GetName());
5169 : }
5170 : }
5171 12 : break;
5172 : case ocDBArea:
5173 : {
5174 0 : ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(_pTokenP->GetIndex());
5175 0 : if (pDBData)
5176 0 : aBuffer.append(pDBData->GetName());
5177 : }
5178 0 : break;
5179 : default:
5180 : ; // nothing
5181 : }
5182 12 : if ( aBuffer.getLength() )
5183 12 : rBuffer.append(aBuffer.makeStringAndClear());
5184 : else
5185 0 : rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
5186 12 : }
5187 : // -----------------------------------------------------------------------------
5188 0 : void ScCompiler::LocalizeString( String& rName )
5189 : {
5190 0 : ::rtl::OUString aName(rName);
5191 0 : ScGlobal::GetAddInCollection()->LocalizeString( aName );
5192 0 : rName = aName;
5193 0 : }
5194 : // -----------------------------------------------------------------------------
5195 :
5196 : // Put quotes around string if non-alphanumeric characters are contained,
5197 : // quote characters contained within are escaped by '\\'.
5198 0 : bool ScCompiler::EnQuote( String& rStr )
5199 : {
5200 0 : sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.Len() );
5201 0 : if ( !CharClass::isNumericType( nType )
5202 0 : && CharClass::isAlphaNumericType( nType ) )
5203 0 : return false;
5204 :
5205 0 : xub_StrLen nPos = 0;
5206 0 : while ( (nPos = rStr.Search( '\'', nPos)) != STRING_NOTFOUND )
5207 : {
5208 0 : rStr.Insert( '\\', nPos );
5209 0 : nPos += 2;
5210 : }
5211 0 : rStr.Insert( '\'', 0 );
5212 0 : rStr += '\'';
5213 0 : return true;
5214 : }
5215 :
5216 0 : sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const
5217 : {
5218 0 : return pConv->getSpecialSymbol(eType);
5219 : }
5220 :
5221 0 : void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const
5222 : {
5223 : // All known AddIn functions.
5224 0 : sheet::FormulaOpCodeMapEntry aEntry;
5225 0 : aEntry.Token.OpCode = ocExternal;
5226 :
5227 0 : ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
5228 0 : const long nCount = pColl->GetFuncCount();
5229 0 : for (long i=0; i < nCount; ++i)
5230 : {
5231 0 : const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
5232 0 : if (pFuncData)
5233 : {
5234 0 : if ( _bIsEnglish )
5235 : {
5236 0 : ::rtl::OUString aName;
5237 0 : if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
5238 0 : aEntry.Name = aName;
5239 : else
5240 0 : aEntry.Name = pFuncData->GetUpperName();
5241 : }
5242 : else
5243 0 : aEntry.Name = pFuncData->GetUpperLocal();
5244 0 : aEntry.Token.Data <<= ::rtl::OUString( pFuncData->GetOriginalName());
5245 0 : _rVec.push_back( aEntry);
5246 : }
5247 0 : }
5248 : // FIXME: what about those old non-UNO AddIns?
5249 0 : }
5250 : // -----------------------------------------------------------------------------
5251 0 : bool ScCompiler::HandleSingleRef()
5252 : {
5253 0 : ScSingleRefData& rRef = static_cast<ScToken*>(mpToken.get())->GetSingleRef();
5254 0 : rRef.CalcAbsIfRel( aPos );
5255 0 : if ( !rRef.Valid() )
5256 : {
5257 0 : SetError( errNoRef );
5258 0 : return true;
5259 : }
5260 0 : SCCOL nCol = rRef.nCol;
5261 0 : SCROW nRow = rRef.nRow;
5262 0 : SCTAB nTab = rRef.nTab;
5263 0 : ScAddress aLook( nCol, nRow, nTab );
5264 0 : bool bColName = rRef.IsColRel();
5265 0 : SCCOL nMyCol = aPos.Col();
5266 0 : SCROW nMyRow = aPos.Row();
5267 0 : bool bInList = false;
5268 0 : bool bValidName = false;
5269 : ScRangePairList* pRL = (bColName ?
5270 0 : pDoc->GetColNameRanges() : pDoc->GetRowNameRanges());
5271 0 : ScRange aRange;
5272 0 : for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
5273 : {
5274 0 : ScRangePair* pR = (*pRL)[i];
5275 0 : if ( pR->GetRange(0).In( aLook ) )
5276 : {
5277 0 : bInList = bValidName = true;
5278 0 : aRange = pR->GetRange(1);
5279 0 : if ( bColName )
5280 : {
5281 0 : aRange.aStart.SetCol( nCol );
5282 0 : aRange.aEnd.SetCol( nCol );
5283 : }
5284 : else
5285 : {
5286 0 : aRange.aStart.SetRow( nRow );
5287 0 : aRange.aEnd.SetRow( nRow );
5288 : }
5289 0 : break; // for
5290 : }
5291 : }
5292 0 : if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
5293 : { // automagically or created by copying and NamePos isn't in list
5294 0 : bool bString = pDoc->HasStringData( nCol, nRow, nTab );
5295 0 : if ( !bString && !pDoc->GetCell( aLook ) )
5296 0 : bString = true; // empty cell is ok
5297 0 : if ( bString )
5298 : { //! coresponds with ScInterpreter::ScColRowNameAuto()
5299 0 : bValidName = true;
5300 0 : if ( bColName )
5301 : { // ColName
5302 0 : SCROW nStartRow = nRow + 1;
5303 0 : if ( nStartRow > MAXROW )
5304 0 : nStartRow = MAXROW;
5305 0 : SCROW nMaxRow = MAXROW;
5306 0 : if ( nMyCol == nCol )
5307 : { // formula cell in same column
5308 0 : if ( nMyRow == nStartRow )
5309 : { // take remainder under name cell
5310 0 : nStartRow++;
5311 0 : if ( nStartRow > MAXROW )
5312 0 : nStartRow = MAXROW;
5313 : }
5314 0 : else if ( nMyRow > nStartRow )
5315 : { // from name cell down to formula cell
5316 0 : nMaxRow = nMyRow - 1;
5317 : }
5318 : }
5319 0 : for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
5320 : { // next defined ColNameRange below limits row
5321 0 : ScRangePair* pR = (*pRL)[i];
5322 0 : const ScRange& rRange = pR->GetRange(1);
5323 0 : if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() )
5324 : { // identical column range
5325 0 : SCROW nTmp = rRange.aStart.Row();
5326 0 : if ( nStartRow < nTmp && nTmp <= nMaxRow )
5327 0 : nMaxRow = nTmp - 1;
5328 : }
5329 : }
5330 0 : aRange.aStart.Set( nCol, nStartRow, nTab );
5331 0 : aRange.aEnd.Set( nCol, nMaxRow, nTab );
5332 : }
5333 : else
5334 : { // RowName
5335 0 : SCCOL nStartCol = nCol + 1;
5336 0 : if ( nStartCol > MAXCOL )
5337 0 : nStartCol = MAXCOL;
5338 0 : SCCOL nMaxCol = MAXCOL;
5339 0 : if ( nMyRow == nRow )
5340 : { // formula cell in same row
5341 0 : if ( nMyCol == nStartCol )
5342 : { // take remainder right from name cell
5343 0 : nStartCol++;
5344 0 : if ( nStartCol > MAXCOL )
5345 0 : nStartCol = MAXCOL;
5346 : }
5347 0 : else if ( nMyCol > nStartCol )
5348 : { // from name cell right to formula cell
5349 0 : nMaxCol = nMyCol - 1;
5350 : }
5351 : }
5352 0 : for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
5353 : { // next defined RowNameRange to the right limits column
5354 0 : ScRangePair* pR = (*pRL)[i];
5355 0 : const ScRange& rRange = pR->GetRange(1);
5356 0 : if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() )
5357 : { // identical row range
5358 0 : SCCOL nTmp = rRange.aStart.Col();
5359 0 : if ( nStartCol < nTmp && nTmp <= nMaxCol )
5360 0 : nMaxCol = nTmp - 1;
5361 : }
5362 : }
5363 0 : aRange.aStart.Set( nStartCol, nRow, nTab );
5364 0 : aRange.aEnd.Set( nMaxCol, nRow, nTab );
5365 : }
5366 : }
5367 : }
5368 0 : if ( bValidName )
5369 : {
5370 : // And now the magic to distinguish between a range and a single
5371 : // cell thereof, which is picked position-dependent of the formula
5372 : // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
5373 : // SingleRef matching the column/row of the formula cell is
5374 : // generated. A ocColRowName or ocIntersect as a neighbor results
5375 : // in a range. Special case: if label is valid for a single cell, a
5376 : // position independent SingleRef is generated.
5377 0 : bool bSingle = (aRange.aStart == aRange.aEnd);
5378 : bool bFound;
5379 0 : if ( bSingle )
5380 0 : bFound = true;
5381 : else
5382 : {
5383 0 : FormulaToken* p1 = pArr->PeekPrevNoSpaces();
5384 0 : FormulaToken* p2 = pArr->PeekNextNoSpaces();
5385 : // begin/end of a formula => single
5386 0 : OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd );
5387 0 : OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd );
5388 0 : if ( eOp1 != ocColRowName && eOp1 != ocIntersect
5389 : && eOp2 != ocColRowName && eOp2 != ocIntersect )
5390 : {
5391 0 : if ( (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) ||
5392 : (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP))
5393 0 : bSingle = true;
5394 : }
5395 0 : if ( bSingle )
5396 : { // column and/or row must match range
5397 0 : if ( bColName )
5398 : {
5399 0 : bFound = (aRange.aStart.Row() <= nMyRow
5400 0 : && nMyRow <= aRange.aEnd.Row());
5401 0 : if ( bFound )
5402 0 : aRange.aStart.SetRow( nMyRow );
5403 : }
5404 : else
5405 : {
5406 0 : bFound = (aRange.aStart.Col() <= nMyCol
5407 0 : && nMyCol <= aRange.aEnd.Col());
5408 0 : if ( bFound )
5409 0 : aRange.aStart.SetCol( nMyCol );
5410 : }
5411 : }
5412 : else
5413 0 : bFound = true;
5414 : }
5415 0 : if ( !bFound )
5416 0 : SetError(errNoRef);
5417 0 : else if ( !bCompileForFAP )
5418 : {
5419 0 : ScTokenArray* pNew = new ScTokenArray();
5420 0 : if ( bSingle )
5421 : {
5422 : ScSingleRefData aRefData;
5423 0 : aRefData.InitAddress( aRange.aStart );
5424 0 : if ( bColName )
5425 0 : aRefData.SetColRel( true );
5426 : else
5427 0 : aRefData.SetRowRel( true );
5428 0 : aRefData.CalcRelFromAbs( aPos );
5429 0 : pNew->AddSingleReference( aRefData );
5430 : }
5431 : else
5432 : {
5433 : ScComplexRefData aRefData;
5434 0 : aRefData.InitRange( aRange );
5435 0 : if ( bColName )
5436 : {
5437 0 : aRefData.Ref1.SetColRel( true );
5438 0 : aRefData.Ref2.SetColRel( true );
5439 : }
5440 : else
5441 : {
5442 0 : aRefData.Ref1.SetRowRel( true );
5443 0 : aRefData.Ref2.SetRowRel( true );
5444 : }
5445 0 : aRefData.CalcRelFromAbs( aPos );
5446 0 : if ( bInList )
5447 0 : pNew->AddDoubleReference( aRefData );
5448 : else
5449 : { // automagically
5450 0 : pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) );
5451 : }
5452 : }
5453 0 : PushTokenArray( pNew, true );
5454 0 : pNew->Reset();
5455 0 : return GetToken();
5456 : }
5457 : }
5458 : else
5459 0 : SetError(errNoName);
5460 0 : return true;
5461 : }
5462 : // -----------------------------------------------------------------------------
5463 4 : bool ScCompiler::HandleDbData()
5464 : {
5465 4 : ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(mpToken->GetIndex());
5466 4 : if ( !pDBData )
5467 0 : SetError(errNoName);
5468 4 : else if ( !bCompileForFAP )
5469 : {
5470 : ScComplexRefData aRefData;
5471 4 : aRefData.InitFlags();
5472 : pDBData->GetArea( (SCTAB&) aRefData.Ref1.nTab,
5473 : (SCCOL&) aRefData.Ref1.nCol,
5474 : (SCROW&) aRefData.Ref1.nRow,
5475 : (SCCOL&) aRefData.Ref2.nCol,
5476 4 : (SCROW&) aRefData.Ref2.nRow);
5477 4 : aRefData.Ref2.nTab = aRefData.Ref1.nTab;
5478 4 : aRefData.CalcRelFromAbs( aPos );
5479 4 : ScTokenArray* pNew = new ScTokenArray();
5480 4 : pNew->AddDoubleReference( aRefData );
5481 4 : PushTokenArray( pNew, true );
5482 4 : pNew->Reset();
5483 4 : return GetToken();
5484 : }
5485 0 : return true;
5486 : }
5487 :
5488 : // -----------------------------------------------------------------------------
5489 0 : FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef )
5490 : {
5491 0 : return ScToken::ExtendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef );
5492 102 : }
5493 :
5494 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|