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