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