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 <formulabase.hxx>
21 #include <rangelst.hxx>
22 #include <addressconverter.hxx>
23
24 #include <map>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/sheet/AddressConvention.hpp>
28 #include <com/sun/star/sheet/ReferenceFlags.hpp>
29 #include <com/sun/star/sheet/SingleReference.hpp>
30 #include <com/sun/star/sheet/ComplexReference.hpp>
31 #include <com/sun/star/sheet/FormulaLanguage.hpp>
32 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
33 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
34 #include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
35 #include <com/sun/star/sheet/XFormulaParser.hpp>
36 #include <rtl/strbuf.hxx>
37 #include <rtl/ustrbuf.hxx>
38 #include <osl/diagnose.h>
39 #include <sal/log.hxx>
40 #include <oox/core/filterbase.hxx>
41 #include <oox/helper/containerhelper.hxx>
42 #include <oox/helper/binaryinputstream.hxx>
43 #include <oox/token/properties.hxx>
44 #include <o3tl/typed_flags_set.hxx>
45
46 namespace {
47
48 enum class FuncFlags : sal_uInt16 {
49 NONE = 0x0000,
50 VOLATILE = 0x0001, /// Result is volatile (e.g. NOW() function).
51 IMPORTONLY = 0x0002, /// Only used in import filter.
52 EXPORTONLY = 0x0004, /// Only used in export filter.
53 MACROCALL = 0x0008, /// Function is stored as macro call in BIFF Excel (_xlfn. prefix). OOXML name MUST exist.
54 MACROCALLODF = 0x0010, /// ODF-only function stored as macro call in BIFF Excel (_xlfnodf. prefix). ODF name MUST exist.
55 EXTERNAL = 0x0020, /// Function is external in Calc.
56 MACROFUNC = 0x0040, /// Function is a macro-sheet function.
57 MACROCMD = 0x0080, /// Function is a macro-sheet command.
58 ALWAYSVAR = 0x0100, /// Function is always represented by a tFuncVar token.
59 PARAMPAIRS = 0x0200, /// Optional parameters are expected to appear in pairs.
60 MACROCALL_FN = 0x0400, /** Function is stored as macro call in Excel (_xlfn. prefix)
61 for OOXML. OOXML name MUST exist. Do not use without FuncFlags::MACROCALL. */
62 MACROCALL_NEW = MACROCALL | MACROCALL_FN, /** New Excel functions not
63 defined in OOXML, _xlfn. prefix in all formats. OOXML name
64 must exist. */
65 BIFFEXPORTONLY = 0x1000, /// Only used in BIFF binary export filter.
66 INTERNAL = 0x2000, /// Function is internal in Calc.
67 EUROTOOL = 0x4000, /// function of euro tool lib, FUNCLIB_EUROTOOL
68 };
69
70 }
71
72 namespace o3tl {
73 template<> struct typed_flags<FuncFlags> : is_typed_flags<FuncFlags, 0x77ff> {};
74 }
75
76 namespace oox::xls {
77
78 using namespace ::com::sun::star::lang;
79 using namespace ::com::sun::star::sheet;
80 using namespace ::com::sun::star::table;
81 using namespace ::com::sun::star::uno;
82
83 // reference helpers ==========================================================
84
BinSingleRef2d()85 BinSingleRef2d::BinSingleRef2d() :
86 mnCol( 0 ),
87 mnRow( 0 ),
88 mbColRel( false ),
89 mbRowRel( false )
90 {
91 }
92
setBiff12Data(sal_uInt16 nCol,sal_Int32 nRow,bool bRelativeAsOffset)93 void BinSingleRef2d::setBiff12Data( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset )
94 {
95 mnCol = nCol & BIFF12_TOK_REF_COLMASK;
96 mnRow = nRow & BIFF12_TOK_REF_ROWMASK;
97 mbColRel = getFlag( nCol, BIFF12_TOK_REF_COLREL );
98 mbRowRel = getFlag( nCol, BIFF12_TOK_REF_ROWREL );
99 if( bRelativeAsOffset && mbColRel && (mnCol > (BIFF12_TOK_REF_COLMASK >> 1)) )
100 mnCol -= (BIFF12_TOK_REF_COLMASK + 1);
101 if( bRelativeAsOffset && mbRowRel && (mnRow > (BIFF12_TOK_REF_ROWMASK >> 1)) )
102 mnRow -= (BIFF12_TOK_REF_ROWMASK + 1);
103 }
104
readBiff12Data(SequenceInputStream & rStrm,bool bRelativeAsOffset)105 void BinSingleRef2d::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
106 {
107 sal_Int32 nRow;
108 sal_uInt16 nCol;
109 nRow = rStrm.readInt32();
110 nCol = rStrm.readuInt16();
111 setBiff12Data( nCol, nRow, bRelativeAsOffset );
112 }
113
readBiff12Data(SequenceInputStream & rStrm,bool bRelativeAsOffset)114 void BinComplexRef2d::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
115 {
116 sal_Int32 nRow1, nRow2;
117 sal_uInt16 nCol1, nCol2;
118 nRow1 = rStrm.readInt32();
119 nRow2 = rStrm.readInt32();
120 nCol1 = rStrm.readuInt16();
121 nCol2 = rStrm.readuInt16();
122 maRef1.setBiff12Data( nCol1, nRow1, bRelativeAsOffset );
123 maRef2.setBiff12Data( nCol2, nRow2, bRelativeAsOffset );
124 }
125
126 // token vector, sequence =====================================================
127
ApiTokenVector()128 ApiTokenVector::ApiTokenVector()
129 : mvTokens()
130 {
131 }
132
append(sal_Int32 nOpCode)133 Any& ApiTokenVector::append( sal_Int32 nOpCode )
134 {
135 mvTokens.emplace_back();
136 mvTokens.back().OpCode = nOpCode;
137 return mvTokens.back().Data;
138 }
139
toSequence() const140 ApiTokenSequence ApiTokenVector::toSequence() const
141 {
142 return ContainerHelper::vectorToSequence( mvTokens );
143 }
144
145 // token sequence iterator ====================================================
146
ApiTokenIterator(const ApiTokenSequence & rTokens,sal_Int32 nSpacesOpCode)147 ApiTokenIterator::ApiTokenIterator( const ApiTokenSequence& rTokens, sal_Int32 nSpacesOpCode ) :
148 mpToken( rTokens.getConstArray() ),
149 mpTokenEnd( rTokens.getConstArray() + rTokens.getLength() ),
150 mnSpacesOpCode( nSpacesOpCode )
151 {
152 skipSpaces();
153 }
154
operator ++()155 ApiTokenIterator& ApiTokenIterator::operator++()
156 {
157 if( is() )
158 {
159 ++mpToken;
160 skipSpaces();
161 }
162 return *this;
163 }
164
skipSpaces()165 void ApiTokenIterator::skipSpaces()
166 {
167 while( is() && (mpToken->OpCode == mnSpacesOpCode) )
168 ++mpToken;
169 }
170
171 // function data ==============================================================
172
173 namespace {
174
175 const size_t FUNCINFO_PARAMINFOCOUNT = 5; /// Number of parameter type entries.
176
177 typedef std::shared_ptr< FunctionInfo > FunctionInfoRef;
178
179 struct FunctionData
180 {
181 const char* mpcOdfFuncName; /// ODF function name.
182 const char* mpcOoxFuncName; /// OOXML function name.
183 sal_uInt16 mnBiff12FuncId; /// BIFF12 function identifier.
184 sal_uInt16 mnBiffFuncId; /// BIFF2-BIFF8 function identifier.
185 sal_uInt8 mnMinParamCount; /// Minimum number of parameters.
186 sal_uInt8 mnMaxParamCount; /// Maximum number of parameters.
187 sal_uInt8 mnRetClass; /// BIFF token class of the return value.
188 FunctionParamInfo mpParamInfos[ FUNCINFO_PARAMINFOCOUNT ]; /// Information about all parameters.
189 FuncFlags mnFlags; /// Additional flags.
190
191 bool isSupported(bool bImportFilter) const;
192 };
193
isSupported(bool bImportFilter) const194 bool FunctionData::isSupported(bool bImportFilter) const
195 {
196 /* For import filters: the FuncFlags::EXPORTONLY, FuncFlags::BIFFEXPORTONLY
197 must not be set.
198 For export filters: the FuncFlags::IMPORTONLY, FuncFlags::BIFFEXPORTONLY
199 must not be set. */
200 if (bImportFilter)
201 return !(mnFlags & ( FuncFlags::EXPORTONLY | FuncFlags::BIFFEXPORTONLY));
202 else
203 return !(mnFlags & ( FuncFlags::IMPORTONLY | FuncFlags::BIFFEXPORTONLY));
204 }
205
206 const sal_uInt16 NOID = SAL_MAX_UINT16; /// No BIFF function identifier available.
207 const sal_uInt8 MX = SAL_MAX_UINT8; /// Maximum parameter count.
208
209 // abbreviations for function return token class
210 const sal_uInt8 R = BIFF_TOKCLASS_REF;
211 const sal_uInt8 V = BIFF_TOKCLASS_VAL;
212 const sal_uInt8 A = BIFF_TOKCLASS_ARR;
213
214 // abbreviations for parameter infos
215 #define RO { FuncParamValidity::Regular }
216 #define RA { FuncParamValidity::Regular }
217 #define RR { FuncParamValidity::Regular }
218 #define RX { FuncParamValidity::Regular }
219 #define VO { FuncParamValidity::Regular }
220 #define VV { FuncParamValidity::Regular }
221 #define VA { FuncParamValidity::Regular }
222 #define VR { FuncParamValidity::Regular }
223 #define VX { FuncParamValidity::Regular }
224 #define RO_E { FuncParamValidity::ExcelOnly }
225 #define VR_E { FuncParamValidity::ExcelOnly }
226 #define C { FuncParamValidity::CalcOnly }
227
228 // Note: parameter types of all macro sheet functions (FuncFlags::MACROFUNC/FuncFlags::MACROCMD) untested!
229
230 /** Functions new in BIFF2. */
231 const FunctionData saFuncTableBiff2[] =
232 {
233 { "COUNT", "COUNT", 0, 0, 0, MX, V, { RX }, FuncFlags::NONE },
234 { "IF", "IF", 1, 1, 2, 3, R, { VO, RO }, FuncFlags::NONE },
235 { "ISNA", "ISNA", 2, 2, 1, 1, V, { VR }, FuncFlags::NONE },
236 { "ISERROR", "ISERROR", 3, 3, 1, 1, V, { VR }, FuncFlags::NONE },
237 { "SUM", "SUM", 4, 4, 0, MX, V, { RX }, FuncFlags::NONE },
238 { "AVERAGE", "AVERAGE", 5, 5, 1, MX, V, { RX }, FuncFlags::NONE },
239 { "MIN", "MIN", 6, 6, 1, MX, V, { RX }, FuncFlags::NONE },
240 { "MAX", "MAX", 7, 7, 1, MX, V, { RX }, FuncFlags::NONE },
241 { "ROW", "ROW", 8, 8, 0, 1, V, { RO }, FuncFlags::NONE },
242 { "COLUMN", "COLUMN", 9, 9, 0, 1, V, { RO }, FuncFlags::NONE },
243 { "NA", "NA", 10, 10, 0, 0, V, {}, FuncFlags::NONE },
244 { "NPV", "NPV", 11, 11, 2, MX, V, { VR, RX }, FuncFlags::NONE },
245 { "STDEV", "STDEV", 12, 12, 1, MX, V, { RX }, FuncFlags::NONE },
246 { "DOLLAR", "DOLLAR", 13, 13, 1, 2, V, { VR }, FuncFlags::NONE },
247 { "FIXED", "FIXED", 14, 14, 1, 2, V, { VR, VR, C }, FuncFlags::NONE },
248 { "SIN", "SIN", 15, 15, 1, 1, V, { VR }, FuncFlags::NONE },
249 { "CSC", "SIN", 15, 15, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
250 { "COS", "COS", 16, 16, 1, 1, V, { VR }, FuncFlags::NONE },
251 { "SEC", "COS", 16, 16, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
252 { "TAN", "TAN", 17, 17, 1, 1, V, { VR }, FuncFlags::NONE },
253 { "COT", "TAN", 17, 17, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
254 { "ATAN", "ATAN", 18, 18, 1, 1, V, { VR }, FuncFlags::NONE },
255 { "ACOT", "ATAN", 18, 18, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
256 { "PI", "PI", 19, 19, 0, 0, V, {}, FuncFlags::NONE },
257 { "SQRT", "SQRT", 20, 20, 1, 1, V, { VR }, FuncFlags::NONE },
258 { "EXP", "EXP", 21, 21, 1, 1, V, { VR }, FuncFlags::NONE },
259 { "LN", "LN", 22, 22, 1, 1, V, { VR }, FuncFlags::NONE },
260 { "LOG10", "LOG10", 23, 23, 1, 1, V, { VR }, FuncFlags::NONE },
261 { "ABS", "ABS", 24, 24, 1, 1, V, { VR }, FuncFlags::NONE },
262 { "INT", "INT", 25, 25, 1, 1, V, { VR }, FuncFlags::NONE },
263 { "SIGN", "SIGN", 26, 26, 1, 1, V, { VR }, FuncFlags::NONE },
264 { "ROUND", "ROUND", 27, 27, 2, 2, V, { VR }, FuncFlags::NONE },
265 { "LOOKUP", "LOOKUP", 28, 28, 2, 3, V, { VR, RA }, FuncFlags::NONE },
266 { "INDEX", "INDEX", 29, 29, 2, 4, R, { RA, VV }, FuncFlags::NONE },
267 { "REPT", "REPT", 30, 30, 2, 2, V, { VR }, FuncFlags::NONE },
268 { "MID", "MID", 31, 31, 3, 3, V, { VR }, FuncFlags::NONE },
269 { "LEN", "LEN", 32, 32, 1, 1, V, { VR }, FuncFlags::NONE },
270 { "VALUE", "VALUE", 33, 33, 1, 1, V, { VR }, FuncFlags::NONE },
271 { "TRUE", "TRUE", 34, 34, 0, 0, V, {}, FuncFlags::NONE },
272 { "FALSE", "FALSE", 35, 35, 0, 0, V, {}, FuncFlags::NONE },
273 { "AND", "AND", 36, 36, 1, MX, V, { RX }, FuncFlags::NONE },
274 { "OR", "OR", 37, 37, 1, MX, V, { RX }, FuncFlags::NONE },
275 { "NOT", "NOT", 38, 38, 1, 1, V, { VR }, FuncFlags::NONE },
276 { "MOD", "MOD", 39, 39, 2, 2, V, { VR }, FuncFlags::NONE },
277 { "DCOUNT", "DCOUNT", 40, 40, 3, 3, V, { RO, RR }, FuncFlags::NONE },
278 { "DSUM", "DSUM", 41, 41, 3, 3, V, { RO, RR }, FuncFlags::NONE },
279 { "DAVERAGE", "DAVERAGE", 42, 42, 3, 3, V, { RO, RR }, FuncFlags::NONE },
280 { "DMIN", "DMIN", 43, 43, 3, 3, V, { RO, RR }, FuncFlags::NONE },
281 { "DMAX", "DMAX", 44, 44, 3, 3, V, { RO, RR }, FuncFlags::NONE },
282 { "DSTDEV", "DSTDEV", 45, 45, 3, 3, V, { RO, RR }, FuncFlags::NONE },
283 { "VAR", "VAR", 46, 46, 1, MX, V, { RX }, FuncFlags::NONE },
284 { "DVAR", "DVAR", 47, 47, 3, 3, V, { RO, RR }, FuncFlags::NONE },
285 { "TEXT", "TEXT", 48, 48, 2, 2, V, { VR }, FuncFlags::NONE },
286 { "LINEST", "LINEST", 49, 49, 1, 2, A, { RA, RA, C, C }, FuncFlags::NONE },
287 { "TREND", "TREND", 50, 50, 1, 3, A, { RA, RA, RA, C }, FuncFlags::NONE },
288 { "LOGEST", "LOGEST", 51, 51, 1, 2, A, { RA, RA, C, C }, FuncFlags::NONE },
289 { "GROWTH", "GROWTH", 52, 52, 1, 3, A, { RA, RA, RA, C }, FuncFlags::NONE },
290 { "PV", "PV", 56, 56, 3, 5, V, { VR }, FuncFlags::NONE },
291 { "FV", "FV", 57, 57, 3, 5, V, { VR }, FuncFlags::NONE },
292 { "NPER", "NPER", 58, 58, 3, 5, V, { VR }, FuncFlags::NONE },
293 { "PMT", "PMT", 59, 59, 3, 5, V, { VR }, FuncFlags::NONE },
294 { "RATE", "RATE", 60, 60, 3, 6, V, { VR }, FuncFlags::NONE },
295 { "MIRR", "MIRR", 61, 61, 3, 3, V, { RA, VR }, FuncFlags::NONE },
296 { "IRR", "IRR", 62, 62, 1, 2, V, { RA, VR }, FuncFlags::NONE },
297 { "RAND", "RAND", 63, 63, 0, 0, V, {}, FuncFlags::VOLATILE },
298 { "MATCH", "MATCH", 64, 64, 2, 3, V, { VR, RX, RR }, FuncFlags::NONE },
299 { "DATE", "DATE", 65, 65, 3, 3, V, { VR }, FuncFlags::NONE },
300 { "TIME", "TIME", 66, 66, 3, 3, V, { VR }, FuncFlags::NONE },
301 { "DAY", "DAY", 67, 67, 1, 1, V, { VR }, FuncFlags::NONE },
302 { "MONTH", "MONTH", 68, 68, 1, 1, V, { VR }, FuncFlags::NONE },
303 { "YEAR", "YEAR", 69, 69, 1, 1, V, { VR }, FuncFlags::NONE },
304 { "WEEKDAY", "WEEKDAY", 70, 70, 1, 1, V, { VR, C }, FuncFlags::NONE },
305 { "HOUR", "HOUR", 71, 71, 1, 1, V, { VR }, FuncFlags::NONE },
306 { "MINUTE", "MINUTE", 72, 72, 1, 1, V, { VR }, FuncFlags::NONE },
307 { "SECOND", "SECOND", 73, 73, 1, 1, V, { VR }, FuncFlags::NONE },
308 { "NOW", "NOW", 74, 74, 0, 0, V, {}, FuncFlags::VOLATILE },
309 { "AREAS", "AREAS", 75, 75, 1, 1, V, { RO }, FuncFlags::NONE },
310 { "ROWS", "ROWS", 76, 76, 1, 1, V, { RO }, FuncFlags::NONE },
311 { "COLUMNS", "COLUMNS", 77, 77, 1, 1, V, { RO }, FuncFlags::NONE },
312 { "OFFSET", "OFFSET", 78, 78, 3, 5, R, { RO, VR }, FuncFlags::VOLATILE },
313 { "SEARCH", "SEARCH", 82, 82, 2, 3, V, { VR }, FuncFlags::NONE },
314 { "TRANSPOSE", "TRANSPOSE", 83, 83, 1, 1, A, { VO }, FuncFlags::NONE },
315 { "TYPE", "TYPE", 86, 86, 1, 1, V, { VX }, FuncFlags::NONE },
316 { "ATAN2", "ATAN2", 97, 97, 2, 2, V, { VR }, FuncFlags::NONE },
317 { "ASIN", "ASIN", 98, 98, 1, 1, V, { VR }, FuncFlags::NONE },
318 { "ACOS", "ACOS", 99, 99, 1, 1, V, { VR }, FuncFlags::NONE },
319 { "CHOOSE", "CHOOSE", 100, 100, 2, MX, R, { VO, RO }, FuncFlags::NONE },
320 { "HLOOKUP", "HLOOKUP", 101, 101, 3, 3, V, { VV, RO, RO, C }, FuncFlags::NONE },
321 { "VLOOKUP", "VLOOKUP", 102, 102, 3, 3, V, { VV, RO, RO, C }, FuncFlags::NONE },
322 { "ISREF", "ISREF", 105, 105, 1, 1, V, { RX }, FuncFlags::NONE },
323 { "LOG", "LOG", 109, 109, 1, 2, V, { VR }, FuncFlags::NONE },
324 { "CHAR", "CHAR", 111, 111, 1, 1, V, { VR }, FuncFlags::NONE },
325 { "LOWER", "LOWER", 112, 112, 1, 1, V, { VR }, FuncFlags::NONE },
326 { "UPPER", "UPPER", 113, 113, 1, 1, V, { VR }, FuncFlags::NONE },
327 { "PROPER", "PROPER", 114, 114, 1, 1, V, { VR }, FuncFlags::NONE },
328 { "LEFT", "LEFT", 115, 115, 1, 2, V, { VR }, FuncFlags::NONE },
329 { "RIGHT", "RIGHT", 116, 116, 1, 2, V, { VR }, FuncFlags::NONE },
330 { "EXACT", "EXACT", 117, 117, 2, 2, V, { VR }, FuncFlags::NONE },
331 { "TRIM", "TRIM", 118, 118, 1, 1, V, { VR }, FuncFlags::NONE },
332 { "REPLACE", "REPLACE", 119, 119, 4, 4, V, { VR }, FuncFlags::NONE },
333 { "SUBSTITUTE", "SUBSTITUTE", 120, 120, 3, 4, V, { VR }, FuncFlags::NONE },
334 { "CODE", "CODE", 121, 121, 1, 1, V, { VR }, FuncFlags::NONE },
335 { "FIND", "FIND", 124, 124, 2, 3, V, { VR }, FuncFlags::NONE },
336 { "CELL", "CELL", 125, 125, 1, 2, V, { VV, RO }, FuncFlags::VOLATILE },
337 { "ISERR", "ISERR", 126, 126, 1, 1, V, { VR }, FuncFlags::NONE },
338 { "ISTEXT", "ISTEXT", 127, 127, 1, 1, V, { VR }, FuncFlags::NONE },
339 { "ISNUMBER", "ISNUMBER", 128, 128, 1, 1, V, { VR }, FuncFlags::NONE },
340 { "ISBLANK", "ISBLANK", 129, 129, 1, 1, V, { VR }, FuncFlags::NONE },
341 { "T", "T", 130, 130, 1, 1, V, { RO }, FuncFlags::NONE },
342 { "N", "N", 131, 131, 1, 1, V, { RO }, FuncFlags::NONE },
343 { "DATEVALUE", "DATEVALUE", 140, 140, 1, 1, V, { VR }, FuncFlags::NONE },
344 { "TIMEVALUE", "TIMEVALUE", 141, 141, 1, 1, V, { VR }, FuncFlags::NONE },
345 { "SLN", "SLN", 142, 142, 3, 3, V, { VR }, FuncFlags::NONE },
346 { "SYD", "SYD", 143, 143, 4, 4, V, { VR }, FuncFlags::NONE },
347 { "DDB", "DDB", 144, 144, 4, 5, V, { VR }, FuncFlags::NONE },
348 { "INDIRECT", "INDIRECT", 148, 148, 1, 2, R, { VR }, FuncFlags::VOLATILE },
349 { "CLEAN", "CLEAN", 162, 162, 1, 1, V, { VR }, FuncFlags::NONE },
350 { "MDETERM", "MDETERM", 163, 163, 1, 1, V, { VA }, FuncFlags::NONE },
351 { "MINVERSE", "MINVERSE", 164, 164, 1, 1, A, { VA }, FuncFlags::NONE },
352 { "MMULT", "MMULT", 165, 165, 2, 2, A, { VA }, FuncFlags::NONE },
353 { "IPMT", "IPMT", 167, 167, 4, 6, V, { VR }, FuncFlags::NONE },
354 { "PPMT", "PPMT", 168, 168, 4, 6, V, { VR }, FuncFlags::NONE },
355 { "COUNTA", "COUNTA", 169, 169, 0, MX, V, { RX }, FuncFlags::NONE },
356 { "PRODUCT", "PRODUCT", 183, 183, 0, MX, V, { RX }, FuncFlags::NONE },
357 { "FACT", "FACT", 184, 184, 1, 1, V, { VR }, FuncFlags::NONE },
358 { "DPRODUCT", "DPRODUCT", 189, 189, 3, 3, V, { RO, RR }, FuncFlags::NONE },
359 { "ISNONTEXT", "ISNONTEXT", 190, 190, 1, 1, V, { VR }, FuncFlags::NONE },
360 { "STDEVP", "STDEVP", 193, 193, 1, MX, V, { RX }, FuncFlags::NONE },
361 { "VARP", "VARP", 194, 194, 1, MX, V, { RX }, FuncFlags::NONE },
362 { "DSTDEVP", "DSTDEVP", 195, 195, 3, 3, V, { RO, RR }, FuncFlags::NONE },
363 { "DVARP", "DVARP", 196, 196, 3, 3, V, { RO, RR }, FuncFlags::NONE },
364 { "TRUNC", "TRUNC", 197, 197, 1, 1, V, { VR, C }, FuncFlags::NONE },
365 { "ISLOGICAL", "ISLOGICAL", 198, 198, 1, 1, V, { VR }, FuncFlags::NONE },
366 { "DCOUNTA", "DCOUNTA", 199, 199, 3, 3, V, { RO, RR }, FuncFlags::NONE },
367 { nullptr, "EXTERN.CALL", 255, 255, 1, MX, R, { RO_E, RO }, FuncFlags::IMPORTONLY },
368
369 // *** macro sheet commands ***
370
371 { nullptr, "A1.R1C1", 30, 30, 0, 1, V, { VR }, FuncFlags::MACROCMD },
372 { nullptr, "RETURN", 55, 55, 0, 1, R, { RO }, FuncFlags::MACROFUNC },
373 { nullptr, "ABSREF", 79, 79, 2, 2, R, { VR, RO }, FuncFlags::MACROFUNC },
374 { nullptr, "ADD.ARROW", 81, 81, 0, 0, V, {}, FuncFlags::MACROCMD },
375 { nullptr, "ACTIVE.CELL", 94, 94, 0, 0, R, {}, FuncFlags::MACROFUNC },
376 { nullptr, "ACTIVATE", 103, 103, 0, 2, V, { VR }, FuncFlags::MACROCMD },
377 { nullptr, "ACTIVATE.NEXT", 104, 104, 0, 0, V, {}, FuncFlags::MACROCMD },
378 { nullptr, "ACTIVATE.PREV", 105, 105, 0, 0, V, {}, FuncFlags::MACROCMD },
379 { nullptr, "ADD.BAR", 151, 151, 0, 0, V, {}, FuncFlags::MACROFUNC | FuncFlags::ALWAYSVAR },
380 { nullptr, "ADD.MENU", 152, 152, 2, 2, V, { VR, RO }, FuncFlags::MACROFUNC | FuncFlags::ALWAYSVAR },
381 { nullptr, "ADD.COMMAND", 153, 153, 3, 3, V, { VR, RO }, FuncFlags::MACROFUNC | FuncFlags::ALWAYSVAR }
382 };
383
384 /** Functions new in BIFF3. */
385 const FunctionData saFuncTableBiff3[] =
386 {
387 { "LINEST", "LINEST", 49, 49, 1, 4, A, { RA, RA, VV }, FuncFlags::NONE }, // BIFF2: 1-2, BIFF3: 1-4
388 { "TREND", "TREND", 50, 50, 1, 4, A, { RA, RA, RA, VV }, FuncFlags::NONE }, // BIFF2: 1-3, BIFF3: 1-4
389 { "LOGEST", "LOGEST", 51, 51, 1, 4, A, { RA, RA, VV }, FuncFlags::NONE }, // BIFF2: 1-2, BIFF3: 1-4
390 { "GROWTH", "GROWTH", 52, 52, 1, 4, A, { RA, RA, RA, VV }, FuncFlags::NONE }, // BIFF2: 1-3, BIFF3: 1-4
391 { "TRUNC", "TRUNC", 197, 197, 1, 2, V, { VR }, FuncFlags::NONE }, // BIFF2: 1, BIFF3: 1-2
392 { "DOLLAR", "USDOLLAR", 204, 204, 1, 2, V, { VR }, FuncFlags::IMPORTONLY },
393 { "FINDB", "FINDB", 205, 205, 2, 3, V, { VR }, FuncFlags::NONE },
394 { "SEARCHB", "SEARCHB", 206, 206, 2, 3, V, { VR }, FuncFlags::NONE },
395 { "REPLACEB", "REPLACEB", 207, 207, 4, 4, V, { VR }, FuncFlags::NONE },
396 { "LEFTB", "LEFTB", 208, 208, 1, 2, V, { VR }, FuncFlags::NONE },
397 { "RIGHTB", "RIGHTB", 209, 209, 1, 2, V, { VR }, FuncFlags::NONE },
398 { "MIDB", "MIDB", 210, 210, 3, 3, V, { VR }, FuncFlags::NONE },
399 { "LENB", "LENB", 211, 211, 1, 1, V, { VR }, FuncFlags::NONE },
400 { "ROUNDUP", "ROUNDUP", 212, 212, 2, 2, V, { VR }, FuncFlags::NONE },
401 { "ROUNDDOWN", "ROUNDDOWN", 213, 213, 2, 2, V, { VR }, FuncFlags::NONE },
402 { "ASC", "ASC", 214, 214, 1, 1, V, { VR }, FuncFlags::NONE },
403 { "JIS", "DBCS", 215, 215, 1, 1, V, { VR }, FuncFlags::NONE },
404 { "ADDRESS", "ADDRESS", 219, 219, 2, 5, V, { VR }, FuncFlags::NONE },
405 { "DAYS360", "DAYS360", 220, 220, 2, 2, V, { VR, VR, C }, FuncFlags::NONE },
406 { "TODAY", "TODAY", 221, 221, 0, 0, V, {}, FuncFlags::VOLATILE },
407 { "VDB", "VDB", 222, 222, 5, 7, V, { VR }, FuncFlags::NONE },
408 { "MEDIAN", "MEDIAN", 227, 227, 1, MX, V, { RX }, FuncFlags::NONE },
409 { "SUMPRODUCT", "SUMPRODUCT", 228, 228, 1, MX, V, { VA }, FuncFlags::NONE },
410 { "SINH", "SINH", 229, 229, 1, 1, V, { VR }, FuncFlags::NONE },
411 { "CSCH", "SINH", 229, 229, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
412 { "COSH", "COSH", 230, 230, 1, 1, V, { VR }, FuncFlags::NONE },
413 { "SECH", "COSH", 230, 230, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
414 { "TANH", "TANH", 231, 231, 1, 1, V, { VR }, FuncFlags::NONE },
415 { "COTH", "TANH", 231, 231, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
416 { "ASINH", "ASINH", 232, 232, 1, 1, V, { VR }, FuncFlags::NONE },
417 { "ACOSH", "ACOSH", 233, 233, 1, 1, V, { VR }, FuncFlags::NONE },
418 { "ATANH", "ATANH", 234, 234, 1, 1, V, { VR }, FuncFlags::NONE },
419 { "ACOTH", "ATANH", 234, 234, 1, 1, V, { VR }, FuncFlags::BIFFEXPORTONLY },
420 { "DGET", "DGET", 235, 235, 3, 3, V, { RO, RR }, FuncFlags::NONE },
421 { "INFO", "INFO", 244, 244, 1, 1, V, { VR }, FuncFlags::VOLATILE },
422
423 // *** macro sheet commands ***
424
425 { nullptr, "ADD.BAR", 151, 151, 0, 1, V, { VR }, FuncFlags::MACROFUNC }, // BIFF2: 0, BIFF3: 0-1
426 { nullptr, "ADD.MENU", 152, 152, 2, 3, V, { VR, RO }, FuncFlags::MACROFUNC }, // BIFF2: 2, BIFF3: 2-3
427 { nullptr, "ADD.COMMAND", 153, 153, 3, 4, V, { VR, RO }, FuncFlags::MACROFUNC } // BIFF2: 3, BIFF3: 3-4
428 };
429
430 /** Functions new in BIFF4. */
431 const FunctionData saFuncTableBiff4[] =
432 {
433 { "FIXED", "FIXED", 14, 14, 1, 3, V, { VR }, FuncFlags::NONE }, // BIFF2-3: 1-2, BIFF4: 1-3
434 { "RANK", "RANK", 216, 216, 2, 3, V, { VR, RO, VR }, FuncFlags::NONE },
435 { "DB", "DB", 247, 247, 4, 5, V, { VR }, FuncFlags::NONE },
436 { "FREQUENCY", "FREQUENCY", 252, 252, 2, 2, A, { RA }, FuncFlags::NONE },
437 { "ERROR.TYPE", "ERROR.TYPE", 261, 261, 1, 1, V, { VR }, FuncFlags::NONE },
438 { "AVEDEV", "AVEDEV", 269, 269, 1, MX, V, { RX }, FuncFlags::NONE },
439 { "BETADIST", "BETADIST", 270, 270, 3, 5, V, { VR }, FuncFlags::NONE },
440 { "GAMMALN", "GAMMALN", 271, 271, 1, 1, V, { VR }, FuncFlags::NONE },
441 { "BETAINV", "BETAINV", 272, 272, 3, 5, V, { VR }, FuncFlags::NONE },
442 { "BINOMDIST", "BINOMDIST", 273, 273, 4, 4, V, { VR }, FuncFlags::NONE },
443 { "LEGACY.CHIDIST", "CHIDIST", 274, 274, 2, 2, V, { VR }, FuncFlags::NONE },
444 { "LEGACY.CHIINV", "CHIINV", 275, 275, 2, 2, V, { VR }, FuncFlags::NONE },
445 { "COMBIN", "COMBIN", 276, 276, 2, 2, V, { VR }, FuncFlags::NONE },
446 { "CONFIDENCE", "CONFIDENCE", 277, 277, 3, 3, V, { VR }, FuncFlags::NONE },
447 { "CRITBINOM", "CRITBINOM", 278, 278, 3, 3, V, { VR }, FuncFlags::NONE },
448 { "EVEN", "EVEN", 279, 279, 1, 1, V, { VR }, FuncFlags::NONE },
449 { "EXPONDIST", "EXPONDIST", 280, 280, 3, 3, V, { VR }, FuncFlags::NONE },
450 { "LEGACY.FDIST", "FDIST", 281, 281, 3, 3, V, { VR }, FuncFlags::NONE },
451 { "LEGACY.FINV", "FINV", 282, 282, 3, 3, V, { VR }, FuncFlags::NONE },
452 { "FISHER", "FISHER", 283, 283, 1, 1, V, { VR }, FuncFlags::NONE },
453 { "FISHERINV", "FISHERINV", 284, 284, 1, 1, V, { VR }, FuncFlags::NONE },
454 { "COM.MICROSOFT.FLOOR", "FLOOR", 285, 285, 2, 2, V, { VR }, FuncFlags::NONE },
455 { "GAMMADIST", "GAMMADIST", 286, 286, 4, 4, V, { VR }, FuncFlags::NONE },
456 { "GAMMAINV", "GAMMAINV", 287, 287, 3, 3, V, { VR }, FuncFlags::NONE },
457 { "COM.MICROSOFT.CEILING", "CEILING", 288, 288, 2, 2, V, { VR }, FuncFlags::NONE },
458 { "HYPGEOMDIST", "HYPGEOMDIST", 289, 289, 4, 4, V, { VR }, FuncFlags::NONE },
459 { "LOGNORMDIST", "LOGNORMDIST", 290, 290, 3, 3, V, { VR }, FuncFlags::NONE },
460 { "LOGINV", "LOGINV", 291, 291, 3, 3, V, { VR }, FuncFlags::NONE },
461 { "NEGBINOMDIST", "NEGBINOMDIST", 292, 292, 3, 3, V, { VR }, FuncFlags::NONE },
462 { "NORMDIST", "NORMDIST", 293, 293, 4, 4, V, { VR }, FuncFlags::NONE },
463 { "LEGACY.NORMSDIST", "NORMSDIST", 294, 294, 1, 1, V, { VR }, FuncFlags::NONE },
464 { "NORMINV", "NORMINV", 295, 295, 3, 3, V, { VR }, FuncFlags::NONE },
465 { "LEGACY.NORMSINV", "NORMSINV", 296, 296, 1, 1, V, { VR }, FuncFlags::NONE },
466 { "STANDARDIZE", "STANDARDIZE", 297, 297, 3, 3, V, { VR }, FuncFlags::NONE },
467 { "ODD", "ODD", 298, 298, 1, 1, V, { VR }, FuncFlags::NONE },
468 { "PERMUT", "PERMUT", 299, 299, 2, 2, V, { VR }, FuncFlags::NONE },
469 { "POISSON", "POISSON", 300, 300, 3, 3, V, { VR }, FuncFlags::NONE },
470 { "LEGACY.TDIST", "TDIST", 301, 301, 3, 3, V, { VR }, FuncFlags::NONE },
471 { "WEIBULL", "WEIBULL", 302, 302, 4, 4, V, { VR }, FuncFlags::NONE },
472 { "SUMXMY2", "SUMXMY2", 303, 303, 2, 2, V, { VA }, FuncFlags::NONE },
473 { "SUMX2MY2", "SUMX2MY2", 304, 304, 2, 2, V, { VA }, FuncFlags::NONE },
474 { "SUMX2PY2", "SUMX2PY2", 305, 305, 2, 2, V, { VA }, FuncFlags::NONE },
475 { "LEGACY.CHITEST", "CHITEST", 306, 306, 2, 2, V, { VA }, FuncFlags::NONE },
476 { "CORREL", "CORREL", 307, 307, 2, 2, V, { VA }, FuncFlags::NONE },
477 { "COVAR", "COVAR", 308, 308, 2, 2, V, { VA }, FuncFlags::NONE },
478 { "FORECAST", "FORECAST", 309, 309, 3, 3, V, { VR, VA }, FuncFlags::NONE },
479 { "FTEST", "FTEST", 310, 310, 2, 2, V, { VA }, FuncFlags::NONE },
480 { "INTERCEPT", "INTERCEPT", 311, 311, 2, 2, V, { VA }, FuncFlags::NONE },
481 { "PEARSON", "PEARSON", 312, 312, 2, 2, V, { VA }, FuncFlags::NONE },
482 { "RSQ", "RSQ", 313, 313, 2, 2, V, { VA }, FuncFlags::NONE },
483 { "STEYX", "STEYX", 314, 314, 2, 2, V, { VA }, FuncFlags::NONE },
484 { "SLOPE", "SLOPE", 315, 315, 2, 2, V, { VA }, FuncFlags::NONE },
485 { "TTEST", "TTEST", 316, 316, 4, 4, V, { VA, VA, VR }, FuncFlags::NONE },
486 { "PROB", "PROB", 317, 317, 3, 4, V, { VA, VA, VR }, FuncFlags::NONE },
487 { "DEVSQ", "DEVSQ", 318, 318, 1, MX, V, { RX }, FuncFlags::NONE },
488 { "GEOMEAN", "GEOMEAN", 319, 319, 1, MX, V, { RX }, FuncFlags::NONE },
489 { "HARMEAN", "HARMEAN", 320, 320, 1, MX, V, { RX }, FuncFlags::NONE },
490 { "SUMSQ", "SUMSQ", 321, 321, 0, MX, V, { RX }, FuncFlags::NONE },
491 { "KURT", "KURT", 322, 322, 1, MX, V, { RX }, FuncFlags::NONE },
492 { "SKEW", "SKEW", 323, 323, 1, MX, V, { RX }, FuncFlags::NONE },
493 { "ZTEST", "ZTEST", 324, 324, 2, 3, V, { RX, VR }, FuncFlags::NONE },
494 { "LARGE", "LARGE", 325, 325, 2, 2, V, { RX, VR }, FuncFlags::NONE },
495 { "SMALL", "SMALL", 326, 326, 2, 2, V, { RX, VR }, FuncFlags::NONE },
496 { "QUARTILE", "QUARTILE", 327, 327, 2, 2, V, { RX, VR }, FuncFlags::NONE },
497 { "PERCENTILE", "PERCENTILE", 328, 328, 2, 2, V, { RX, VR }, FuncFlags::NONE },
498 { "PERCENTRANK", "PERCENTRANK", 329, 329, 2, 3, V, { RX, VR, VR_E }, FuncFlags::NONE },
499 { "MODE", "MODE", 330, 330, 1, MX, V, { VA }, FuncFlags::NONE },
500 { "TRIMMEAN", "TRIMMEAN", 331, 331, 2, 2, V, { RX, VR }, FuncFlags::NONE },
501 { "TINV", "TINV", 332, 332, 2, 2, V, { VR }, FuncFlags::NONE },
502
503 // *** Analysis add-in ***
504
505 { "HEX2BIN", "HEX2BIN", 384, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
506 { "HEX2DEC", "HEX2DEC", 385, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
507 { "HEX2OCT", "HEX2OCT", 386, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
508 { "DEC2BIN", "DEC2BIN", 387, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
509 { "DEC2HEX", "DEC2HEX", 388, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
510 { "DEC2OCT", "DEC2OCT", 389, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
511 { "OCT2BIN", "OCT2BIN", 390, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
512 { "OCT2HEX", "OCT2HEX", 391, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
513 { "OCT2DEC", "OCT2DEC", 392, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
514 { "BIN2DEC", "BIN2DEC", 393, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
515 { "BIN2OCT", "BIN2OCT", 394, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
516 { "BIN2HEX", "BIN2HEX", 395, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
517 { "IMSUB", "IMSUB", 396, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
518 { "IMDIV", "IMDIV", 397, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
519 { "IMPOWER", "IMPOWER", 398, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
520 { "IMABS", "IMABS", 399, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
521 { "IMSQRT", "IMSQRT", 400, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
522 { "IMLN", "IMLN", 401, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
523 { "IMLOG2", "IMLOG2", 402, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
524 { "IMLOG10", "IMLOG10", 403, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
525 { "IMSIN", "IMSIN", 404, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
526 { "IMCOS", "IMCOS", 405, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
527 { "IMEXP", "IMEXP", 406, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
528 { "IMARGUMENT", "IMARGUMENT", 407, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
529 { "IMCONJUGATE", "IMCONJUGATE", 408, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
530 { "IMAGINARY", "IMAGINARY", 409, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
531 { "IMREAL", "IMREAL", 410, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
532 { "COMPLEX", "COMPLEX", 411, NOID, 2, 3, V, { RR }, FuncFlags::EXTERNAL },
533 { "IMSUM", "IMSUM", 412, NOID, 1, MX, V, { RX }, FuncFlags::EXTERNAL },
534 { "IMPRODUCT", "IMPRODUCT", 413, NOID, 1, MX, V, { RX }, FuncFlags::EXTERNAL },
535 { "SERIESSUM", "SERIESSUM", 414, NOID, 4, 4, V, { RR, RR, RR, RX }, FuncFlags::EXTERNAL },
536 { "FACTDOUBLE", "FACTDOUBLE", 415, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
537 { "SQRTPI", "SQRTPI", 416, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
538 { "QUOTIENT", "QUOTIENT", 417, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
539 { "DELTA", "DELTA", 418, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
540 { "GESTEP", "GESTEP", 419, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
541 { "ISEVEN", "ISEVEN", 420, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
542 { "ISODD", "ISODD", 421, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
543 { "MROUND", "MROUND", 422, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
544 { "ERF", "ERF", 423, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
545 { "ERFC", "ERFC", 424, NOID, 1, 1, V, { RR }, FuncFlags::EXTERNAL },
546 { "BESSELJ", "BESSELJ", 425, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
547 { "BESSELK", "BESSELK", 426, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
548 { "BESSELY", "BESSELY", 427, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
549 { "BESSELI", "BESSELI", 428, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
550 { "XIRR", "XIRR", 429, NOID, 2, 3, V, { RX, RX, RR }, FuncFlags::EXTERNAL },
551 { "XNPV", "XNPV", 430, NOID, 3, 3, V, { RR, RX, RX }, FuncFlags::EXTERNAL },
552 { "PRICEMAT", "PRICEMAT", 431, NOID, 5, 6, V, { RR }, FuncFlags::EXTERNAL },
553 { "YIELDMAT", "YIELDMAT", 432, NOID, 5, 6, V, { RR }, FuncFlags::EXTERNAL },
554 { "INTRATE", "INTRATE", 433, NOID, 4, 5, V, { RR }, FuncFlags::EXTERNAL },
555 { "RECEIVED", "RECEIVED", 434, NOID, 4, 5, V, { RR }, FuncFlags::EXTERNAL },
556 { "DISC", "DISC", 435, NOID, 4, 5, V, { RR }, FuncFlags::EXTERNAL },
557 { "PRICEDISC", "PRICEDISC", 436, NOID, 4, 5, V, { RR }, FuncFlags::EXTERNAL },
558 { "YIELDDISC", "YIELDDISC", 437, NOID, 4, 5, V, { RR }, FuncFlags::EXTERNAL },
559 { "TBILLEQ", "TBILLEQ", 438, NOID, 3, 3, V, { RR }, FuncFlags::EXTERNAL },
560 { "TBILLPRICE", "TBILLPRICE", 439, NOID, 3, 3, V, { RR }, FuncFlags::EXTERNAL },
561 { "TBILLYIELD", "TBILLYIELD", 440, NOID, 3, 3, V, { RR }, FuncFlags::EXTERNAL },
562 { "PRICE", "PRICE", 441, NOID, 6, 7, V, { RR }, FuncFlags::EXTERNAL },
563 { "YIELD", "YIELD", 442, NOID, 6, 7, V, { RR }, FuncFlags::EXTERNAL },
564 { "DOLLARDE", "DOLLARDE", 443, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
565 { "DOLLARFR", "DOLLARFR", 444, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
566 { "NOMINAL", "NOMINAL", 445, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
567 { "EFFECT", "EFFECT", 446, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
568 { "CUMPRINC", "CUMPRINC", 447, NOID, 6, 6, V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
569 { "CUMIPMT", "CUMIPMT", 448, NOID, 6, 6, V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
570 { "EDATE", "EDATE", 449, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
571 { "EOMONTH", "EOMONTH", 450, NOID, 2, 2, V, { RR }, FuncFlags::EXTERNAL },
572 { "YEARFRAC", "YEARFRAC", 451, NOID, 2, 3, V, { RR }, FuncFlags::EXTERNAL },
573 { "COUPDAYBS", "COUPDAYBS", 452, NOID, 3, 4, V, { RR }, FuncFlags::EXTERNAL },
574 { "COUPDAYS", "COUPDAYS", 453, NOID, 3, 4, V, { RR }, FuncFlags::EXTERNAL },
575 { "COUPDAYSNC", "COUPDAYSNC", 454, NOID, 3, 4, V, { RR }, FuncFlags::EXTERNAL },
576 { "COUPNCD", "COUPNCD", 455, NOID, 3, 4, V, { RR }, FuncFlags::EXTERNAL },
577 { "COUPNUM", "COUPNUM", 456, NOID, 3, 4, V, { RR }, FuncFlags::EXTERNAL },
578 { "COUPPCD", "COUPPCD", 457, NOID, 3, 4, V, { RR }, FuncFlags::EXTERNAL },
579 { "DURATION", "DURATION", 458, NOID, 5, 6, V, { RR }, FuncFlags::EXTERNAL }, // Calc: builtin and add-in (but different!)
580 { "MDURATION", "MDURATION", 459, NOID, 5, 6, V, { RR }, FuncFlags::EXTERNAL },
581 { "ODDLPRICE", "ODDLPRICE", 460, NOID, 7, 8, V, { RR }, FuncFlags::EXTERNAL },
582 { "ODDLYIELD", "ODDLYIELD", 461, NOID, 8, 9, V, { RR }, FuncFlags::EXTERNAL },
583 { "ODDFPRICE", "ODDFPRICE", 462, NOID, 8, 9, V, { RR }, FuncFlags::EXTERNAL },
584 { "ODDFYIELD", "ODDFYIELD", 463, NOID, 8, 9, V, { RR }, FuncFlags::EXTERNAL },
585 { "RANDBETWEEN", "RANDBETWEEN", 464, NOID, 2, 2, V, { RR }, FuncFlags::VOLATILE | FuncFlags::EXTERNAL },
586 { "WEEKNUM", "WEEKNUM", 465, NOID, 1, 2, V, { RR }, FuncFlags::EXTERNAL },
587 { "AMORDEGRC", "AMORDEGRC", 466, NOID, 6, 7, V, { RR }, FuncFlags::EXTERNAL },
588 { "AMORLINC", "AMORLINC", 467, NOID, 6, 7, V, { RR }, FuncFlags::EXTERNAL },
589 { "CONVERT", "CONVERT", 468, NOID, 3, 3, V, { RR }, FuncFlags::EXTERNAL }, // Calc: builtin and add-in (but different!)
590 { "ACCRINT", "ACCRINT", 469, NOID, 6, 7, V, { RR }, FuncFlags::EXTERNAL },
591 { "ACCRINTM", "ACCRINTM", 470, NOID, 4, 5, V, { RR }, FuncFlags::EXTERNAL },
592 { "WORKDAY", "WORKDAY", 471, NOID, 2, 3, V, { RR, RR, RX, C }, FuncFlags::EXTERNAL },
593 { "NETWORKDAYS", "NETWORKDAYS", 472, NOID, 2, 3, V, { RR, RR, RX, C }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
594 { "GCD", "GCD", 473, NOID, 1, MX, V, { RX }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
595 { "MULTINOMIAL", "MULTINOMIAL", 474, NOID, 1, MX, V, { RX }, FuncFlags::EXTERNAL },
596 { "LCM", "LCM", 475, NOID, 1, MX, V, { RX }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
597 { "FVSCHEDULE", "FVSCHEDULE", 476, NOID, 2, 2, V, { RR, RX }, FuncFlags::EXTERNAL },
598
599 // *** macro sheet commands ***
600
601 { nullptr, "ACTIVATE.NEXT", 104, 104, 0, 1, V, { VR }, FuncFlags::MACROCMD }, // BIFF2-3: 0, BIFF4: 0-1
602 { nullptr, "ACTIVATE.PREV", 105, 105, 0, 1, V, { VR }, FuncFlags::MACROCMD } // BIFF2-3: 0, BIFF4: 0-1
603 };
604
605 /** Functions new in BIFF5/BIFF7. */
606 const FunctionData saFuncTableBiff5[] =
607 {
608 { "WEEKDAY", "WEEKDAY", 70, 70, 1, 2, V, { VR }, FuncFlags::NONE }, // BIFF2-4: 1, BIFF5: 1-2
609 { "HLOOKUP", "HLOOKUP", 101, 101, 3, 4, V, { VV, RO, RO, VV }, FuncFlags::NONE }, // BIFF2-4: 3, BIFF5: 3-4
610 { "VLOOKUP", "VLOOKUP", 102, 102, 3, 4, V, { VV, RO, RO, VV }, FuncFlags::NONE }, // BIFF2-4: 3, BIFF5: 3-4
611 { "DAYS360", "DAYS360", 220, 220, 2, 3, V, { VR }, FuncFlags::NONE }, // BIFF3-4: 2, BIFF5: 2-3
612 { nullptr, "EXTERN.CALL", 255, 255, 1, MX, R, { RO_E, RO }, FuncFlags::EXPORTONLY }, // MACRO or EXTERNAL
613 { "CONCATENATE", "CONCATENATE", 336, 336, 0, MX, V, { VR }, FuncFlags::NONE },
614 { "POWER", "POWER", 337, 337, 2, 2, V, { VR }, FuncFlags::NONE },
615 { "RADIANS", "RADIANS", 342, 342, 1, 1, V, { VR }, FuncFlags::NONE },
616 { "DEGREES", "DEGREES", 343, 343, 1, 1, V, { VR }, FuncFlags::NONE },
617 { "SUBTOTAL", "SUBTOTAL", 344, 344, 2, MX, V, { VR, RO }, FuncFlags::NONE },
618 { "SUMIF", "SUMIF", 345, 345, 2, 3, V, { RO, VR, RO }, FuncFlags::NONE },
619 { "COUNTIF", "COUNTIF", 346, 346, 2, 2, V, { RO, VR }, FuncFlags::NONE },
620 { "COUNTBLANK", "COUNTBLANK", 347, 347, 1, 1, V, { RO }, FuncFlags::NONE },
621 { "ISPMT", "ISPMT", 350, 350, 4, 4, V, { VR }, FuncFlags::NONE },
622 { "DATEDIF", "DATEDIF", 351, 351, 3, 3, V, { VR }, FuncFlags::NONE },
623 { nullptr, "DATESTRING", 352, 352, 1, 1, V, { VR }, FuncFlags::IMPORTONLY }, // not supported in Calc, missing in OOXML spec
624 { nullptr, "NUMBERSTRING", 353, 353, 2, 2, V, { VR }, FuncFlags::IMPORTONLY }, // not supported in Calc, missing in OOXML spec
625 { "ROMAN", "ROMAN", 354, 354, 1, 2, V, { VR }, FuncFlags::NONE },
626
627 // *** EuroTool add-in ***
628 { "EUROCONVERT", "EUROCONVERT", NOID, NOID, 3, 5, V, { VR }, FuncFlags::EUROTOOL },
629
630 // *** macro sheet commands ***
631
632 { nullptr, "ADD.MENU", 152, 152, 2, 4, V, { VR, RO, RO, VR }, FuncFlags::MACROFUNC }, // BIFF3-4: 2-3, BIFF5: 2-4
633 { nullptr, "ADD.COMMAND", 153, 153, 3, 5, V, { VR, RO, RO, RO, VR }, FuncFlags::MACROFUNC }, // BIFF3-4: 3-4, BIFF5: 3-5
634 { nullptr, "ADD.CHART.AUTOFORMAT", 390, 390, 0, 2, V, { VR }, FuncFlags::MACROCMD },
635 { nullptr, "ADD.LIST.ITEM", 451, 451, 0, 2, V, { VR }, FuncFlags::MACROCMD },
636 { nullptr, "ACTIVE.CELL.FONT", 476, 476, 0, 14, V, { VR }, FuncFlags::MACROCMD }
637 };
638
639 /** Functions new in BIFF8. */
640 const FunctionData saFuncTableBiff8[] =
641 {
642 { "GETPIVOTDATA", "GETPIVOTDATA", 358, 358, 2, MX, V, { RR, RR, VR, VR }, FuncFlags::IMPORTONLY | FuncFlags::PARAMPAIRS },
643 { "HYPERLINK", "HYPERLINK", 359, 359, 1, 2, V, { VV, VO }, FuncFlags::NONE },
644 { nullptr, "PHONETIC", 360, 360, 1, 1, V, { RO }, FuncFlags::IMPORTONLY },
645 { "AVERAGEA", "AVERAGEA", 361, 361, 1, MX, V, { RX }, FuncFlags::NONE },
646 { "MAXA", "MAXA", 362, 362, 1, MX, V, { RX }, FuncFlags::NONE },
647 { "MINA", "MINA", 363, 363, 1, MX, V, { RX }, FuncFlags::NONE },
648 { "STDEVPA", "STDEVPA", 364, 364, 1, MX, V, { RX }, FuncFlags::NONE },
649 { "VARPA", "VARPA", 365, 365, 1, MX, V, { RX }, FuncFlags::NONE },
650 { "STDEVA", "STDEVA", 366, 366, 1, MX, V, { RX }, FuncFlags::NONE },
651 { "VARA", "VARA", 367, 367, 1, MX, V, { RX }, FuncFlags::NONE },
652 { "COM.MICROSOFT.BAHTTEXT", "BAHTTEXT", 368, 368, 1, 1, V, { VR }, FuncFlags::MACROCALL },
653 { nullptr, "THAIDAYOFWEEK", 369, 369, 1, 1, V, { VR }, FuncFlags::MACROCALL },
654 { nullptr, "THAIDIGIT", 370, 370, 1, 1, V, { VR }, FuncFlags::MACROCALL },
655 { nullptr, "THAIMONTHOFYEAR", 371, 371, 1, 1, V, { VR }, FuncFlags::MACROCALL },
656 { nullptr, "THAINUMSOUND", 372, 372, 1, 1, V, { VR }, FuncFlags::MACROCALL },
657 { nullptr, "THAINUMSTRING", 373, 373, 1, 1, V, { VR }, FuncFlags::MACROCALL },
658 { nullptr, "THAISTRINGLENGTH", 374, 374, 1, 1, V, { VR }, FuncFlags::MACROCALL },
659 { nullptr, "ISTHAIDIGIT", 375, 375, 1, 1, V, { VR }, FuncFlags::MACROCALL },
660 { nullptr, "ROUNDBAHTDOWN", 376, 376, 1, 1, V, { VR }, FuncFlags::MACROCALL },
661 { nullptr, "ROUNDBAHTUP", 377, 377, 1, 1, V, { VR }, FuncFlags::MACROCALL },
662 { nullptr, "THAIYEAR", 378, 378, 1, 1, V, { VR }, FuncFlags::MACROCALL },
663 { nullptr, "RTD", 379, 379, 3, 3, A, { VR, VR, RO }, FuncFlags::NONE }
664 };
665
666 /** Functions new in OOXML. */
667 const FunctionData saFuncTableOox[] =
668 {
669 { nullptr, "CUBEVALUE", 380, NOID, 1, MX, V, { VR, RX }, FuncFlags::NONE },
670 { nullptr, "CUBEMEMBER", 381, NOID, 2, 3, V, { VR, RX, VR }, FuncFlags::NONE },
671 { nullptr, "CUBEMEMBERPROPERTY", 382, NOID, 3, 3, V, { VR }, FuncFlags::NONE },
672 { nullptr, "CUBERANKEDMEMBER", 383, NOID, 3, 4, V, { VR }, FuncFlags::NONE },
673 { nullptr, "CUBEKPIMEMBER", 477, NOID, 3, 4, V, { VR }, FuncFlags::NONE },
674 { nullptr, "CUBESET", 478, NOID, 2, 5, V, { VR, RX, VR }, FuncFlags::NONE },
675 { nullptr, "CUBESETCOUNT", 479, NOID, 1, 1, V, { VR }, FuncFlags::NONE },
676 { "IFERROR", "IFERROR", 480, NOID, 2, 2, V, { VO, RO }, FuncFlags::MACROCALL },
677 { "COUNTIFS", "COUNTIFS", 481, NOID, 2, MX, V, { RO, VR }, FuncFlags::MACROCALL | FuncFlags::PARAMPAIRS },
678 { "SUMIFS", "SUMIFS", 482, NOID, 3, MX, V, { RO, RO, VR }, FuncFlags::MACROCALL | FuncFlags::PARAMPAIRS },
679 { "AVERAGEIF", "AVERAGEIF", 483, NOID, 2, 3, V, { RO, VR, RO }, FuncFlags::MACROCALL },
680 { "AVERAGEIFS", "AVERAGEIFS", 484, NOID, 3, MX, V, { RO, RO, VR }, FuncFlags::MACROCALL | FuncFlags::PARAMPAIRS },
681 { "COM.MICROSOFT.ISO.CEILING", "ISO.CEILING", NOID, NOID, 1, 2, V, { VR }, FuncFlags::MACROCALL },
682 { "COM.MICROSOFT.NETWORKDAYS.INTL", "NETWORKDAYS.INTL", NOID, NOID, 2, 4, V, { VR, VR, VR, RX }, FuncFlags::MACROCALL },
683 { "COM.MICROSOFT.WORKDAY.INTL", "WORKDAY.INTL", NOID, NOID, 2, 4, V, { VR, VR, VR, RX }, FuncFlags::MACROCALL }
684 };
685
686 /** Functions new in Excel 2010.
687
688 A lot of statistical functions have been renamed (although the 'old' function name still is valid).
689 See http://office.microsoft.com/en-us/excel-help/what-s-new-changes-made-to-excel-functions-HA010355760.aspx
690
691 Functions with FuncFlags::IMPORTONLY are rewritten in
692 sc/source/filter/excel/xeformula.cxx during export for
693 BIFF, OOXML export uses this different mapping here but still uses the
694 mapping there to determine the feature set.
695
696 FIXME: either have the exporter determine the feature set from the active
697 mapping, preferred, or enhance that mapping there such that for OOXML the
698 rewrite can be overridden.
699
700 @See sc/source/filter/excel/xlformula.cxx saFuncTable_2010
701 */
702 /* FIXME: BIFF12 function identifiers available? Where to obtain? */
703 const FunctionData saFuncTable2010[] =
704 {
705 { "COM.MICROSOFT.COVARIANCE.P", "COVARIANCE.P", NOID, NOID, 2, 2, V, { VA }, FuncFlags::MACROCALL_NEW },
706 { "COM.MICROSOFT.COVARIANCE.S", "COVARIANCE.S", NOID, NOID, 2, 2, V, { VA }, FuncFlags::MACROCALL_NEW },
707 { "COM.MICROSOFT.STDEV.P", "STDEV.P", NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
708 { "COM.MICROSOFT.STDEV.S", "STDEV.S", NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
709 { "COM.MICROSOFT.VAR.P", "VAR.P" , NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
710 { "COM.MICROSOFT.VAR.S", "VAR.S", NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
711 { "COM.MICROSOFT.BETA.DIST", "BETA.DIST" , NOID, NOID, 4, 6, V, { VR }, FuncFlags::MACROCALL_NEW },
712 { "COM.MICROSOFT.BETA.INV", "BETA.INV", NOID, NOID, 3, 5, V, { VR }, FuncFlags::MACROCALL_NEW },
713 { "COM.MICROSOFT.BINOM.DIST", "BINOM.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
714 { "COM.MICROSOFT.BINOM.INV", "BINOM.INV", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
715 { "COM.MICROSOFT.CHISQ.DIST", "CHISQ.DIST", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
716 { "COM.MICROSOFT.CHISQ.INV", "CHISQ.INV", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
717 { "COM.MICROSOFT.CHISQ.DIST.RT", "CHISQ.DIST.RT", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
718 { "COM.MICROSOFT.CHISQ.INV.RT", "CHISQ.INV.RT", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
719 { "COM.MICROSOFT.CHISQ.TEST", "CHISQ.TEST", NOID, NOID, 2, 2, V, { VA }, FuncFlags::MACROCALL_NEW },
720 { "COM.MICROSOFT.CONFIDENCE.NORM", "CONFIDENCE.NORM", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
721 { "COM.MICROSOFT.CONFIDENCE.T", "CONFIDENCE.T", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
722 { "FDIST", "F.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
723 { "COM.MICROSOFT.F.DIST.RT", "F.DIST.RT", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
724 { "FINV", "F.INV", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
725 { "COM.MICROSOFT.F.INV.RT", "F.INV.RT", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
726 { "COM.MICROSOFT.F.TEST", "F.TEST", NOID, NOID, 2, 2, V, { VA }, FuncFlags::MACROCALL_NEW },
727 { "COM.MICROSOFT.EXPON.DIST", "EXPON.DIST", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
728 { "COM.MICROSOFT.HYPGEOM.DIST", "HYPGEOM.DIST", NOID, NOID, 5, 5, V, { VR }, FuncFlags::MACROCALL_NEW },
729 { "COM.MICROSOFT.POISSON.DIST", "POISSON.DIST", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
730 { "COM.MICROSOFT.WEIBULL.DIST", "WEIBULL.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
731 { "COM.MICROSOFT.GAMMA.DIST", "GAMMA.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
732 { "COM.MICROSOFT.GAMMA.INV", "GAMMA.INV", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
733 { "COM.MICROSOFT.GAMMALN.PRECISE", "GAMMALN.PRECISE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
734 { "COM.MICROSOFT.LOGNORM.DIST", "LOGNORM.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
735 { "COM.MICROSOFT.LOGNORM.INV", "LOGNORM.INV", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
736 { "COM.MICROSOFT.NORM.DIST", "NORM.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
737 { "COM.MICROSOFT.NORM.INV", "NORM.INV", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
738 { "COM.MICROSOFT.NORM.S.DIST", "NORM.S.DIST", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
739 { "COM.MICROSOFT.NORM.S.INV", "NORM.S.INV", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
740 { "COM.MICROSOFT.T.DIST", "T.DIST", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
741 { "COM.MICROSOFT.T.DIST.2T", "T.DIST.2T", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
742 { "COM.MICROSOFT.T.DIST.RT", "T.DIST.RT", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
743 { "COM.MICROSOFT.T.INV", "T.INV", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
744 { "COM.MICROSOFT.T.INV.2T", "T.INV.2T", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
745 { "COM.MICROSOFT.T.TEST", "T.TEST", NOID, NOID, 4, 4, V, { VA, VA, VR }, FuncFlags::MACROCALL_NEW },
746 { "COM.MICROSOFT.PERCENTILE.INC", "PERCENTILE.INC", NOID, NOID, 2, 2, V, { RX, VR }, FuncFlags::MACROCALL_NEW },
747 { "COM.MICROSOFT.PERCENTRANK.INC", "PERCENTRANK.INC", NOID, NOID, 2, 3, V, { RX, VR, VR_E }, FuncFlags::MACROCALL_NEW },
748 { "COM.MICROSOFT.QUARTILE.INC", "QUARTILE.INC", NOID, NOID, 2, 2, V, { RX, VR }, FuncFlags::MACROCALL_NEW },
749 { "COM.MICROSOFT.RANK.EQ", "RANK.EQ", NOID, NOID, 2, 3, V, { VR, RO, VR }, FuncFlags::MACROCALL_NEW },
750 { "COM.MICROSOFT.PERCENTILE.EXC", "PERCENTILE.EXC", NOID, NOID, 2, 2, V, { RX, VR }, FuncFlags::MACROCALL_NEW },
751 { "COM.MICROSOFT.PERCENTRANK.EXC", "PERCENTRANK.EXC", NOID, NOID, 2, 3, V, { RX, VR, VR_E }, FuncFlags::MACROCALL_NEW },
752 { "COM.MICROSOFT.QUARTILE.EXC", "QUARTILE.EXC", NOID, NOID, 2, 2, V, { RX, VR }, FuncFlags::MACROCALL_NEW },
753 { "COM.MICROSOFT.RANK.AVG", "RANK.AVG", NOID, NOID, 2, 3, V, { VR, RO, VR }, FuncFlags::MACROCALL_NEW },
754 { "COM.MICROSOFT.MODE.SNGL", "MODE.SNGL", NOID, NOID, 1, MX, V, { VA }, FuncFlags::MACROCALL_NEW },
755 { "COM.MICROSOFT.MODE.MULT", "MODE.MULT", NOID, NOID, 1, MX, V, { VA }, FuncFlags::MACROCALL_NEW },
756 { "COM.MICROSOFT.NEGBINOM.DIST", "NEGBINOM.DIST", NOID, NOID, 4, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
757 { "COM.MICROSOFT.Z.TEST", "Z.TEST", NOID, NOID, 2, 3, V, { RX, VR }, FuncFlags::MACROCALL_NEW },
758 { "COM.MICROSOFT.CEILING.PRECISE", "CEILING.PRECISE", NOID, NOID, 1, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
759 { "COM.MICROSOFT.FLOOR.PRECISE", "FLOOR.PRECISE", NOID, NOID, 1, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
760 { "COM.MICROSOFT.ERF.PRECISE", "ERF.PRECISE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
761 { "COM.MICROSOFT.ERFC.PRECISE", "ERFC.PRECISE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
762 { "COM.MICROSOFT.AGGREGATE", "AGGREGATE", NOID, NOID, 3, MX, V, { VR, RO }, FuncFlags::MACROCALL_NEW }
763 };
764
765 /** Functions new in Excel 2013.
766
767 See http://office.microsoft.com/en-us/excel-help/new-functions-in-excel-2013-HA103980604.aspx
768 Most functions apparently were added for ODF1.2 ODFF / OpenFormula
769 compatibility.
770
771 Functions with FuncFlags::IMPORTONLY are rewritten in
772 sc/source/filter/excel/xeformula.cxx during export for
773 BIFF, OOXML export uses this different mapping here but still uses the
774 mapping there to determine the feature set.
775
776 FIXME: either have the exporter determine the feature set from the active
777 mapping, preferred, or enhance that mapping there such that for OOXML the
778 rewrite can be overridden.
779
780 @See sc/source/filter/excel/xlformula.cxx saFuncTable_2013
781 */
782 /* FIXME: BIFF12 function identifiers available? Where to obtain? */
783 const FunctionData saFuncTable2013[] =
784 {
785 { "ACOT", "ACOT", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
786 { "ACOTH", "ACOTH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
787 { "ARABIC", "ARABIC", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
788 { "BASE", "BASE", NOID, NOID, 2, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
789 { "BINOM.DIST.RANGE", "BINOM.DIST.RANGE", NOID, NOID, 3, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
790 { "BITAND", "BITAND", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
791 { "BITLSHIFT", "BITLSHIFT", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
792 { "BITOR", "BITOR", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
793 { "BITRSHIFT", "BITRSHIFT", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
794 { "BITXOR", "BITXOR", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
795 { "COM.MICROSOFT.CEILING.MATH", "CEILING.MATH", NOID, NOID, 1, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
796 { "CEILING", "CEILING.MATH", NOID, NOID, 1, 3, V, { VR }, FuncFlags::EXPORTONLY | FuncFlags::MACROCALL_NEW },
797 { "COMBINA", "COMBINA", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
798 { "COT", "COT", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
799 { "COTH", "COTH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
800 { "CSC", "CSC", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
801 { "CSCH", "CSCH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
802 { "DAYS", "DAYS", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
803 { "DECIMAL", "DECIMAL", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
804 { "COM.MICROSOFT.ENCODEURL","ENCODEURL", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
805 { "COM.MICROSOFT.FILTERXML","FILTERXML", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
806 { "COM.MICROSOFT.FLOOR.MATH", "FLOOR.MATH", NOID, NOID, 1, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
807 { "FLOOR", "FLOOR.MATH", NOID, NOID, 1, 3, V, { VR }, FuncFlags::EXPORTONLY | FuncFlags::MACROCALL_NEW },
808 // NOTE: this FDIST is not our LEGACY.FDIST
809 { nullptr/*"FDIST"*/, "FDIST", NOID, NOID, 3, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
810 // NOTE: this FINV is not our LEGACY.FINV
811 { nullptr/*"FINV"*/, "FINV", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
812 { "FORMULA", "FORMULATEXT", NOID, NOID, 1, 1, V, { RO }, FuncFlags::MACROCALL_NEW },
813 { "GAMMA", "GAMMA", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
814 { "GAUSS", "GAUSS", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
815 { "IFNA", "IFNA", NOID, NOID, 2, 2, V, { VO, RO }, FuncFlags::MACROCALL_NEW },
816 { "IMCOSH", "IMCOSH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
817 { "IMCOT", "IMCOT", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
818 { "IMCSC", "IMCSC", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
819 { "IMCSCH", "IMCSCH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
820 { "IMSEC", "IMSEC", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
821 { "IMSECH", "IMSECH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
822 { "IMSINH", "IMSINH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
823 { "IMTAN", "IMTAN", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
824 { "ISFORMULA", "ISFORMULA", NOID, NOID, 1, 1, V, { RO }, FuncFlags::MACROCALL_NEW },
825 { "ISOWEEKNUM", "ISOWEEKNUM", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
826 { "MUNIT", "MUNIT", NOID, NOID, 1, 1, A, { VR }, FuncFlags::MACROCALL_NEW },
827 { "NUMBERVALUE", "NUMBERVALUE", NOID, NOID, 1, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
828 { "PDURATION", "PDURATION", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
829 { "PERMUTATIONA", "PERMUTATIONA", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW },
830 { "PHI", "PHI", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
831 { "RRI", "RRI", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
832 { "SEC", "SEC", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
833 { "SECH", "SECH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
834 { "SHEET", "SHEET", NOID, NOID, 0, 1, V, { RO }, FuncFlags::MACROCALL_NEW },
835 { "SHEETS", "SHEETS", NOID, NOID, 0, 1, V, { RO }, FuncFlags::MACROCALL_NEW },
836 { "SKEWP", "SKEW.P", NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
837 { "UNICHAR", "UNICHAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
838 { "UNICODE", "UNICODE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
839 { "COM.MICROSOFT.WEBSERVICE","WEBSERVICE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
840 { "XOR", "XOR", NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW }
841 };
842
843 /** Functions new in Excel 2016.
844
845 See https://support.office.com/en-us/article/Forecasting-functions-897a2fe9-6595-4680-a0b0-93e0308d5f6e?ui=en-US&rs=en-US&ad=US#_forecast.ets
846 and https://support.office.com/en-us/article/What-s-New-and-Improved-in-Office-2016-for-Office-365-95c8d81d-08ba-42c1-914f-bca4603e1426?ui=en-US&rs=en-US&ad=US
847
848 @See sc/source/filter/excel/xlformula.cxx saFuncTable_2016
849 */
850 /* FIXME: BIFF12 function identifiers available? Where to obtain? */
851 const FunctionData saFuncTable2016[] =
852 {
853 { "COM.MICROSOFT.FORECAST.ETS", "FORECAST.ETS", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
854 { "COM.MICROSOFT.FORECAST.ETS.CONFINT", "FORECAST.ETS.CONFINT", NOID, NOID, 4, 7, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
855 { "COM.MICROSOFT.FORECAST.ETS.SEASONALITY", "FORECAST.ETS.SEASONALITY", NOID, NOID, 2, 4, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
856 { "COM.MICROSOFT.FORECAST.ETS.STAT", "FORECAST.ETS.STAT", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
857 { "COM.MICROSOFT.FORECAST.LINEAR", "FORECAST.LINEAR", NOID, NOID, 3, 3, V, { VR, VA }, FuncFlags::MACROCALL_NEW },
858 { "COM.MICROSOFT.CONCAT", "CONCAT", NOID, NOID, 1, MX, V, { VR }, FuncFlags::MACROCALL_NEW },
859 { "COM.MICROSOFT.TEXTJOIN", "TEXTJOIN", NOID, NOID, 3, MX, V, { VR }, FuncFlags::MACROCALL_NEW },
860 { "COM.MICROSOFT.IFS", "IFS", NOID, NOID, 2, MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW },
861 { "COM.MICROSOFT.SWITCH", "SWITCH", NOID, NOID, 3, MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW },
862 { "COM.MICROSOFT.MINIFS", "MINIFS", NOID, NOID, 3, MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW },
863 { "COM.MICROSOFT.MAXIFS", "MAXIFS", NOID, NOID, 3, MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW }
864 };
865
866
867 /** Functions defined by OpenFormula, but not supported by Calc or by Excel. */
868 const FunctionData saFuncTableOdf[] =
869 {
870 { "CHISQDIST", nullptr, NOID, NOID, 2, 3, V, { VR }, FuncFlags::MACROCALLODF },
871 { "CHISQINV", nullptr, NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALLODF }
872 };
873
874 /** Functions defined by Calc, but not in OpenFormula nor supported by Excel. */
875 const FunctionData saFuncTableOOoLO[] =
876 {
877 { "ORG.OPENOFFICE.WEEKS", "ORG.OPENOFFICE.WEEKS", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
878 { "ORG.OPENOFFICE.MONTHS", "ORG.OPENOFFICE.MONTHS", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
879 { "ORG.OPENOFFICE.YEARS", "ORG.OPENOFFICE.YEARS", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
880 { "ORG.OPENOFFICE.ISLEAPYEAR", "ORG.OPENOFFICE.ISLEAPYEAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
881 { "ORG.OPENOFFICE.DAYSINMONTH", "ORG.OPENOFFICE.DAYSINMONTH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
882 { "ORG.OPENOFFICE.DAYSINYEAR", "ORG.OPENOFFICE.DAYSINYEAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
883 { "ORG.OPENOFFICE.WEEKSINYEAR", "ORG.OPENOFFICE.WEEKSINYEAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
884 { "ORG.OPENOFFICE.ROT13", "ORG.OPENOFFICE.ROT13", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
885 /* Next 8 lines are for importing from .xlsx files saved by Calc before
886 * fdo#59727 was patched with the entries above. */
887 { "ORG.OPENOFFICE.WEEKS", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFWEEKS", NOID, NOID, 3, 3, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
888 { "ORG.OPENOFFICE.MONTHS", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFMONTHS", NOID, NOID, 3, 3, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
889 { "ORG.OPENOFFICE.YEARS", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFYEARS", NOID, NOID, 3, 3, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
890 { "ORG.OPENOFFICE.ISLEAPYEAR", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETISLEAPYEAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
891 { "ORG.OPENOFFICE.DAYSINMONTH", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINMONTH", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
892 { "ORG.OPENOFFICE.DAYSINYEAR", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINYEAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
893 { "ORG.OPENOFFICE.WEEKSINYEAR", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETWEEKSINYEAR", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
894 { "ORG.OPENOFFICE.ROT13", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETROT13", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
895 // More functions written wrongly in the past.
896 { "ORG.OPENOFFICE.ERRORTYPE", "ORG.OPENOFFICE.ERRORTYPE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
897 { "ORG.OPENOFFICE.MULTIRANGE", "ORG.OPENOFFICE.MULTIRANGE", NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
898 { "ORG.OPENOFFICE.GOALSEEK", "ORG.OPENOFFICE.GOALSEEK", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
899 { "ORG.OPENOFFICE.EASTERSUNDAY","ORG.OPENOFFICE.EASTERSUNDAY", NOID, NOID, 1, 1, V, { VR }, FuncFlags::MACROCALL_NEW },
900 { "ORG.OPENOFFICE.CURRENT", "ORG.OPENOFFICE.CURRENT", NOID, NOID, 0, 0, V, { VR }, FuncFlags::MACROCALL_NEW },
901 { "ORG.OPENOFFICE.STYLE", "ORG.OPENOFFICE.STYLE", NOID, NOID, 1, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
902 // And the import for the wrongly written functions even without _xlfn.
903 { "ORG.OPENOFFICE.ERRORTYPE", "ERRORTYPE", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY },
904 { "ORG.OPENOFFICE.MULTIRANGE", "MULTIRANGE", NOID, NOID, 1, MX, V, { RX }, FuncFlags::IMPORTONLY },
905 { "ORG.OPENOFFICE.GOALSEEK", "GOALSEEK", NOID, NOID, 3, 3, V, { VR }, FuncFlags::IMPORTONLY },
906 { "ORG.OPENOFFICE.EASTERSUNDAY","EASTERSUNDAY", NOID, NOID, 1, 1, V, { VR }, FuncFlags::IMPORTONLY },
907 { "ORG.OPENOFFICE.CURRENT", "CURRENT", NOID, NOID, 0, 0, V, { VR }, FuncFlags::IMPORTONLY },
908 { "ORG.OPENOFFICE.STYLE", "STYLE", NOID, NOID, 1, 3, V, { VR }, FuncFlags::IMPORTONLY },
909 // Other functions.
910 { "ORG.OPENOFFICE.CONVERT", "ORG.OPENOFFICE.CONVERT", NOID, NOID, 3, 3, V, { VR }, FuncFlags::MACROCALL_NEW },
911 { "ORG.LIBREOFFICE.COLOR", "ORG.LIBREOFFICE.COLOR", NOID, NOID, 3, 4, V, { VR }, FuncFlags::MACROCALL_NEW },
912 { "ORG.LIBREOFFICE.RAWSUBTRACT","ORG.LIBREOFFICE.RAWSUBTRACT",NOID, NOID, 1, MX, V, { RX }, FuncFlags::MACROCALL_NEW },
913 { "ORG.LIBREOFFICE.FORECAST.ETS.MULT", "ORG.LIBREOFFICE.FORECAST.ETS.MULT", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
914 { "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT", "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT", NOID, NOID, 4, 7, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
915 { "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
916 { "ORG.LIBREOFFICE.ROUNDSIG", "ORG.LIBREOFFICE.ROUNDSIG", NOID, NOID, 2, 2, V, { RX }, FuncFlags::MACROCALL_NEW },
917 { "ORG.LIBREOFFICE.REGEX", "ORG.LIBREOFFICE.REGEX", NOID, NOID, 2, 4, V, { RX }, FuncFlags::MACROCALL_NEW },
918 { "ORG.LIBREOFFICE.FOURIER", "ORG.LIBREOFFICE.FOURIER", NOID, NOID, 2, 5, A, { RX }, FuncFlags::MACROCALL_NEW },
919 { "ORG.LIBREOFFICE.RAND.NV", "ORG.LIBREOFFICE.RAND.NV", NOID, NOID, 0, 0, V, {}, FuncFlags::MACROCALL_NEW },
920 { "ORG.LIBREOFFICE.RANDBETWEEN.NV", "ORG.LIBREOFFICE.RANDBETWEEN.NV", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW }
921
922 };
923
924 const sal_Unicode API_TOKEN_OPEN = '(';
925 const sal_Unicode API_TOKEN_CLOSE = ')';
926 const sal_Unicode API_TOKEN_SEP = ';';
927
928 const sal_Unicode API_TOKEN_ARRAY_OPEN = '{';
929 const sal_Unicode API_TOKEN_ARRAY_CLOSE = '}';
930 const sal_Unicode API_TOKEN_ARRAY_ROWSEP = '|';
931 const sal_Unicode API_TOKEN_ARRAY_COLSEP = ';';
932
933 } // namespace
934
935 // function info parameter class iterator =====================================
936
FunctionParamInfoIterator(const FunctionInfo & rFuncInfo)937 FunctionParamInfoIterator::FunctionParamInfoIterator( const FunctionInfo& rFuncInfo ) :
938 mpParamInfo( rFuncInfo.mpParamInfos ),
939 mpParamInfoEnd( rFuncInfo.mpParamInfos + FUNCINFO_PARAMINFOCOUNT ),
940 mbParamPairs( rFuncInfo.mbParamPairs )
941 {
942 }
943
isCalcOnlyParam() const944 bool FunctionParamInfoIterator::isCalcOnlyParam() const
945 {
946 return mpParamInfo && (mpParamInfo->meValid == FuncParamValidity::CalcOnly);
947 }
948
isExcelOnlyParam() const949 bool FunctionParamInfoIterator::isExcelOnlyParam() const
950 {
951 return mpParamInfo && (mpParamInfo->meValid == FuncParamValidity::ExcelOnly);
952 }
953
operator ++()954 FunctionParamInfoIterator& FunctionParamInfoIterator::operator++()
955 {
956 if( mpParamInfo )
957 {
958 // move pointer to next entry, if something explicit follows
959 if( mpParamInfo + 1 < mpParamInfoEnd )
960 ++mpParamInfo;
961 // if last parameter type is 'Excel-only' or 'Calc-only', do not repeat it
962 else if( isExcelOnlyParam() || isCalcOnlyParam() )
963 mpParamInfo = nullptr;
964 // points to last info, but parameter pairs expected, move to previous info
965 else if( mbParamPairs )
966 --mpParamInfo;
967 // otherwise: repeat last parameter class
968 }
969 return *this;
970 }
971
972 // function provider ==========================================================
973
974 struct FunctionProviderImpl
975 {
976 typedef RefMap< OUString, FunctionInfo > FuncNameMap;
977 typedef RefMap< sal_uInt16, FunctionInfo > FuncIdMap;
978
979 FunctionInfoVector maFuncs; /// All function infos in one list.
980 FuncNameMap maOoxFuncs; /// Maps OOXML function names to function data.
981 FuncIdMap maBiff12Funcs; /// Maps BIFF12 function indexes to function data.
982 FuncIdMap maBiffFuncs; /// Maps BIFF2-BIFF8 function indexes to function data.
983 FuncNameMap maMacroFuncs; /// Maps macro function names to function data.
984
985 explicit FunctionProviderImpl(bool bImportFilter);
986
987 private:
988 /** Creates and inserts a function info struct from the passed function data. */
989 void initFunc(const FunctionData& rFuncData);
990
991 /** Initializes the members from the passed function data list. */
992 void initFuncs(const FunctionData* pBeg, const FunctionData* pEnd, bool bImportFilter);
993 };
994
FunctionProviderImpl(bool bImportFilter)995 FunctionProviderImpl::FunctionProviderImpl( bool bImportFilter )
996 {
997 /* Add functions supported in the current BIFF version only. Function
998 tables from later BIFF versions may overwrite single functions from
999 earlier tables. */
1000 initFuncs(saFuncTableBiff2, saFuncTableBiff2 + SAL_N_ELEMENTS(saFuncTableBiff2), bImportFilter);
1001 initFuncs(saFuncTableBiff3, saFuncTableBiff3 + SAL_N_ELEMENTS(saFuncTableBiff3), bImportFilter);
1002 initFuncs(saFuncTableBiff4, saFuncTableBiff4 + SAL_N_ELEMENTS(saFuncTableBiff4), bImportFilter);
1003 initFuncs(saFuncTableBiff5, saFuncTableBiff5 + SAL_N_ELEMENTS(saFuncTableBiff5), bImportFilter);
1004 initFuncs(saFuncTableBiff8, saFuncTableBiff8 + SAL_N_ELEMENTS(saFuncTableBiff8), bImportFilter);
1005 initFuncs(saFuncTableOox , saFuncTableOox + SAL_N_ELEMENTS(saFuncTableOox ), bImportFilter);
1006 initFuncs(saFuncTable2010 , saFuncTable2010 + SAL_N_ELEMENTS(saFuncTable2010 ), bImportFilter);
1007 initFuncs(saFuncTable2013 , saFuncTable2013 + SAL_N_ELEMENTS(saFuncTable2013 ), bImportFilter);
1008 initFuncs(saFuncTable2016 , saFuncTable2016 + SAL_N_ELEMENTS(saFuncTable2016 ), bImportFilter);
1009 initFuncs(saFuncTableOdf , saFuncTableOdf + SAL_N_ELEMENTS(saFuncTableOdf ), bImportFilter);
1010 initFuncs(saFuncTableOOoLO, saFuncTableOOoLO + SAL_N_ELEMENTS(saFuncTableOOoLO), bImportFilter);
1011 }
1012
initFunc(const FunctionData & rFuncData)1013 void FunctionProviderImpl::initFunc(const FunctionData& rFuncData)
1014 {
1015 // create a function info object
1016 FunctionInfoRef xFuncInfo = std::make_shared<FunctionInfo>();
1017 if( rFuncData.mpcOdfFuncName )
1018 xFuncInfo->maOdfFuncName = OUString::createFromAscii( rFuncData.mpcOdfFuncName );
1019 if( rFuncData.mpcOoxFuncName )
1020 xFuncInfo->maOoxFuncName = OUString::createFromAscii( rFuncData.mpcOoxFuncName );
1021
1022 if( rFuncData.mnFlags & FuncFlags::MACROCALL )
1023 {
1024 OSL_ENSURE( !xFuncInfo->maOoxFuncName.isEmpty(), "FunctionProviderImpl::initFunc - missing OOXML function name" );
1025 OSL_ENSURE( !(rFuncData.mnFlags & FuncFlags::MACROCALLODF ), "FunctionProviderImpl::initFunc - unexpected flag FuncFlags::MACROCALLODF" );
1026 xFuncInfo->maBiffMacroName = "_xlfn." + xFuncInfo->maOoxFuncName;
1027 if( rFuncData.mnFlags & FuncFlags::MACROCALL_FN )
1028 {
1029 xFuncInfo->maOoxFuncName = "_xlfn." + xFuncInfo->maOoxFuncName;
1030 //! From here on maOoxFuncName contains the _xlfn. prefix!
1031 }
1032 }
1033 else if( rFuncData.mnFlags & FuncFlags::MACROCALLODF )
1034 {
1035 OSL_ENSURE( !xFuncInfo->maOdfFuncName.isEmpty(), "FunctionProviderImpl::initFunc - missing ODF function name" );
1036 xFuncInfo->maBiffMacroName = "_xlfnodf." + xFuncInfo->maOdfFuncName;
1037 }
1038 xFuncInfo->meFuncLibType = (rFuncData.mnFlags & FuncFlags::EUROTOOL) ? FUNCLIB_EUROTOOL : FUNCLIB_UNKNOWN;
1039 xFuncInfo->mnApiOpCode = -1;
1040 xFuncInfo->mnBiff12FuncId = rFuncData.mnBiff12FuncId;
1041 xFuncInfo->mnBiffFuncId = rFuncData.mnBiffFuncId;
1042 xFuncInfo->mnMinParamCount = rFuncData.mnMinParamCount;
1043 xFuncInfo->mnMaxParamCount = (rFuncData.mnMaxParamCount == MX) ? OOX_MAX_PARAMCOUNT : rFuncData.mnMaxParamCount;
1044 xFuncInfo->mnRetClass = rFuncData.mnRetClass;
1045 xFuncInfo->mpParamInfos = rFuncData.mpParamInfos;
1046 xFuncInfo->mbParamPairs = bool(rFuncData.mnFlags & FuncFlags::PARAMPAIRS);
1047 xFuncInfo->mbVolatile = bool(rFuncData.mnFlags & FuncFlags::VOLATILE);
1048 xFuncInfo->mbExternal = bool(rFuncData.mnFlags & FuncFlags::EXTERNAL);
1049 xFuncInfo->mbInternal = !xFuncInfo->mbExternal || ( rFuncData.mnFlags & FuncFlags::INTERNAL );
1050 bool bMacroCmd(rFuncData.mnFlags & FuncFlags::MACROCMD);
1051 xFuncInfo->mbMacroFunc = bMacroCmd || ( rFuncData.mnFlags & FuncFlags::MACROFUNC );
1052 xFuncInfo->mbVarParam = bMacroCmd || (rFuncData.mnMinParamCount != rFuncData.mnMaxParamCount) || ( rFuncData.mnFlags & FuncFlags::ALWAYSVAR );
1053
1054 setFlag( xFuncInfo->mnBiff12FuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
1055 setFlag( xFuncInfo->mnBiffFuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
1056
1057 // insert the function info into the member maps
1058 maFuncs.push_back( xFuncInfo );
1059 if( !xFuncInfo->maOoxFuncName.isEmpty() )
1060 maOoxFuncs[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
1061 if( xFuncInfo->mnBiff12FuncId != NOID )
1062 maBiff12Funcs[ xFuncInfo->mnBiff12FuncId ] = xFuncInfo;
1063 if( xFuncInfo->mnBiffFuncId != NOID )
1064 maBiffFuncs[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
1065 if( !xFuncInfo->maBiffMacroName.isEmpty() )
1066 maMacroFuncs[ xFuncInfo->maBiffMacroName ] = xFuncInfo;
1067 }
1068
initFuncs(const FunctionData * pBeg,const FunctionData * pEnd,bool bImportFilter)1069 void FunctionProviderImpl::initFuncs(const FunctionData* pBeg, const FunctionData* pEnd, bool bImportFilter)
1070 {
1071 for( const FunctionData* pIt = pBeg; pIt != pEnd; ++pIt )
1072 if( pIt->isSupported(bImportFilter) )
1073 initFunc(*pIt);
1074 }
1075
FunctionProvider(bool bImportFilter)1076 FunctionProvider::FunctionProvider( bool bImportFilter ) :
1077 mxFuncImpl( std::make_shared<FunctionProviderImpl>( bImportFilter ) )
1078 {
1079 }
1080
~FunctionProvider()1081 FunctionProvider::~FunctionProvider()
1082 {
1083 }
1084
getFuncInfoFromOoxFuncName(const OUString & rFuncName) const1085 const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
1086 {
1087 return mxFuncImpl->maOoxFuncs.get( rFuncName ).get();
1088 }
1089
getFuncInfoFromBiff12FuncId(sal_uInt16 nFuncId) const1090 const FunctionInfo* FunctionProvider::getFuncInfoFromBiff12FuncId( sal_uInt16 nFuncId ) const
1091 {
1092 return mxFuncImpl->maBiff12Funcs.get( nFuncId ).get();
1093 }
1094
getFuncInfoFromMacroName(const OUString & rFuncName) const1095 const FunctionInfo* FunctionProvider::getFuncInfoFromMacroName( const OUString& rFuncName ) const
1096 {
1097 return mxFuncImpl->maMacroFuncs.get( rFuncName ).get();
1098 }
1099
getFuncLibTypeFromLibraryName(const OUString & rLibraryName)1100 FunctionLibraryType FunctionProvider::getFuncLibTypeFromLibraryName( const OUString& rLibraryName )
1101 {
1102 // the EUROTOOL add-in containing the EUROCONVERT function
1103 if( rLibraryName.equalsIgnoreAsciiCase("EUROTOOL.XLA")
1104 || rLibraryName.equalsIgnoreAsciiCase("EUROTOOL.XLAM"))
1105 return FUNCLIB_EUROTOOL;
1106
1107 // default: unknown library
1108 return FUNCLIB_UNKNOWN;
1109 }
1110
getFuncs() const1111 const FunctionInfoVector& FunctionProvider::getFuncs() const
1112 {
1113 return mxFuncImpl->maFuncs;
1114 }
1115
1116 // op-code and function provider ==============================================
1117
1118 struct OpCodeProviderImpl : public ApiOpCodes
1119 {
1120 typedef RefMap< sal_Int32, FunctionInfo > OpCodeFuncMap;
1121 typedef RefMap< OUString, FunctionInfo > FuncNameMap;
1122 typedef ::std::vector< FormulaOpCodeMapEntry > OpCodeEntryVector;
1123
1124 OpCodeFuncMap maOpCodeFuncs; /// Maps API function op-codes to function data.
1125 FuncNameMap maExtProgFuncs; /// Maps programmatical API function names to function data.
1126 OpCodeEntryVector maParserMap; /// OOXML token mapping for formula parser service.
1127
1128 explicit OpCodeProviderImpl(
1129 const FunctionInfoVector& rFuncInfos,
1130 const Reference< XMultiServiceFactory >& rxModelFactory );
1131
1132 private:
1133 typedef ::std::map< OUString, ApiToken > ApiTokenMap;
1134 typedef Sequence< FormulaOpCodeMapEntry > OpCodeEntrySequence;
1135
1136 static bool fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
1137 static bool fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
1138 bool fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const;
1139
1140 static bool initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
1141 bool initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName );
1142 bool initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const char* pcOdfName, const char* pcOoxName );
1143 bool initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName );
1144
1145 bool initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap );
1146 bool initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos );
1147 };
1148
OpCodeProviderImpl(const FunctionInfoVector & rFuncInfos,const Reference<XMultiServiceFactory> & rxModelFactory)1149 OpCodeProviderImpl::OpCodeProviderImpl( const FunctionInfoVector& rFuncInfos,
1150 const Reference< XMultiServiceFactory >& rxModelFactory )
1151 {
1152 if( !rxModelFactory.is() )
1153 return;
1154
1155 try
1156 {
1157 Reference< XFormulaOpCodeMapper > xMapper( rxModelFactory->createInstance(
1158 "com.sun.star.sheet.FormulaOpCodeMapper" ), UNO_QUERY_THROW );
1159
1160 // op-codes provided as attributes
1161 OPCODE_UNKNOWN = xMapper->getOpCodeUnknown();
1162 OPCODE_EXTERNAL = xMapper->getOpCodeExternal();
1163
1164 using namespace ::com::sun::star::sheet::FormulaMapGroup;
1165 using namespace ::com::sun::star::sheet::FormulaMapGroupSpecialOffset;
1166
1167 OpCodeEntrySequence aEntrySeq;
1168 ApiTokenMap aTokenMap, aExtFuncTokenMap;
1169 bool bIsValid =
1170 // special
1171 fillEntrySeq( aEntrySeq, xMapper, SPECIAL ) &&
1172 initOpCode( OPCODE_PUSH, aEntrySeq, PUSH ) &&
1173 initOpCode( OPCODE_MISSING, aEntrySeq, MISSING ) &&
1174 initOpCode( OPCODE_SPACES, aEntrySeq, SPACES ) &&
1175 initOpCode( OPCODE_NAME, aEntrySeq, NAME ) &&
1176 initOpCode( OPCODE_DBAREA, aEntrySeq, DB_AREA ) &&
1177 initOpCode( OPCODE_NLR, aEntrySeq, COL_ROW_NAME ) &&
1178 initOpCode( OPCODE_MACRO, aEntrySeq, MACRO ) &&
1179 initOpCode( OPCODE_BAD, aEntrySeq, BAD ) &&
1180 initOpCode( OPCODE_NONAME, aEntrySeq, NO_NAME ) &&
1181 // separators
1182 fillTokenMap( aTokenMap, aEntrySeq, xMapper, SEPARATORS ) &&
1183 initOpCode( OPCODE_OPEN, aTokenMap, API_TOKEN_OPEN, '(' ) &&
1184 initOpCode( OPCODE_CLOSE, aTokenMap, API_TOKEN_CLOSE, ')' ) &&
1185 initOpCode( OPCODE_SEP, aTokenMap, API_TOKEN_SEP, ',' ) &&
1186 // array separators
1187 fillTokenMap( aTokenMap, aEntrySeq, xMapper, ARRAY_SEPARATORS ) &&
1188 initOpCode( OPCODE_ARRAY_OPEN, aTokenMap, API_TOKEN_ARRAY_OPEN, '{' ) &&
1189 initOpCode( OPCODE_ARRAY_CLOSE, aTokenMap, API_TOKEN_ARRAY_CLOSE, '}' ) &&
1190 initOpCode( OPCODE_ARRAY_ROWSEP, aTokenMap, API_TOKEN_ARRAY_ROWSEP, ';' ) &&
1191 initOpCode( OPCODE_ARRAY_COLSEP, aTokenMap, API_TOKEN_ARRAY_COLSEP, ',' ) &&
1192 // unary operators
1193 fillTokenMap( aTokenMap, aEntrySeq, xMapper, UNARY_OPERATORS ) &&
1194 initOpCode( OPCODE_PLUS_SIGN, aTokenMap, '+', '\0' ) && // same op-code as OPCODE_ADD
1195 initOpCode( OPCODE_MINUS_SIGN, aTokenMap, '-', '-' ) &&
1196 initOpCode( OPCODE_PERCENT, aTokenMap, '%', '%' ) &&
1197 // binary operators
1198 fillTokenMap( aTokenMap, aEntrySeq, xMapper, BINARY_OPERATORS ) &&
1199 initOpCode( OPCODE_ADD, aTokenMap, '+', '+' ) &&
1200 initOpCode( OPCODE_SUB, aTokenMap, '-', '-' ) &&
1201 initOpCode( OPCODE_MULT, aTokenMap, '*', '*' ) &&
1202 initOpCode( OPCODE_DIV, aTokenMap, '/', '/' ) &&
1203 initOpCode( OPCODE_POWER, aTokenMap, '^', '^' ) &&
1204 initOpCode( OPCODE_CONCAT, aTokenMap, '&', '&' ) &&
1205 initOpCode( OPCODE_EQUAL, aTokenMap, '=', '=' ) &&
1206 initOpCode( OPCODE_NOT_EQUAL, aTokenMap, "<>", "<>" ) &&
1207 initOpCode( OPCODE_LESS, aTokenMap, '<', '<' ) &&
1208 initOpCode( OPCODE_LESS_EQUAL, aTokenMap, "<=", "<=" ) &&
1209 initOpCode( OPCODE_GREATER, aTokenMap, '>', '>' ) &&
1210 initOpCode( OPCODE_GREATER_EQUAL, aTokenMap, ">=", ">=" ) &&
1211 initOpCode( OPCODE_INTERSECT, aTokenMap, '!', ' ' ) &&
1212 initOpCode( OPCODE_LIST, aTokenMap, '~', ',' ) &&
1213 initOpCode( OPCODE_RANGE, aTokenMap, ':', ':' ) &&
1214 // functions
1215 fillFuncTokenMaps( aTokenMap, aExtFuncTokenMap, aEntrySeq, xMapper ) &&
1216 initFuncOpCodes( aTokenMap, aExtFuncTokenMap, rFuncInfos ) &&
1217 initOpCode( OPCODE_DDE, aTokenMap, "DDE", nullptr );
1218
1219 OSL_ENSURE( bIsValid, "OpCodeProviderImpl::OpCodeProviderImpl - opcodes not initialized" );
1220
1221 // OPCODE_PLUS_SIGN and OPCODE_ADD should be equal, otherwise "+" has to be passed above
1222 OSL_ENSURE( OPCODE_PLUS_SIGN == OPCODE_ADD, "OpCodeProviderImpl::OpCodeProviderImpl - need opcode mapping for OPCODE_PLUS_SIGN" );
1223 }
1224 catch( Exception& )
1225 {
1226 OSL_FAIL( "OpCodeProviderImpl::OpCodeProviderImpl - cannot receive formula opcode mapper" );
1227 }
1228 }
1229
fillEntrySeq(OpCodeEntrySequence & orEntrySeq,const Reference<XFormulaOpCodeMapper> & rxMapper,sal_Int32 nMapGroup)1230 bool OpCodeProviderImpl::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
1231 const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
1232 {
1233 try
1234 {
1235 orEntrySeq = rxMapper->getAvailableMappings( css::sheet::FormulaLanguage::ODFF, nMapGroup );
1236 return orEntrySeq.hasElements();
1237 }
1238 catch( Exception& )
1239 {
1240 }
1241 return false;
1242 }
1243
fillTokenMap(ApiTokenMap & orTokenMap,OpCodeEntrySequence & orEntrySeq,const Reference<XFormulaOpCodeMapper> & rxMapper,sal_Int32 nMapGroup)1244 bool OpCodeProviderImpl::fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq,
1245 const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
1246 {
1247 orTokenMap.clear();
1248 if( fillEntrySeq( orEntrySeq, rxMapper, nMapGroup ) )
1249 {
1250 for( const FormulaOpCodeMapEntry& rEntry : std::as_const(orEntrySeq) )
1251 orTokenMap[ rEntry.Name ] = rEntry.Token;
1252 }
1253 return orEntrySeq.hasElements();
1254 }
1255
fillFuncTokenMaps(ApiTokenMap & orIntFuncTokenMap,ApiTokenMap & orExtFuncTokenMap,OpCodeEntrySequence & orEntrySeq,const Reference<XFormulaOpCodeMapper> & rxMapper) const1256 bool OpCodeProviderImpl::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const
1257 {
1258 orIntFuncTokenMap.clear();
1259 orExtFuncTokenMap.clear();
1260 if( fillEntrySeq( orEntrySeq, rxMapper, css::sheet::FormulaMapGroup::FUNCTIONS ) )
1261 {
1262 for( const FormulaOpCodeMapEntry& rEntry : std::as_const(orEntrySeq) )
1263 ((rEntry.Token.OpCode == OPCODE_EXTERNAL) ? orExtFuncTokenMap : orIntFuncTokenMap)[ rEntry.Name ] = rEntry.Token;
1264 }
1265 return orEntrySeq.hasElements();
1266 }
1267
initOpCode(sal_Int32 & ornOpCode,const OpCodeEntrySequence & rEntrySeq,sal_Int32 nSpecialId)1268 bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId )
1269 {
1270 if( (0 <= nSpecialId) && (nSpecialId < rEntrySeq.getLength()) )
1271 {
1272 ornOpCode = rEntrySeq[ nSpecialId ].Token.OpCode;
1273 return true;
1274 }
1275 OSL_FAIL( OString( OString::Concat("OpCodeProviderImpl::initOpCode - opcode for special offset ") +
1276 OString::number( nSpecialId ) + " not found" ).getStr() );
1277 return false;
1278 }
1279
initOpCode(sal_Int32 & ornOpCode,const ApiTokenMap & rTokenMap,const OUString & rOdfName,const OUString & rOoxName)1280 bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName )
1281 {
1282 ApiTokenMap::const_iterator aIt = rTokenMap.find( rOdfName );
1283 if( aIt != rTokenMap.end() )
1284 {
1285 ornOpCode = aIt->second.OpCode;
1286 if( !rOoxName.isEmpty() )
1287 {
1288 FormulaOpCodeMapEntry aEntry;
1289 aEntry.Name = rOoxName;
1290 aEntry.Token.OpCode = ornOpCode;
1291 maParserMap.push_back( aEntry );
1292 }
1293 return true;
1294 }
1295 OSL_FAIL( OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for \"" +
1296 OUStringToOString( rOdfName, RTL_TEXTENCODING_ASCII_US ) +
1297 "\" not found" ).getStr() );
1298 return false;
1299 }
1300
initOpCode(sal_Int32 & ornOpCode,const ApiTokenMap & rTokenMap,const char * pcOdfName,const char * pcOoxName)1301 bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const char* pcOdfName, const char* pcOoxName )
1302 {
1303 OUString aOoxName;
1304 if( pcOoxName ) aOoxName = OUString::createFromAscii( pcOoxName );
1305 return initOpCode( ornOpCode, rTokenMap, OUString::createFromAscii( pcOdfName ), aOoxName );
1306 }
1307
initOpCode(sal_Int32 & ornOpCode,const ApiTokenMap & rTokenMap,sal_Unicode cOdfName,sal_Unicode cOoxName)1308 bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName )
1309 {
1310 OUString aOoxName;
1311 if( cOoxName ) aOoxName = OUString( cOoxName );
1312 return initOpCode( ornOpCode, rTokenMap, OUString( cOdfName ), aOoxName );
1313 }
1314
initFuncOpCode(FunctionInfo & orFuncInfo,const ApiTokenMap & rFuncTokenMap)1315 bool OpCodeProviderImpl::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap )
1316 {
1317 bool bIsValid = false;
1318 if( !orFuncInfo.maOdfFuncName.isEmpty() )
1319 {
1320 ApiTokenMap::const_iterator aIt = rFuncTokenMap.find( orFuncInfo.maOdfFuncName );
1321 if( aIt != rFuncTokenMap.end() )
1322 {
1323 orFuncInfo.mnApiOpCode = aIt->second.OpCode;
1324 bIsValid =
1325 (orFuncInfo.mnApiOpCode >= 0) &&
1326 (orFuncInfo.mnApiOpCode != OPCODE_UNKNOWN) &&
1327 (orFuncInfo.mnApiOpCode != OPCODE_NONAME);
1328 OSL_ENSURE( bIsValid,
1329 OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no valid opcode for ODF function \"" ).
1330 append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
1331 append( '"' ).getStr() );
1332
1333 if( bIsValid && (orFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) )
1334 {
1335 bIsValid = (aIt->second.Data >>= orFuncInfo.maExtProgName) && !orFuncInfo.maExtProgName.isEmpty();
1336 OSL_ENSURE( bIsValid,
1337 OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no programmatical name for external function \"" ).
1338 append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
1339 append( '"' ).getStr() );
1340 }
1341
1342 // add to parser map, if OOXML function name exists
1343 if( bIsValid && !orFuncInfo.maOoxFuncName.isEmpty() )
1344 {
1345 // create the parser map entry
1346 FormulaOpCodeMapEntry aEntry;
1347 aEntry.Name = orFuncInfo.maOoxFuncName;
1348 aEntry.Token = aIt->second;
1349 maParserMap.push_back( aEntry );
1350 }
1351 }
1352 else
1353 {
1354 // ignore entries for functions unknown by Calc *and* by Excel
1355 bIsValid = orFuncInfo.maOoxFuncName.isEmpty();
1356 SAL_WARN_IF( !bIsValid, "sc",
1357 "OpCodeProviderImpl::initFuncOpCode - no opcode mapping for function ODF '" <<
1358 orFuncInfo.maOdfFuncName << "' <-> OOXML '" << orFuncInfo.maOoxFuncName << "'");
1359 }
1360 }
1361 else if( orFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
1362 {
1363 orFuncInfo.mnApiOpCode = OPCODE_EXTERNAL;
1364 bIsValid = true;
1365 }
1366 else if( !orFuncInfo.maOoxFuncName.isEmpty() )
1367 {
1368 orFuncInfo.mnApiOpCode = OPCODE_BAD;
1369 bIsValid = true;
1370 }
1371
1372 if( !bIsValid || (orFuncInfo.mnApiOpCode == OPCODE_UNKNOWN) || (orFuncInfo.mnApiOpCode < 0) )
1373 orFuncInfo.mnApiOpCode = OPCODE_NONAME;
1374 return bIsValid;
1375 }
1376
initFuncOpCodes(const ApiTokenMap & rIntFuncTokenMap,const ApiTokenMap & rExtFuncTokenMap,const FunctionInfoVector & rFuncInfos)1377 bool OpCodeProviderImpl::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos )
1378 {
1379 bool bIsValid = true;
1380 for( const FunctionInfoRef& xFuncInfo : rFuncInfos )
1381 {
1382 // set API opcode from ODF function name
1383 if (xFuncInfo->mbExternal)
1384 bIsValid &= initFuncOpCode( *xFuncInfo, rExtFuncTokenMap );
1385 if (xFuncInfo->mbInternal)
1386 bIsValid &= initFuncOpCode( *xFuncInfo, rIntFuncTokenMap );
1387 // insert the function info into the maps
1388 if( (xFuncInfo->mnApiOpCode != OPCODE_NONAME) && (xFuncInfo->mnApiOpCode != OPCODE_BAD) )
1389 {
1390 if( (xFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && !xFuncInfo->maExtProgName.isEmpty() )
1391 maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
1392 else
1393 maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
1394 }
1395 }
1396 return bIsValid;
1397 }
1398
OpCodeProvider(const Reference<XMultiServiceFactory> & rxModelFactory,bool bImportFilter)1399 OpCodeProvider::OpCodeProvider( const Reference< XMultiServiceFactory >& rxModelFactory,
1400 bool bImportFilter ) :
1401 FunctionProvider( bImportFilter ),
1402 mxOpCodeImpl( std::make_shared<OpCodeProviderImpl>( getFuncs(), rxModelFactory ) )
1403 {
1404 }
1405
~OpCodeProvider()1406 OpCodeProvider::~OpCodeProvider()
1407 {
1408 }
1409
getOpCodes() const1410 const ApiOpCodes& OpCodeProvider::getOpCodes() const
1411 {
1412 return *mxOpCodeImpl;
1413 }
1414
getFuncInfoFromApiToken(const ApiToken & rToken) const1415 const FunctionInfo* OpCodeProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
1416 {
1417 const FunctionInfo* pFuncInfo = nullptr;
1418 if( (rToken.OpCode == mxOpCodeImpl->OPCODE_EXTERNAL) && rToken.Data.has< OUString >() )
1419 pFuncInfo = mxOpCodeImpl->maExtProgFuncs.get( rToken.Data.get< OUString >() ).get();
1420 else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_MACRO) && rToken.Data.has< OUString >() )
1421 pFuncInfo = getFuncInfoFromMacroName( rToken.Data.get< OUString >() );
1422 else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_BAD) && rToken.Data.has< OUString >() )
1423 pFuncInfo = getFuncInfoFromOoxFuncName( rToken.Data.get< OUString >() );
1424 else
1425 pFuncInfo = mxOpCodeImpl->maOpCodeFuncs.get( rToken.OpCode ).get();
1426 return pFuncInfo;
1427 }
1428
getOoxParserMap() const1429 Sequence< FormulaOpCodeMapEntry > OpCodeProvider::getOoxParserMap() const
1430 {
1431 return ContainerHelper::vectorToSequence( mxOpCodeImpl->maParserMap );
1432 }
1433
1434 // API formula parser wrapper =================================================
1435
ApiParserWrapper(const Reference<XMultiServiceFactory> & rxModelFactory,const OpCodeProvider & rOpCodeProv)1436 ApiParserWrapper::ApiParserWrapper(
1437 const Reference< XMultiServiceFactory >& rxModelFactory, const OpCodeProvider& rOpCodeProv ) :
1438 OpCodeProvider( rOpCodeProv )
1439 {
1440 if( rxModelFactory.is() ) try
1441 {
1442 mxParser.set( rxModelFactory->createInstance( "com.sun.star.sheet.FormulaParser" ), UNO_QUERY_THROW );
1443 }
1444 catch( Exception& )
1445 {
1446 }
1447 OSL_ENSURE( mxParser.is(), "ApiParserWrapper::ApiParserWrapper - cannot create API formula parser object" );
1448 maParserProps.set( mxParser );
1449 maParserProps.setProperty( PROP_CompileEnglish, true );
1450 maParserProps.setProperty( PROP_FormulaConvention, css::sheet::AddressConvention::XL_OOX );
1451 maParserProps.setProperty( PROP_IgnoreLeadingSpaces, false );
1452 maParserProps.setProperty( PROP_OpCodeMap, getOoxParserMap() );
1453 }
1454
parseFormula(const OUString & rFormula,const ScAddress & rRefPos)1455 ApiTokenSequence ApiParserWrapper::parseFormula( const OUString& rFormula, const ScAddress& rRefPos )
1456 {
1457 ApiTokenSequence aTokenSeq;
1458 if( mxParser.is() ) try
1459 {
1460 aTokenSeq = mxParser->parseFormula( rFormula,
1461 CellAddress(rRefPos.Tab(), rRefPos.Col(), rRefPos.Row()) );
1462 }
1463 catch( Exception& )
1464 {
1465 }
1466 return aTokenSeq;
1467 }
1468
1469 // formula parser/printer base class for filters ==============================
1470
1471 namespace {
1472
lclConvertToCellAddress(ScAddress & orAddress,const SingleReference & rSingleRef,sal_Int32 nForbiddenFlags,sal_Int32 nFilterBySheet)1473 bool lclConvertToCellAddress( ScAddress& orAddress, const SingleReference& rSingleRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
1474 {
1475 orAddress = ScAddress( rSingleRef.Column, rSingleRef.Row, rSingleRef.Sheet );
1476 return
1477 !getFlag( rSingleRef.Flags, nForbiddenFlags ) &&
1478 ((nFilterBySheet < 0) || (nFilterBySheet == rSingleRef.Sheet));
1479 }
1480
lclConvertToCellRange(ScRange & orRange,const ComplexReference & rComplexRef,sal_Int32 nForbiddenFlags,sal_Int32 nFilterBySheet)1481 bool lclConvertToCellRange( ScRange& orRange, const ComplexReference& rComplexRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
1482 {
1483 orRange = ScRange( rComplexRef.Reference1.Column, rComplexRef.Reference1.Row, rComplexRef.Reference1.Sheet,
1484 rComplexRef.Reference2.Column, rComplexRef.Reference2.Row, rComplexRef.Reference2.Sheet );
1485 return
1486 !getFlag( rComplexRef.Reference1.Flags, nForbiddenFlags ) &&
1487 !getFlag( rComplexRef.Reference2.Flags, nForbiddenFlags ) &&
1488 (rComplexRef.Reference1.Sheet == rComplexRef.Reference2.Sheet) &&
1489 ((nFilterBySheet < 0) || (nFilterBySheet == rComplexRef.Reference1.Sheet));
1490 }
1491
1492 enum TokenToRangeListState { STATE_REF, STATE_SEP, STATE_OPEN, STATE_CLOSE, STATE_ERROR };
1493
lclProcessRef(ScRangeList & orRanges,const Any & rData,sal_Int32 nFilterBySheet)1494 TokenToRangeListState lclProcessRef( ScRangeList& orRanges, const Any& rData, sal_Int32 nFilterBySheet )
1495 {
1496 using namespace ::com::sun::star::sheet::ReferenceFlags;
1497 const sal_Int32 FORBIDDEN_FLAGS_REL = COLUMN_DELETED | ROW_DELETED | SHEET_DELETED |
1498 COLUMN_RELATIVE | ROW_RELATIVE | SHEET_RELATIVE | RELATIVE_NAME;
1499
1500 sal_Int32 nForbiddenFlags = FORBIDDEN_FLAGS_REL;
1501 SingleReference aSingleRef;
1502 if( rData >>= aSingleRef )
1503 {
1504 ScAddress aAddress;
1505 // ignore invalid addresses (with #REF! errors), but do not stop parsing
1506 if( lclConvertToCellAddress( aAddress, aSingleRef, nForbiddenFlags, nFilterBySheet ) )
1507 orRanges.push_back( ScRange(aAddress, aAddress) );
1508 return STATE_REF;
1509 }
1510 ComplexReference aComplexRef;
1511 if( rData >>= aComplexRef )
1512 {
1513 ScRange aRange;
1514 // ignore invalid ranges (with #REF! errors), but do not stop parsing
1515 if( lclConvertToCellRange( aRange, aComplexRef, nForbiddenFlags, nFilterBySheet ) )
1516 orRanges.push_back( aRange );
1517 return STATE_REF;
1518 }
1519 return STATE_ERROR;
1520 }
1521
lclProcessOpen(sal_Int32 & ornParenLevel)1522 TokenToRangeListState lclProcessOpen( sal_Int32& ornParenLevel )
1523 {
1524 ++ornParenLevel;
1525 return STATE_OPEN;
1526 }
1527
lclProcessClose(sal_Int32 & ornParenLevel)1528 TokenToRangeListState lclProcessClose( sal_Int32& ornParenLevel )
1529 {
1530 --ornParenLevel;
1531 return (ornParenLevel >= 0) ? STATE_CLOSE : STATE_ERROR;
1532 }
1533
1534 } // namespace
1535
FormulaProcessorBase(const WorkbookHelper & rHelper)1536 FormulaProcessorBase::FormulaProcessorBase( const WorkbookHelper& rHelper ) :
1537 OpCodeProvider( rHelper.getBaseFilter().getModelFactory(), rHelper.getBaseFilter().isImportFilter() ),
1538 ApiOpCodes( getOpCodes() ),
1539 WorkbookHelper( rHelper )
1540 {
1541 }
1542
generateAddress2dString(const ScAddress & rAddress,bool bAbsolute)1543 OUString FormulaProcessorBase::generateAddress2dString( const ScAddress& rAddress, bool bAbsolute )
1544 {
1545 return generateAddress2dString( BinAddress( rAddress ), bAbsolute );
1546 }
1547
generateAddress2dString(const BinAddress & rAddress,bool bAbsolute)1548 OUString FormulaProcessorBase::generateAddress2dString( const BinAddress& rAddress, bool bAbsolute )
1549 {
1550 OUStringBuffer aBuffer;
1551 // column
1552 for( sal_Int32 nTemp = rAddress.mnCol; nTemp >= 0; nTemp = (nTemp / 26) - 1 )
1553 aBuffer.insert( 0, sal_Unicode( 'A' + (nTemp % 26) ) );
1554 if( bAbsolute )
1555 aBuffer.insert( 0, '$' );
1556 // row
1557 if( bAbsolute )
1558 aBuffer.append( '$' );
1559 aBuffer.append( static_cast< sal_Int32 >( rAddress.mnRow + 1 ) );
1560 return aBuffer.makeStringAndClear();
1561 }
1562
generateApiString(const OUString & rString)1563 OUString FormulaProcessorBase::generateApiString( const OUString& rString )
1564 {
1565 OUString aRetString = rString;
1566 sal_Int32 nQuotePos = aRetString.getLength();
1567 while( (nQuotePos = aRetString.lastIndexOf( '"', nQuotePos )) >= 0 )
1568 aRetString = aRetString.replaceAt( nQuotePos, 1, "\"\"" );
1569 return "\"" + aRetString + "\"";
1570 }
1571
generateApiArray(const Matrix<Any> & rMatrix)1572 OUString FormulaProcessorBase::generateApiArray( const Matrix< Any >& rMatrix )
1573 {
1574 OSL_ENSURE( !rMatrix.empty(), "FormulaProcessorBase::generateApiArray - missing matrix values" );
1575 OUStringBuffer aBuffer;
1576 aBuffer.append( API_TOKEN_ARRAY_OPEN );
1577 for( size_t nRow = 0, nHeight = rMatrix.height(); nRow < nHeight; ++nRow )
1578 {
1579 if( nRow > 0 )
1580 aBuffer.append( API_TOKEN_ARRAY_ROWSEP );
1581 for( Matrix< Any >::const_iterator aBeg = rMatrix.row_begin( nRow ), aIt = aBeg, aEnd = rMatrix.row_end( nRow ); aIt != aEnd; ++aIt )
1582 {
1583 double fValue = 0.0;
1584 OUString aString;
1585 if( aIt != aBeg )
1586 aBuffer.append( API_TOKEN_ARRAY_COLSEP );
1587 if( *aIt >>= fValue )
1588 aBuffer.append( fValue );
1589 else if( *aIt >>= aString )
1590 aBuffer.append( generateApiString( aString ) );
1591 else
1592 aBuffer.append( "\"\"" );
1593 }
1594 }
1595 aBuffer.append( API_TOKEN_ARRAY_CLOSE );
1596 return aBuffer.makeStringAndClear();
1597 }
1598
extractReference(const ApiTokenSequence & rTokens) const1599 Any FormulaProcessorBase::extractReference( const ApiTokenSequence& rTokens ) const
1600 {
1601 ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES );
1602 if( aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) )
1603 {
1604 Any aRefAny = aTokenIt->Data;
1605 if( !(++aTokenIt).is() && (aRefAny.has< SingleReference >() || aRefAny.has< ComplexReference >()) )
1606 return aRefAny;
1607 }
1608 return Any();
1609 }
1610
extractCellRange(ScRange & orRange,const ApiTokenSequence & rTokens) const1611 bool FormulaProcessorBase::extractCellRange( ScRange& orRange,
1612 const ApiTokenSequence& rTokens ) const
1613 {
1614 ScRangeList aRanges;
1615 lclProcessRef( aRanges, extractReference( rTokens ), -1 );
1616 if( !aRanges.empty() )
1617 {
1618 orRange = aRanges.front();
1619 return true;
1620 }
1621 return false;
1622 }
1623
extractCellRangeList(ScRangeList & orRanges,const ApiTokenSequence & rTokens,sal_Int32 nFilterBySheet) const1624 void FormulaProcessorBase::extractCellRangeList( ScRangeList& orRanges,
1625 const ApiTokenSequence& rTokens, sal_Int32 nFilterBySheet ) const
1626 {
1627 orRanges.RemoveAll();
1628 TokenToRangeListState eState = STATE_OPEN;
1629 sal_Int32 nParenLevel = 0;
1630 for( ApiTokenIterator aIt( rTokens, OPCODE_SPACES ); aIt.is() && (eState != STATE_ERROR); ++aIt )
1631 {
1632 sal_Int32 nOpCode = aIt->OpCode;
1633 switch( eState )
1634 {
1635 // #i107275# accept OPCODE_SEP and OPCODE_LIST as separator token
1636 case STATE_REF:
1637 if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
1638 else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
1639 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
1640 else eState = STATE_ERROR;
1641 break;
1642 case STATE_SEP:
1643 if( nOpCode == OPCODE_PUSH ) eState = lclProcessRef( orRanges, aIt->Data, nFilterBySheet );
1644 else if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
1645 else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
1646 else if( nOpCode == OPCODE_OPEN ) eState = lclProcessOpen( nParenLevel );
1647 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
1648 else eState = STATE_ERROR;
1649 break;
1650 case STATE_OPEN:
1651 if( nOpCode == OPCODE_PUSH ) eState = lclProcessRef( orRanges, aIt->Data, nFilterBySheet );
1652 else if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
1653 else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
1654 else if( nOpCode == OPCODE_OPEN ) eState = lclProcessOpen( nParenLevel );
1655 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
1656 else eState = STATE_ERROR;
1657 break;
1658 case STATE_CLOSE:
1659 if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
1660 else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
1661 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
1662 else eState = STATE_ERROR;
1663 break;
1664 default:;
1665 }
1666 }
1667
1668 if( eState == STATE_ERROR )
1669 orRanges.RemoveAll();
1670 else
1671 getAddressConverter().validateCellRangeList( orRanges, false );
1672 }
1673
extractString(OUString & orString,const ApiTokenSequence & rTokens) const1674 bool FormulaProcessorBase::extractString( OUString& orString, const ApiTokenSequence& rTokens ) const
1675 {
1676 ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES );
1677 return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) && (aTokenIt->Data >>= orString) && !(++aTokenIt).is();
1678 }
1679
extractSpecialTokenInfo(ApiSpecialTokenInfo & orTokenInfo,const ApiTokenSequence & rTokens) const1680 bool FormulaProcessorBase::extractSpecialTokenInfo( ApiSpecialTokenInfo& orTokenInfo, const ApiTokenSequence& rTokens ) const
1681 {
1682 ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES );
1683 return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_BAD) && (aTokenIt->Data >>= orTokenInfo);
1684 }
1685
convertStringToStringList(ApiTokenSequence & orTokens,sal_Unicode cStringSep,bool bTrimLeadingSpaces) const1686 void FormulaProcessorBase::convertStringToStringList(
1687 ApiTokenSequence& orTokens, sal_Unicode cStringSep, bool bTrimLeadingSpaces ) const
1688 {
1689 OUString aString;
1690 if( !extractString( aString, orTokens ) || aString.isEmpty() )
1691 return;
1692
1693 ::std::vector< ApiToken > aNewTokens;
1694 for( sal_Int32 nPos{ 0 }; nPos>=0; )
1695 {
1696 OUString aEntry = aString.getToken( 0, cStringSep, nPos );
1697 if( bTrimLeadingSpaces )
1698 {
1699 sal_Int32 nStart = 0;
1700 while( (nStart < aEntry.getLength()) && (aEntry[ nStart ] == ' ') ) ++nStart;
1701 aEntry = aEntry.copy( nStart );
1702 }
1703 if( !aNewTokens.empty() )
1704 aNewTokens.emplace_back( OPCODE_SEP, Any() );
1705 aNewTokens.emplace_back( OPCODE_PUSH, Any( aEntry ) );
1706 }
1707 orTokens = ContainerHelper::vectorToSequence( aNewTokens );
1708 }
1709
1710 } // namespace oox
1711
1712 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1713