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