/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
#include <formulabase.hxx>
#include <rangelst.hxx>
#include <addressconverter.hxx>
 
#include <map>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/sheet/AddressConvention.hpp>
#include <com/sun/star/sheet/ReferenceFlags.hpp>
#include <com/sun/star/sheet/SingleReference.hpp>
#include <com/sun/star/sheet/ComplexReference.hpp>
#include <com/sun/star/sheet/FormulaLanguage.hpp>
#include <com/sun/star/sheet/FormulaMapGroup.hpp>
#include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
#include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
#include <com/sun/star/sheet/XFormulaParser.hpp>
 
#include <comphelper/sequence.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <oox/core/filterbase.hxx>
#include <oox/helper/containerhelper.hxx>
#include <oox/helper/binaryinputstream.hxx>
#include <oox/token/properties.hxx>
#include <o3tl/typed_flags_set.hxx>
#include <o3tl/string_view.hxx>
 
namespace {
 
enum class FuncFlags : sal_uInt16 {
    NONE              = 0x0000,
    VOLATILE          = 0x0001,   /// Result is volatile (e.g. NOW() function).
    IMPORTONLY        = 0x0002,   /// Only used in import filter.
    EXPORTONLY        = 0x0004,   /// Only used in export filter.
    MACROCALL         = 0x0008,   /// Function is stored as macro call in BIFF Excel (_xlfn. prefix). OOXML name MUST exist.
    MACROCALLODF      = 0x0010,   /// ODF-only function stored as macro call in BIFF Excel (_xlfnodf. prefix). ODF name MUST exist.
    EXTERNAL          = 0x0020,   /// Function is external in Calc.
    MACROFUNC         = 0x0040,   /// Function is a macro-sheet function.
    MACROCMD          = 0x0080,   /// Function is a macro-sheet command.
    ALWAYSVAR         = 0x0100,   /// Function is always represented by a tFuncVar token.
    PARAMPAIRS        = 0x0200,   /// Optional parameters are expected to appear in pairs.
    MACROCALL_FN      = 0x0400,   /** Function is stored as macro call in Excel (_xlfn. prefix)
                                      for OOXML. OOXML name MUST exist. Do not use without FuncFlags::MACROCALL. */
    MACROCALL_NEW     = MACROCALL | MACROCALL_FN, /** New Excel functions not
                                                      defined in OOXML, _xlfn. prefix in all formats. OOXML name
                                                      must exist. */
    BIFFEXPORTONLY    = 0x1000,   /// Only used in BIFF binary export filter.
    INTERNAL          = 0x2000,   /// Function is internal in Calc.
    EUROTOOL          = 0x4000,   /// function of euro tool lib, FUNCLIB_EUROTOOL
};
 
}
 
namespace o3tl {
    template<> struct typed_flags<FuncFlags> : is_typed_flags<FuncFlags, 0x77ff> {};
}
 
namespace oox::xls {
 
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::table;
using namespace ::com::sun::star::uno;
 
// reference helpers ==========================================================
 
BinSingleRef2d::BinSingleRef2d() :
    mnCol( 0 ),
    mnRow( 0 ),
    mbColRel( false ),
    mbRowRel( false )
{
}
 
void BinSingleRef2d::setBiff12Data( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset )
{
    mnCol = nCol & BIFF12_TOK_REF_COLMASK;
    mnRow = nRow & BIFF12_TOK_REF_ROWMASK;
    mbColRel = getFlag( nCol, BIFF12_TOK_REF_COLREL );
    mbRowRel = getFlag( nCol, BIFF12_TOK_REF_ROWREL );
    if( bRelativeAsOffset && mbColRel && (mnCol > (BIFF12_TOK_REF_COLMASK >> 1)) )
        mnCol -= (BIFF12_TOK_REF_COLMASK + 1);
    if( bRelativeAsOffset && mbRowRel && (mnRow > (BIFF12_TOK_REF_ROWMASK >> 1)) )
        mnRow -= (BIFF12_TOK_REF_ROWMASK + 1);
}
 
void BinSingleRef2d::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
{
    sal_Int32 nRow;
    sal_uInt16 nCol;
    nRow = rStrm.readInt32();
    nCol = rStrm.readuInt16();
    setBiff12Data( nCol, nRow, bRelativeAsOffset );
}
 
void BinComplexRef2d::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
{
    sal_Int32 nRow1, nRow2;
    sal_uInt16 nCol1, nCol2;
    nRow1 = rStrm.readInt32();
    nRow2 = rStrm.readInt32();
    nCol1 = rStrm.readuInt16();
    nCol2 = rStrm.readuInt16();
    maRef1.setBiff12Data( nCol1, nRow1, bRelativeAsOffset );
    maRef2.setBiff12Data( nCol2, nRow2, bRelativeAsOffset );
}
 
// token vector, sequence =====================================================
 
ApiTokenVector::ApiTokenVector()
{
}
 
Any& ApiTokenVector::append( sal_Int32 nOpCode )
{
    mvTokens.emplace_back();
    mvTokens.back().OpCode = nOpCode;
    return mvTokens.back().Data;
}
 
ApiTokenSequence ApiTokenVector::toSequence() const
{
    return comphelper::containerToSequence( mvTokens );
}
 
// token sequence iterator ====================================================
 
ApiTokenIterator::ApiTokenIterator( const ApiTokenSequence& rTokens, sal_Int32 nSpacesOpCode ) :
    mpToken( rTokens.getConstArray() ),
    mpTokenEnd( rTokens.getConstArray() + rTokens.getLength() ),
    mnSpacesOpCode( nSpacesOpCode )
{
    skipSpaces();
}
 
ApiTokenIterator& ApiTokenIterator::operator++()
{
    if( is() )
    {
        ++mpToken;
        skipSpaces();
    }
    return *this;
}
 
void ApiTokenIterator::skipSpaces()
{
    while( is() && (mpToken->OpCode == mnSpacesOpCode) )
        ++mpToken;
}
 
// function data ==============================================================
 
namespace {
 
const size_t FUNCINFO_PARAMINFOCOUNT        = 5;        /// Number of parameter type entries.
 
typedef std::shared_ptr< FunctionInfo > FunctionInfoRef;
 
struct FunctionData
{
    const char*          mpcOdfFuncName;     /// ODF function name.
    const char*          mpcOoxFuncName;     /// OOXML function name.
    sal_uInt16           mnBiff12FuncId;     /// BIFF12 function identifier.
    sal_uInt16           mnBiffFuncId;       /// BIFF2-BIFF8 function identifier.
    sal_uInt8            mnMinParamCount;    /// Minimum number of parameters.
    sal_uInt8            mnMaxParamCount;    /// Maximum number of parameters.
    sal_uInt8            mnRetClass;         /// BIFF token class of the return value.
    FunctionParamInfo    mpParamInfos[ FUNCINFO_PARAMINFOCOUNT ]; /// Information about all parameters.
    FuncFlags            mnFlags;            /// Additional flags.
 
    bool         isSupported(bool bImportFilter) const;
};
 
bool FunctionData::isSupported(bool bImportFilter) const
{
    /*  For import filters: the FuncFlags::EXPORTONLY, FuncFlags::BIFFEXPORTONLY
                            must not be set.
        For export filters: the FuncFlags::IMPORTONLY, FuncFlags::BIFFEXPORTONLY
                            must not be set. */
    if (bImportFilter)
        return !(mnFlags & ( FuncFlags::EXPORTONLY | FuncFlags::BIFFEXPORTONLY));
    else
        return !(mnFlags & ( FuncFlags::IMPORTONLY | FuncFlags::BIFFEXPORTONLY));
}
 
const sal_uInt16 NOID = SAL_MAX_UINT16;     /// No BIFF function identifier available.
const sal_uInt8 MX    = SAL_MAX_UINT8;      /// Maximum parameter count.
 
// abbreviations for function return token class
const sal_uInt8 R = BIFF_TOKCLASS_REF;
const sal_uInt8 V = BIFF_TOKCLASS_VAL;
const sal_uInt8 A = BIFF_TOKCLASS_ARR;
 
// abbreviations for parameter infos
#define RO   { FuncParamValidity::Regular }
#define RA   { FuncParamValidity::Regular }
#define RR   { FuncParamValidity::Regular }
#define RX   { FuncParamValidity::Regular }
#define VO   { FuncParamValidity::Regular  }
#define VV   { FuncParamValidity::Regular  }
#define VA   { FuncParamValidity::Regular  }
#define VR   { FuncParamValidity::Regular  }
#define VX   { FuncParamValidity::Regular  }
#define RO_E { FuncParamValidity::ExcelOnly }
#define VR_E { FuncParamValidity::ExcelOnly  }
#define C    { FuncParamValidity::CalcOnly }
 
// Note: parameter types of all macro sheet functions (FuncFlags::MACROFUNC/FuncFlags::MACROCMD) untested!
 
/** Functions new in BIFF2. */
const FunctionData saFuncTableBiff2[] =
{
    { "COUNT",                  "COUNT",                0,      0,      0,  MX, V, { RX }, FuncFlags::NONE },
    { "IF",                     "IF",                   1,      1,      2,  3,  R, { VO, RO }, FuncFlags::NONE },
    { "ISNA",                   "ISNA",                 2,      2,      1,  1,  V, { VR }, FuncFlags::NONE },
    { "ISERROR",                "ISERROR",              3,      3,      1,  1,  V, { VR }, FuncFlags::NONE },
    { "SUM",                    "SUM",                  4,      4,      0,  MX, V, { RX }, FuncFlags::NONE },
    { "AVERAGE",                "AVERAGE",              5,      5,      1,  MX, V, { RX }, FuncFlags::NONE },
    { "MIN",                    "MIN",                  6,      6,      1,  MX, V, { RX }, FuncFlags::NONE },
    { "MAX",                    "MAX",                  7,      7,      1,  MX, V, { RX }, FuncFlags::NONE },
    { "ROW",                    "ROW",                  8,      8,      0,  1,  V, { RO }, FuncFlags::NONE },
    { "COLUMN",                 "COLUMN",               9,      9,      0,  1,  V, { RO }, FuncFlags::NONE },
    { "NA",                     "NA",                   10,     10,     0,  0,  V, {}, FuncFlags::NONE },
    { "NPV",                    "NPV",                  11,     11,     2,  MX, V, { VR, RX }, FuncFlags::NONE },
    { "STDEV",                  "STDEV",                12,     12,     1,  MX, V, { RX }, FuncFlags::NONE },
    { "DOLLAR",                 "DOLLAR",               13,     13,     1,  2,  V, { VR }, FuncFlags::NONE },
    { "FIXED",                  "FIXED",                14,     14,     1,  2,  V, { VR, VR, C }, FuncFlags::NONE },
    { "SIN",                    "SIN",                  15,     15,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "CSC",                    "SIN",                  15,     15,     1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "COS",                    "COS",                  16,     16,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "SEC",                    "COS",                  16,     16,     1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "TAN",                    "TAN",                  17,     17,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "COT",                    "TAN",                  17,     17,     1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "ATAN",                   "ATAN",                 18,     18,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "ACOT",                   "ATAN",                 18,     18,     1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "PI",                     "PI",                   19,     19,     0,  0,  V, {}, FuncFlags::NONE },
    { "SQRT",                   "SQRT",                 20,     20,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "EXP",                    "EXP",                  21,     21,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "LN",                     "LN",                   22,     22,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "LOG10",                  "LOG10",                23,     23,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "ABS",                    "ABS",                  24,     24,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "INT",                    "INT",                  25,     25,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "SIGN",                   "SIGN",                 26,     26,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "ROUND",                  "ROUND",                27,     27,     2,  2,  V, { VR }, FuncFlags::NONE },
    { "LOOKUP",                 "LOOKUP",               28,     28,     2,  3,  V, { VR, RA }, FuncFlags::NONE },
    { "INDEX",                  "INDEX",                29,     29,     2,  4,  R, { RA, VV }, FuncFlags::NONE },
    { "REPT",                   "REPT",                 30,     30,     2,  2,  V, { VR }, FuncFlags::NONE },
    { "MID",                    "MID",                  31,     31,     3,  3,  V, { VR }, FuncFlags::NONE },
    { "LEN",                    "LEN",                  32,     32,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "VALUE",                  "VALUE",                33,     33,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "TRUE",                   "TRUE",                 34,     34,     0,  0,  V, {}, FuncFlags::NONE },
    { "FALSE",                  "FALSE",                35,     35,     0,  0,  V, {}, FuncFlags::NONE },
    { "AND",                    "AND",                  36,     36,     1,  MX, V, { RX }, FuncFlags::NONE },
    { "OR",                     "OR",                   37,     37,     1,  MX, V, { RX }, FuncFlags::NONE },
    { "NOT",                    "NOT",                  38,     38,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "MOD",                    "MOD",                  39,     39,     2,  2,  V, { VR }, FuncFlags::NONE },
    { "DCOUNT",                 "DCOUNT",               40,     40,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "DSUM",                   "DSUM",                 41,     41,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "DAVERAGE",               "DAVERAGE",             42,     42,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "DMIN",                   "DMIN",                 43,     43,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "DMAX",                   "DMAX",                 44,     44,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "DSTDEV",                 "DSTDEV",               45,     45,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "VAR",                    "VAR",                  46,     46,     1,  MX, V, { RX }, FuncFlags::NONE },
    { "DVAR",                   "DVAR",                 47,     47,     3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "TEXT",                   "TEXT",                 48,     48,     2,  2,  V, { VR }, FuncFlags::NONE },
    { "LINEST",                 "LINEST",               49,     49,     1,  2,  A, { RA, RA, C, C }, FuncFlags::NONE },
    { "TREND",                  "TREND",                50,     50,     1,  3,  A, { RA, RA, RA, C }, FuncFlags::NONE },
    { "LOGEST",                 "LOGEST",               51,     51,     1,  2,  A, { RA, RA, C, C }, FuncFlags::NONE },
    { "GROWTH",                 "GROWTH",               52,     52,     1,  3,  A, { RA, RA, RA, C }, FuncFlags::NONE },
    { "PV",                     "PV",                   56,     56,     3,  5,  V, { VR }, FuncFlags::NONE },
    { "FV",                     "FV",                   57,     57,     3,  5,  V, { VR }, FuncFlags::NONE },
    { "NPER",                   "NPER",                 58,     58,     3,  5,  V, { VR }, FuncFlags::NONE },
    { "PMT",                    "PMT",                  59,     59,     3,  5,  V, { VR }, FuncFlags::NONE },
    { "RATE",                   "RATE",                 60,     60,     3,  6,  V, { VR }, FuncFlags::NONE },
    { "MIRR",                   "MIRR",                 61,     61,     3,  3,  V, { RA, VR }, FuncFlags::NONE },
    { "IRR",                    "IRR",                  62,     62,     1,  2,  V, { RA, VR }, FuncFlags::NONE },
    { "RAND",                   "RAND",                 63,     63,     0,  0,  V, {}, FuncFlags::VOLATILE },
    { "MATCH",                  "MATCH",                64,     64,     2,  3,  V, { VR, RX, RR }, FuncFlags::NONE },
    { "DATE",                   "DATE",                 65,     65,     3,  3,  V, { VR }, FuncFlags::NONE },
    { "TIME",                   "TIME",                 66,     66,     3,  3,  V, { VR }, FuncFlags::NONE },
    { "DAY",                    "DAY",                  67,     67,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "MONTH",                  "MONTH",                68,     68,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "YEAR",                   "YEAR",                 69,     69,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "WEEKDAY",                "WEEKDAY",              70,     70,     1,  1,  V, { VR, C }, FuncFlags::NONE },
    { "HOUR",                   "HOUR",                 71,     71,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "MINUTE",                 "MINUTE",               72,     72,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "SECOND",                 "SECOND",               73,     73,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "NOW",                    "NOW",                  74,     74,     0,  0,  V, {}, FuncFlags::VOLATILE },
    { "AREAS",                  "AREAS",                75,     75,     1,  1,  V, { RO }, FuncFlags::NONE },
    { "ROWS",                   "ROWS",                 76,     76,     1,  1,  V, { RO }, FuncFlags::NONE },
    { "COLUMNS",                "COLUMNS",              77,     77,     1,  1,  V, { RO }, FuncFlags::NONE },
    { "OFFSET",                 "OFFSET",               78,     78,     3,  5,  R, { RO, VR }, FuncFlags::VOLATILE },
    { "SEARCH",                 "SEARCH",               82,     82,     2,  3,  V, { VR }, FuncFlags::NONE },
    { "TRANSPOSE",              "TRANSPOSE",            83,     83,     1,  1,  A, { VO }, FuncFlags::NONE },
    { "TYPE",                   "TYPE",                 86,     86,     1,  1,  V, { VX }, FuncFlags::NONE },
    { "ATAN2",                  "ATAN2",                97,     97,     2,  2,  V, { VR }, FuncFlags::NONE },
    { "ASIN",                   "ASIN",                 98,     98,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "ACOS",                   "ACOS",                 99,     99,     1,  1,  V, { VR }, FuncFlags::NONE },
    { "CHOOSE",                 "CHOOSE",               100,    100,    2,  MX, R, { VO, RO }, FuncFlags::NONE },
    { "HLOOKUP",                "HLOOKUP",              101,    101,    3,  3,  V, { VV, RO, RO, C }, FuncFlags::NONE },
    { "VLOOKUP",                "VLOOKUP",              102,    102,    3,  3,  V, { VV, RO, RO, C }, FuncFlags::NONE },
    { "ISREF",                  "ISREF",                105,    105,    1,  1,  V, { RX }, FuncFlags::NONE },
    { "LOG",                    "LOG",                  109,    109,    1,  2,  V, { VR }, FuncFlags::NONE },
    { "CHAR",                   "CHAR",                 111,    111,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "LOWER",                  "LOWER",                112,    112,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "UPPER",                  "UPPER",                113,    113,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "PROPER",                 "PROPER",               114,    114,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "LEFT",                   "LEFT",                 115,    115,    1,  2,  V, { VR }, FuncFlags::NONE },
    { "RIGHT",                  "RIGHT",                116,    116,    1,  2,  V, { VR }, FuncFlags::NONE },
    { "EXACT",                  "EXACT",                117,    117,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "TRIM",                   "TRIM",                 118,    118,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "REPLACE",                "REPLACE",              119,    119,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "SUBSTITUTE",             "SUBSTITUTE",           120,    120,    3,  4,  V, { VR }, FuncFlags::NONE },
    { "CODE",                   "CODE",                 121,    121,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "FIND",                   "FIND",                 124,    124,    2,  3,  V, { VR }, FuncFlags::NONE },
    { "CELL",                   "CELL",                 125,    125,    1,  2,  V, { VV, RO }, FuncFlags::VOLATILE },
    { "ISERR",                  "ISERR",                126,    126,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ISTEXT",                 "ISTEXT",               127,    127,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ISNUMBER",               "ISNUMBER",             128,    128,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ISBLANK",                "ISBLANK",              129,    129,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "T",                      "T",                    130,    130,    1,  1,  V, { RO }, FuncFlags::NONE },
    { "N",                      "N",                    131,    131,    1,  1,  V, { RO }, FuncFlags::NONE },
    { "DATEVALUE",              "DATEVALUE",            140,    140,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "TIMEVALUE",              "TIMEVALUE",            141,    141,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "SLN",                    "SLN",                  142,    142,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "SYD",                    "SYD",                  143,    143,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "DDB",                    "DDB",                  144,    144,    4,  5,  V, { VR }, FuncFlags::NONE },
    { "INDIRECT",               "INDIRECT",             148,    148,    1,  2,  R, { VR }, FuncFlags::VOLATILE },
    { "CLEAN",                  "CLEAN",                162,    162,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "MDETERM",                "MDETERM",              163,    163,    1,  1,  V, { VA }, FuncFlags::NONE },
    { "MINVERSE",               "MINVERSE",             164,    164,    1,  1,  A, { VA }, FuncFlags::NONE },
    { "MMULT",                  "MMULT",                165,    165,    2,  2,  A, { VA }, FuncFlags::NONE },
    { "IPMT",                   "IPMT",                 167,    167,    4,  6,  V, { VR }, FuncFlags::NONE },
    { "PPMT",                   "PPMT",                 168,    168,    4,  6,  V, { VR }, FuncFlags::NONE },
    { "COUNTA",                 "COUNTA",               169,    169,    0,  MX, V, { RX }, FuncFlags::NONE },
    { "PRODUCT",                "PRODUCT",              183,    183,    0,  MX, V, { RX }, FuncFlags::NONE },
    { "FACT",                   "FACT",                 184,    184,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "DPRODUCT",               "DPRODUCT",             189,    189,    3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "ISNONTEXT",              "ISNONTEXT",            190,    190,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "STDEVP",                 "STDEVP",               193,    193,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "VARP",                   "VARP",                 194,    194,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "DSTDEVP",                "DSTDEVP",              195,    195,    3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "DVARP",                  "DVARP",                196,    196,    3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "TRUNC",                  "TRUNC",                197,    197,    1,  1,  V, { VR, C }, FuncFlags::NONE },
    { "ISLOGICAL",              "ISLOGICAL",            198,    198,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "DCOUNTA",                "DCOUNTA",              199,    199,    3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { nullptr,                        "EXTERN.CALL",          255,    255,    1,  MX, R, { RO_E, RO }, FuncFlags::IMPORTONLY },
 
    // *** macro sheet commands ***
 
    { nullptr,                        "A1.R1C1",              30,     30,     0,  1,  V, { VR }, FuncFlags::MACROCMD },
    { nullptr,                        "RETURN",               55,     55,     0,  1,  R, { RO }, FuncFlags::MACROFUNC },
    { nullptr,                        "ABSREF",               79,     79,     2,  2,  R, { VR, RO }, FuncFlags::MACROFUNC },
    { nullptr,                        "ADD.ARROW",            81,     81,     0,  0,  V, {}, FuncFlags::MACROCMD },
    { nullptr,                        "ACTIVE.CELL",          94,     94,     0,  0,  R, {}, FuncFlags::MACROFUNC },
    { nullptr,                        "ACTIVATE",             103,    103,    0,  2,  V, { VR }, FuncFlags::MACROCMD },
    { nullptr,                        "ACTIVATE.NEXT",        104,    104,    0,  0,  V, {}, FuncFlags::MACROCMD },
    { nullptr,                        "ACTIVATE.PREV",        105,    105,    0,  0,  V, {}, FuncFlags::MACROCMD },
    { nullptr,                        "ADD.BAR",              151,    151,    0,  0,  V, {}, FuncFlags::MACROFUNC | FuncFlags::ALWAYSVAR },
    { nullptr,                        "ADD.MENU",             152,    152,    2,  2,  V, { VR, RO }, FuncFlags::MACROFUNC | FuncFlags::ALWAYSVAR },
    { nullptr,                        "ADD.COMMAND",          153,    153,    3,  3,  V, { VR, RO }, FuncFlags::MACROFUNC | FuncFlags::ALWAYSVAR }
};
 
/** Functions new in BIFF3. */
const FunctionData saFuncTableBiff3[] =
{
    { "LINEST",                 "LINEST",               49,     49,     1,  4,  A, { RA, RA, VV }, FuncFlags::NONE },             // BIFF2: 1-2, BIFF3: 1-4
    { "TREND",                  "TREND",                50,     50,     1,  4,  A, { RA, RA, RA, VV }, FuncFlags::NONE },             // BIFF2: 1-3, BIFF3: 1-4
    { "LOGEST",                 "LOGEST",               51,     51,     1,  4,  A, { RA, RA, VV }, FuncFlags::NONE },             // BIFF2: 1-2, BIFF3: 1-4
    { "GROWTH",                 "GROWTH",               52,     52,     1,  4,  A, { RA, RA, RA, VV }, FuncFlags::NONE },             // BIFF2: 1-3, BIFF3: 1-4
    { "TRUNC",                  "TRUNC",                197,    197,    1,  2,  V, { VR }, FuncFlags::NONE },                      // BIFF2: 1,   BIFF3: 1-2
    { "DOLLAR",                 "USDOLLAR",             204,    204,    1,  2,  V, { VR }, FuncFlags::IMPORTONLY },
    { "FINDB",                  "FINDB",                205,    205,    2,  3,  V, { VR }, FuncFlags::NONE },
    { "SEARCHB",                "SEARCHB",              206,    206,    2,  3,  V, { VR }, FuncFlags::NONE },
    { "REPLACEB",               "REPLACEB",             207,    207,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "LEFTB",                  "LEFTB",                208,    208,    1,  2,  V, { VR }, FuncFlags::NONE },
    { "RIGHTB",                 "RIGHTB",               209,    209,    1,  2,  V, { VR }, FuncFlags::NONE },
    { "MIDB",                   "MIDB",                 210,    210,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "LENB",                   "LENB",                 211,    211,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ROUNDUP",                "ROUNDUP",              212,    212,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "ROUNDDOWN",              "ROUNDDOWN",            213,    213,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "ASC",                    "ASC",                  214,    214,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "JIS",                    "DBCS",                 215,    215,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ADDRESS",                "ADDRESS",              219,    219,    2,  5,  V, { VR }, FuncFlags::NONE },
    { "DAYS360",                "DAYS360",              220,    220,    2,  2,  V, { VR, VR, C }, FuncFlags::NONE },
    { "TODAY",                  "TODAY",                221,    221,    0,  0,  V, {}, FuncFlags::VOLATILE },
    { "VDB",                    "VDB",                  222,    222,    5,  7,  V, { VR }, FuncFlags::NONE },
    { "MEDIAN",                 "MEDIAN",               227,    227,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "SUMPRODUCT",             "SUMPRODUCT",           228,    228,    1,  MX, V, { VA }, FuncFlags::NONE },
    { "SINH",                   "SINH",                 229,    229,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "CSCH",                   "SINH",                 229,    229,    1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "COSH",                   "COSH",                 230,    230,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "SECH",                   "COSH",                 230,    230,    1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "TANH",                   "TANH",                 231,    231,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "COTH",                   "TANH",                 231,    231,    1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "ASINH",                  "ASINH",                232,    232,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ACOSH",                  "ACOSH",                233,    233,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ATANH",                  "ATANH",                234,    234,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "ACOTH",                  "ATANH",                234,    234,    1,  1,  V, { VR }, FuncFlags::BIFFEXPORTONLY },
    { "DGET",                   "DGET",                 235,    235,    3,  3,  V, { RO, RR }, FuncFlags::NONE },
    { "INFO",                   "INFO",                 244,    244,    1,  1,  V, { VR }, FuncFlags::VOLATILE },
 
    // *** macro sheet commands ***
 
    { nullptr,                        "ADD.BAR",              151,    151,    0,  1,  V, { VR }, FuncFlags::MACROFUNC },    // BIFF2: 0,   BIFF3: 0-1
    { nullptr,                        "ADD.MENU",             152,    152,    2,  3,  V, { VR, RO }, FuncFlags::MACROFUNC },  // BIFF2: 2,   BIFF3: 2-3
    { nullptr,                        "ADD.COMMAND",          153,    153,    3,  4,  V, { VR, RO }, FuncFlags::MACROFUNC }   // BIFF2: 3,   BIFF3: 3-4
};
 
/** Functions new in BIFF4. */
const FunctionData saFuncTableBiff4[] =
{
    { "FIXED",                  "FIXED",                14,     14,     1,  3,  V, { VR }, FuncFlags::NONE },       // BIFF2-3: 1-2, BIFF4: 1-3
    { "RANK",                   "RANK",                 216,    216,    2,  3,  V, { VR, RO, VR }, FuncFlags::NONE },
    { "DB",                     "DB",                   247,    247,    4,  5,  V, { VR }, FuncFlags::NONE },
    { "FREQUENCY",              "FREQUENCY",            252,    252,    2,  2,  A, { RA }, FuncFlags::NONE },
    { "ERROR.TYPE",             "ERROR.TYPE",           261,    261,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "AVEDEV",                 "AVEDEV",               269,    269,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "BETADIST",               "BETADIST",             270,    270,    3,  5,  V, { VR }, FuncFlags::NONE },
    { "GAMMALN",                "GAMMALN",              271,    271,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "BETAINV",                "BETAINV",              272,    272,    3,  5,  V, { VR }, FuncFlags::NONE },
    { "BINOMDIST",              "BINOMDIST",            273,    273,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.CHIDIST",         "CHIDIST",              274,    274,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.CHIINV",          "CHIINV",               275,    275,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "COMBIN",                 "COMBIN",               276,    276,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "CONFIDENCE",             "CONFIDENCE",           277,    277,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "CRITBINOM",              "CRITBINOM",            278,    278,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "EVEN",                   "EVEN",                 279,    279,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "EXPONDIST",              "EXPONDIST",            280,    280,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.FDIST",           "FDIST",                281,    281,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.FINV",            "FINV",                 282,    282,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "FISHER",                 "FISHER",               283,    283,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "FISHERINV",              "FISHERINV",            284,    284,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "COM.MICROSOFT.FLOOR",    "FLOOR",                285,    285,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "GAMMADIST",              "GAMMADIST",            286,    286,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "GAMMAINV",               "GAMMAINV",             287,    287,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "COM.MICROSOFT.CEILING",  "CEILING",              288,    288,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "HYPGEOMDIST",            "HYPGEOMDIST",          289,    289,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "LOGNORMDIST",            "LOGNORMDIST",          290,    290,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "LOGINV",                 "LOGINV",               291,    291,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "NEGBINOMDIST",           "NEGBINOMDIST",         292,    292,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "NORMDIST",               "NORMDIST",             293,    293,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.NORMSDIST",       "NORMSDIST",            294,    294,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "NORMINV",                "NORMINV",              295,    295,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.NORMSINV",        "NORMSINV",             296,    296,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "STANDARDIZE",            "STANDARDIZE",          297,    297,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "ODD",                    "ODD",                  298,    298,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "PERMUT",                 "PERMUT",               299,    299,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "POISSON",                "POISSON",              300,    300,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "LEGACY.TDIST",           "TDIST",                301,    301,    3,  3,  V, { VR }, FuncFlags::NONE },
    { "WEIBULL",                "WEIBULL",              302,    302,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "SUMXMY2",                "SUMXMY2",              303,    303,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "SUMX2MY2",               "SUMX2MY2",             304,    304,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "SUMX2PY2",               "SUMX2PY2",             305,    305,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "LEGACY.CHITEST",         "CHITEST",              306,    306,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "CORREL",                 "CORREL",               307,    307,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "COVAR",                  "COVAR",                308,    308,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "FORECAST",               "FORECAST",             309,    309,    3,  3,  V, { VR, VA }, FuncFlags::NONE },
    { "FTEST",                  "FTEST",                310,    310,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "INTERCEPT",              "INTERCEPT",            311,    311,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "PEARSON",                "PEARSON",              312,    312,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "RSQ",                    "RSQ",                  313,    313,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "STEYX",                  "STEYX",                314,    314,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "SLOPE",                  "SLOPE",                315,    315,    2,  2,  V, { VA }, FuncFlags::NONE },
    { "TTEST",                  "TTEST",                316,    316,    4,  4,  V, { VA, VA, VR }, FuncFlags::NONE },
    { "PROB",                   "PROB",                 317,    317,    3,  4,  V, { VA, VA, VR }, FuncFlags::NONE },
    { "DEVSQ",                  "DEVSQ",                318,    318,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "GEOMEAN",                "GEOMEAN",              319,    319,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "HARMEAN",                "HARMEAN",              320,    320,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "SUMSQ",                  "SUMSQ",                321,    321,    0,  MX, V, { RX }, FuncFlags::NONE },
    { "KURT",                   "KURT",                 322,    322,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "SKEW",                   "SKEW",                 323,    323,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "ZTEST",                  "ZTEST",                324,    324,    2,  3,  V, { RX, VR }, FuncFlags::NONE },
    { "LARGE",                  "LARGE",                325,    325,    2,  2,  V, { RX, VR }, FuncFlags::NONE },
    { "SMALL",                  "SMALL",                326,    326,    2,  2,  V, { RX, VR }, FuncFlags::NONE },
    { "QUARTILE",               "QUARTILE",             327,    327,    2,  2,  V, { RX, VR }, FuncFlags::NONE },
    { "PERCENTILE",             "PERCENTILE",           328,    328,    2,  2,  V, { RX, VR }, FuncFlags::NONE },
    { "PERCENTRANK",            "PERCENTRANK",          329,    329,    2,  3,  V, { RX, VR, VR_E }, FuncFlags::NONE },
    { "MODE",                   "MODE",                 330,    330,    1,  MX, V, { VA }, FuncFlags::NONE },
    { "TRIMMEAN",               "TRIMMEAN",             331,    331,    2,  2,  V, { RX, VR }, FuncFlags::NONE },
    { "TINV",                   "TINV",                 332,    332,    2,  2,  V, { VR }, FuncFlags::NONE },
 
    // *** Analysis add-in ***
 
    { "HEX2BIN",                "HEX2BIN",              384,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "HEX2DEC",                "HEX2DEC",              385,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "HEX2OCT",                "HEX2OCT",              386,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "DEC2BIN",                "DEC2BIN",              387,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "DEC2HEX",                "DEC2HEX",              388,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "DEC2OCT",                "DEC2OCT",              389,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "OCT2BIN",                "OCT2BIN",              390,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "OCT2HEX",                "OCT2HEX",              391,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "OCT2DEC",                "OCT2DEC",              392,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "BIN2DEC",                "BIN2DEC",              393,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "BIN2OCT",                "BIN2OCT",              394,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "BIN2HEX",                "BIN2HEX",              395,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMSUB",                  "IMSUB",                396,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMDIV",                  "IMDIV",                397,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMPOWER",                "IMPOWER",              398,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMABS",                  "IMABS",                399,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMSQRT",                 "IMSQRT",               400,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMLN",                   "IMLN",                 401,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMLOG2",                 "IMLOG2",               402,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMLOG10",                "IMLOG10",              403,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMSIN",                  "IMSIN",                404,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMCOS",                  "IMCOS",                405,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMEXP",                  "IMEXP",                406,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMARGUMENT",             "IMARGUMENT",           407,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMCONJUGATE",            "IMCONJUGATE",          408,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMAGINARY",              "IMAGINARY",            409,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMREAL",                 "IMREAL",               410,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "COMPLEX",                "COMPLEX",              411,    NOID,   2,  3,  V, { RR }, FuncFlags::EXTERNAL },
    { "IMSUM",                  "IMSUM",                412,    NOID,   1,  MX, V, { RX }, FuncFlags::EXTERNAL },
    { "IMPRODUCT",              "IMPRODUCT",            413,    NOID,   1,  MX, V, { RX }, FuncFlags::EXTERNAL },
    { "SERIESSUM",              "SERIESSUM",            414,    NOID,   4,  4,  V, { RR, RR, RR, RX }, FuncFlags::EXTERNAL },
    { "FACTDOUBLE",             "FACTDOUBLE",           415,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "SQRTPI",                 "SQRTPI",               416,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "QUOTIENT",               "QUOTIENT",             417,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "DELTA",                  "DELTA",                418,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "GESTEP",                 "GESTEP",               419,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "ISEVEN",                 "ISEVEN",               420,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "ISODD",                  "ISODD",                421,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "MROUND",                 "MROUND",               422,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "ERF",                    "ERF",                  423,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "ERFC",                   "ERFC",                 424,    NOID,   1,  1,  V, { RR }, FuncFlags::EXTERNAL },
    { "BESSELJ",                "BESSELJ",              425,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "BESSELK",                "BESSELK",              426,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "BESSELY",                "BESSELY",              427,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "BESSELI",                "BESSELI",              428,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "XIRR",                   "XIRR",                 429,    NOID,   2,  3,  V, { RX, RX, RR }, FuncFlags::EXTERNAL },
    { "XNPV",                   "XNPV",                 430,    NOID,   3,  3,  V, { RR, RX, RX }, FuncFlags::EXTERNAL },
    { "PRICEMAT",               "PRICEMAT",             431,    NOID,   5,  6,  V, { RR }, FuncFlags::EXTERNAL },
    { "YIELDMAT",               "YIELDMAT",             432,    NOID,   5,  6,  V, { RR }, FuncFlags::EXTERNAL },
    { "INTRATE",                "INTRATE",              433,    NOID,   4,  5,  V, { RR }, FuncFlags::EXTERNAL },
    { "RECEIVED",               "RECEIVED",             434,    NOID,   4,  5,  V, { RR }, FuncFlags::EXTERNAL },
    { "DISC",                   "DISC",                 435,    NOID,   4,  5,  V, { RR }, FuncFlags::EXTERNAL },
    { "PRICEDISC",              "PRICEDISC",            436,    NOID,   4,  5,  V, { RR }, FuncFlags::EXTERNAL },
    { "YIELDDISC",              "YIELDDISC",            437,    NOID,   4,  5,  V, { RR }, FuncFlags::EXTERNAL },
    { "TBILLEQ",                "TBILLEQ",              438,    NOID,   3,  3,  V, { RR }, FuncFlags::EXTERNAL },
    { "TBILLPRICE",             "TBILLPRICE",           439,    NOID,   3,  3,  V, { RR }, FuncFlags::EXTERNAL },
    { "TBILLYIELD",             "TBILLYIELD",           440,    NOID,   3,  3,  V, { RR }, FuncFlags::EXTERNAL },
    { "PRICE",                  "PRICE",                441,    NOID,   6,  7,  V, { RR }, FuncFlags::EXTERNAL },
    { "YIELD",                  "YIELD",                442,    NOID,   6,  7,  V, { RR }, FuncFlags::EXTERNAL },
    { "DOLLARDE",               "DOLLARDE",             443,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "DOLLARFR",               "DOLLARFR",             444,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "NOMINAL",                "NOMINAL",              445,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "EFFECT",                 "EFFECT",               446,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "CUMPRINC",               "CUMPRINC",             447,    NOID,   6,  6,  V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "CUMIPMT",                "CUMIPMT",              448,    NOID,   6,  6,  V, { RR }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "EDATE",                  "EDATE",                449,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "EOMONTH",                "EOMONTH",              450,    NOID,   2,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "YEARFRAC",               "YEARFRAC",             451,    NOID,   2,  3,  V, { RR }, FuncFlags::EXTERNAL },
    { "COUPDAYBS",              "COUPDAYBS",            452,    NOID,   3,  4,  V, { RR }, FuncFlags::EXTERNAL },
    { "COUPDAYS",               "COUPDAYS",             453,    NOID,   3,  4,  V, { RR }, FuncFlags::EXTERNAL },
    { "COUPDAYSNC",             "COUPDAYSNC",           454,    NOID,   3,  4,  V, { RR }, FuncFlags::EXTERNAL },
    { "COUPNCD",                "COUPNCD",              455,    NOID,   3,  4,  V, { RR }, FuncFlags::EXTERNAL },
    { "COUPNUM",                "COUPNUM",              456,    NOID,   3,  4,  V, { RR }, FuncFlags::EXTERNAL },
    { "COUPPCD",                "COUPPCD",              457,    NOID,   3,  4,  V, { RR }, FuncFlags::EXTERNAL },
    { "DURATION",               "DURATION",             458,    NOID,   5,  6,  V, { RR }, FuncFlags::EXTERNAL }, // Calc: builtin and add-in (but different!)
    { "MDURATION",              "MDURATION",            459,    NOID,   5,  6,  V, { RR }, FuncFlags::EXTERNAL },
    { "ODDLPRICE",              "ODDLPRICE",            460,    NOID,   7,  8,  V, { RR }, FuncFlags::EXTERNAL },
    { "ODDLYIELD",              "ODDLYIELD",            461,    NOID,   8,  9,  V, { RR }, FuncFlags::EXTERNAL },
    { "ODDFPRICE",              "ODDFPRICE",            462,    NOID,   8,  9,  V, { RR }, FuncFlags::EXTERNAL },
    { "ODDFYIELD",              "ODDFYIELD",            463,    NOID,   8,  9,  V, { RR }, FuncFlags::EXTERNAL },
    { "RANDBETWEEN",            "RANDBETWEEN",          464,    NOID,   2,  2,  V, { RR }, FuncFlags::VOLATILE | FuncFlags::EXTERNAL },
    { "WEEKNUM",                "WEEKNUM",              465,    NOID,   1,  2,  V, { RR }, FuncFlags::EXTERNAL },
    { "AMORDEGRC",              "AMORDEGRC",            466,    NOID,   6,  7,  V, { RR }, FuncFlags::EXTERNAL },
    { "AMORLINC",               "AMORLINC",             467,    NOID,   6,  7,  V, { RR }, FuncFlags::EXTERNAL },
    { "CONVERT",                "CONVERT",              468,    NOID,   3,  3,  V, { RR }, FuncFlags::EXTERNAL },       // Calc: builtin and add-in (but different!)
    { "ACCRINT",                "ACCRINT",              469,    NOID,   6,  7,  V, { RR }, FuncFlags::EXTERNAL },
    { "ACCRINTM",               "ACCRINTM",             470,    NOID,   4,  5,  V, { RR }, FuncFlags::EXTERNAL },
    { "WORKDAY",                "WORKDAY",              471,    NOID,   2,  3,  V, { RR, RR, RX, C }, FuncFlags::EXTERNAL },
    { "NETWORKDAYS",            "NETWORKDAYS",          472,    NOID,   2,  3,  V, { RR, RR, RX, C }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "GCD",                    "GCD",                  473,    NOID,   1,  MX, V, { RX }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "MULTINOMIAL",            "MULTINOMIAL",          474,    NOID,   1,  MX, V, { RX }, FuncFlags::EXTERNAL },
    { "LCM",                    "LCM",                  475,    NOID,   1,  MX, V, { RX }, FuncFlags::EXTERNAL | FuncFlags::INTERNAL }, // Calc: builtin and add-in
    { "FVSCHEDULE",             "FVSCHEDULE",           476,    NOID,   2,  2,  V, { RR, RX }, FuncFlags::EXTERNAL },
 
    // *** macro sheet commands ***
 
    { nullptr,                        "ACTIVATE.NEXT",        104,    104,    0,  1,  V, { VR }, FuncFlags::MACROCMD },      // BIFF2-3: 0, BIFF4: 0-1
    { nullptr,                        "ACTIVATE.PREV",        105,    105,    0,  1,  V, { VR }, FuncFlags::MACROCMD }       // BIFF2-3: 0, BIFF4: 0-1
};
 
/** Functions new in BIFF5/BIFF7. */
const FunctionData saFuncTableBiff5[] =
{
    { "WEEKDAY",                "WEEKDAY",              70,     70,     1,  2,  V, { VR }, FuncFlags::NONE },                              // BIFF2-4: 1,   BIFF5: 1-2
    { "HLOOKUP",                "HLOOKUP",              101,    101,    3,  4,  V, { VV, RO, RO, VV }, FuncFlags::NONE },                     // BIFF2-4: 3,   BIFF5: 3-4
    { "VLOOKUP",                "VLOOKUP",              102,    102,    3,  4,  V, { VV, RO, RO, VV }, FuncFlags::NONE },                     // BIFF2-4: 3,   BIFF5: 3-4
    { "DAYS360",                "DAYS360",              220,    220,    2,  3,  V, { VR }, FuncFlags::NONE },                              // BIFF3-4: 2,   BIFF5: 2-3
    { nullptr,                        "EXTERN.CALL",          255,    255,    1,  MX, R, { RO_E, RO }, FuncFlags::EXPORTONLY },        // MACRO or EXTERNAL
    { "CONCATENATE",            "CONCATENATE",          336,    336,    0,  MX, V, { VR }, FuncFlags::NONE },
    { "POWER",                  "POWER",                337,    337,    2,  2,  V, { VR }, FuncFlags::NONE },
    { "RADIANS",                "RADIANS",              342,    342,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "DEGREES",                "DEGREES",              343,    343,    1,  1,  V, { VR }, FuncFlags::NONE },
    { "SUBTOTAL",               "SUBTOTAL",             344,    344,    2,  MX, V, { VR, RO }, FuncFlags::NONE },
    { "SUMIF",                  "SUMIF",                345,    345,    2,  3,  V, { RO, VR, RO }, FuncFlags::NONE },
    { "COUNTIF",                "COUNTIF",              346,    346,    2,  2,  V, { RO, VR }, FuncFlags::NONE },
    { "COUNTBLANK",             "COUNTBLANK",           347,    347,    1,  1,  V, { RO }, FuncFlags::NONE },
    { "ISPMT",                  "ISPMT",                350,    350,    4,  4,  V, { VR }, FuncFlags::NONE },
    { "DATEDIF",                "DATEDIF",              351,    351,    3,  3,  V, { VR }, FuncFlags::NONE },
    { nullptr,                        "DATESTRING",           352,    352,    1,  1,  V, { VR }, FuncFlags::IMPORTONLY },   // not supported in Calc, missing in OOXML spec
    { nullptr,                        "NUMBERSTRING",         353,    353,    2,  2,  V, { VR }, FuncFlags::IMPORTONLY },   // not supported in Calc, missing in OOXML spec
    { "ROMAN",                  "ROMAN",                354,    354,    1,  2,  V, { VR }, FuncFlags::NONE },
 
    // *** EuroTool add-in ***
    { "EUROCONVERT",            "EUROCONVERT",          NOID,   NOID,   3,  5,  V, { VR }, FuncFlags::EUROTOOL },
 
    // *** macro sheet commands ***
 
    { nullptr,                        "ADD.MENU",             152,    152,    2,  4,  V, { VR, RO, RO, VR }, FuncFlags::MACROFUNC },    // BIFF3-4: 2-3, BIFF5: 2-4
    { nullptr,                        "ADD.COMMAND",          153,    153,    3,  5,  V, { VR, RO, RO, RO, VR }, FuncFlags::MACROFUNC }, // BIFF3-4: 3-4, BIFF5: 3-5
    { nullptr,                        "ADD.CHART.AUTOFORMAT", 390,    390,    0,  2,  V, { VR }, FuncFlags::MACROCMD },
    { nullptr,                        "ADD.LIST.ITEM",        451,    451,    0,  2,  V, { VR }, FuncFlags::MACROCMD },
    { nullptr,                        "ACTIVE.CELL.FONT",     476,    476,    0,  14, V, { VR }, FuncFlags::MACROCMD }
};
 
/** Functions new in BIFF8. */
const FunctionData saFuncTableBiff8[] =
{
    { "GETPIVOTDATA",           "GETPIVOTDATA",         358,    358,    2,  MX, V, { RR, RR, VR, VR }, FuncFlags::IMPORTONLY | FuncFlags::PARAMPAIRS },
    { "HYPERLINK",              "HYPERLINK",            359,    359,    1,  2,  V, { VV, VO }, FuncFlags::NONE },
    { nullptr,                        "PHONETIC",             360,    360,    1,  1,  V, { RO }, FuncFlags::IMPORTONLY },
    { "AVERAGEA",               "AVERAGEA",             361,    361,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "MAXA",                   "MAXA",                 362,    362,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "MINA",                   "MINA",                 363,    363,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "STDEVPA",                "STDEVPA",              364,    364,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "VARPA",                  "VARPA",                365,    365,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "STDEVA",                 "STDEVA",               366,    366,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "VARA",                   "VARA",                 367,    367,    1,  MX, V, { RX }, FuncFlags::NONE },
    { "COM.MICROSOFT.BAHTTEXT", "BAHTTEXT",             368,    368,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAIDAYOFWEEK",        369,    369,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAIDIGIT",            370,    370,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAIMONTHOFYEAR",      371,    371,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAINUMSOUND",         372,    372,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAINUMSTRING",        373,    373,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAISTRINGLENGTH",     374,    374,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "ISTHAIDIGIT",          375,    375,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "ROUNDBAHTDOWN",        376,    376,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "ROUNDBAHTUP",          377,    377,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "THAIYEAR",             378,    378,    1,  1,  V, { VR }, FuncFlags::MACROCALL },
    { nullptr,                        "RTD",                  379,    379,    3,  3,  A, { VR, VR, RO }, FuncFlags::NONE }
};
 
/** Functions new in OOXML. */
const FunctionData saFuncTableOox[] =
{
    { nullptr,                        "CUBEVALUE",            380,    NOID,   1,  MX, V, { VR, RX }, FuncFlags::NONE },
    { nullptr,                        "CUBEMEMBER",           381,    NOID,   2,  3,  V, { VR, RX, VR }, FuncFlags::NONE },
    { nullptr,                        "CUBEMEMBERPROPERTY",   382,    NOID,   3,  3,  V, { VR }, FuncFlags::NONE },
    { nullptr,                        "CUBERANKEDMEMBER",     383,    NOID,   3,  4,  V, { VR }, FuncFlags::NONE },
    { nullptr,                        "CUBEKPIMEMBER",        477,    NOID,   3,  4,  V, { VR }, FuncFlags::NONE },
    { nullptr,                        "CUBESET",              478,    NOID,   2,  5,  V, { VR, RX, VR }, FuncFlags::NONE },
    { nullptr,                        "CUBESETCOUNT",         479,    NOID,   1,  1,  V, { VR }, FuncFlags::NONE },
    { "IFERROR",                "IFERROR",              480,    NOID,   2,  2,  V, { VO, RO }, FuncFlags::MACROCALL },
    { "COUNTIFS",               "COUNTIFS",             481,    NOID,   2,  MX, V, { RO, VR }, FuncFlags::MACROCALL | FuncFlags::PARAMPAIRS },
    { "SUMIFS",                 "SUMIFS",               482,    NOID,   3,  MX, V, { RO, RO, VR }, FuncFlags::MACROCALL | FuncFlags::PARAMPAIRS },
    { "AVERAGEIF",              "AVERAGEIF",            483,    NOID,   2,  3,  V, { RO, VR, RO }, FuncFlags::MACROCALL },
    { "AVERAGEIFS",             "AVERAGEIFS",           484,    NOID,   3,  MX, V, { RO, RO, VR }, FuncFlags::MACROCALL | FuncFlags::PARAMPAIRS },
    { "COM.MICROSOFT.ISO.CEILING",  "ISO.CEILING",     NOID,    NOID,   1,  2,  V, { VR }, FuncFlags::MACROCALL },
    { "COM.MICROSOFT.NETWORKDAYS.INTL", "NETWORKDAYS.INTL", NOID, NOID, 2,  4,  V, { VR, VR, VR, RX }, FuncFlags::MACROCALL },
    { "COM.MICROSOFT.WORKDAY.INTL",     "WORKDAY.INTL",     NOID, NOID, 2,  4,  V, { VR, VR, VR, RX }, FuncFlags::MACROCALL }
};
 
/** Functions new in Excel 2010.
 
    A lot of statistical functions have been renamed (although the 'old' function name still is valid).
    See http://office.microsoft.com/en-us/excel-help/what-s-new-changes-made-to-excel-functions-HA010355760.aspx
 
    Functions with FuncFlags::IMPORTONLY are rewritten in
    sc/source/filter/excel/xeformula.cxx during export for
    BIFF, OOXML export uses this different mapping here but still uses the
    mapping there to determine the feature set.
 
    FIXME: either have the exporter determine the feature set from the active
    mapping, preferred, or enhance that mapping there such that for OOXML the
    rewrite can be overridden.
 
    @See sc/source/filter/excel/xlformula.cxx saFuncTable_2010
 */
/* FIXME: BIFF12 function identifiers available? Where to obtain? */
const FunctionData saFuncTable2010[] =
{
    { "COM.MICROSOFT.COVARIANCE.P",           "COVARIANCE.P",        NOID,    NOID,   2,  2,  V, { VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.COVARIANCE.S",           "COVARIANCE.S",        NOID,    NOID,   2,  2,  V, { VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.STDEV.P",                "STDEV.P",             NOID,    NOID,   1, MX,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.STDEV.S",                "STDEV.S",             NOID,    NOID,   1, MX,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.VAR.P",                  "VAR.P"  ,             NOID,    NOID,   1, MX,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.VAR.S",                  "VAR.S",               NOID,    NOID,   1, MX,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.BETA.DIST",              "BETA.DIST"  ,         NOID,    NOID,   4,  6,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.BETA.INV",               "BETA.INV",            NOID,    NOID,   3,  5,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.BINOM.DIST",             "BINOM.DIST",          NOID,    NOID,   4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.BINOM.INV",              "BINOM.INV",           NOID,    NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CHISQ.DIST",             "CHISQ.DIST",          NOID,    NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CHISQ.INV",              "CHISQ.INV",           NOID,    NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CHISQ.DIST.RT",          "CHISQ.DIST.RT",       NOID,    NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CHISQ.INV.RT",           "CHISQ.INV.RT",        NOID,    NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CHISQ.TEST",             "CHISQ.TEST",          NOID,    NOID,   2,  2,  V, { VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CONFIDENCE.NORM",        "CONFIDENCE.NORM",     NOID,    NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CONFIDENCE.T",           "CONFIDENCE.T",        NOID,    NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "FDIST",                                "F.DIST",              NOID,   NOID,    4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.F.DIST.RT",              "F.DIST.RT",           NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "FINV",                                 "F.INV",               NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.F.INV.RT",               "F.INV.RT",            NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.F.TEST",                 "F.TEST",              NOID,   NOID,    2,  2,  V, { VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.EXPON.DIST",             "EXPON.DIST",          NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.HYPGEOM.DIST",           "HYPGEOM.DIST",        NOID,   NOID,    5,  5,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.POISSON.DIST",           "POISSON.DIST",        NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.WEIBULL.DIST",           "WEIBULL.DIST",        NOID,   NOID,    4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.GAMMA.DIST",             "GAMMA.DIST",          NOID,   NOID,    4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.GAMMA.INV",              "GAMMA.INV",           NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.GAMMALN.PRECISE",        "GAMMALN.PRECISE",     NOID,   NOID,    1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.LOGNORM.DIST",           "LOGNORM.DIST",        NOID,   NOID,    4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.LOGNORM.INV",            "LOGNORM.INV",         NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.NORM.DIST",              "NORM.DIST",           NOID,   NOID,    4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.NORM.INV",               "NORM.INV",            NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.NORM.S.DIST",            "NORM.S.DIST",         NOID,   NOID,    2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.NORM.S.INV",             "NORM.S.INV",          NOID,   NOID,    1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.T.DIST",                 "T.DIST",              NOID,   NOID,    3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.T.DIST.2T",              "T.DIST.2T",           NOID,   NOID,    2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.T.DIST.RT",              "T.DIST.RT",           NOID,   NOID,    2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.T.INV",                  "T.INV",               NOID,   NOID,    2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.T.INV.2T",               "T.INV.2T",            NOID,   NOID,    2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.T.TEST",                 "T.TEST",              NOID,   NOID,    4,  4,  V, { VA, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.PERCENTILE.INC",         "PERCENTILE.INC",      NOID,   NOID,    2,  2,  V, { RX, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.PERCENTRANK.INC",        "PERCENTRANK.INC",     NOID,   NOID,    2,  3,  V, { RX, VR, VR_E }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.QUARTILE.INC",           "QUARTILE.INC",        NOID,   NOID,    2,  2,  V, { RX, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.RANK.EQ",                "RANK.EQ",             NOID,   NOID,    2,  3,  V, { VR, RO, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.PERCENTILE.EXC",         "PERCENTILE.EXC",      NOID,   NOID,    2,  2,  V, { RX, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.PERCENTRANK.EXC",        "PERCENTRANK.EXC",     NOID,   NOID,    2,  3,  V, { RX, VR, VR_E }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.QUARTILE.EXC",           "QUARTILE.EXC",        NOID,   NOID,    2,  2,  V, { RX, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.RANK.AVG",               "RANK.AVG",            NOID,   NOID,    2,  3,  V, { VR, RO, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.MODE.SNGL",              "MODE.SNGL",           NOID,   NOID,    1,  MX, V, { VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.MODE.MULT",              "MODE.MULT",           NOID,   NOID,    1,  MX, V, { VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.NEGBINOM.DIST",          "NEGBINOM.DIST",       NOID,   NOID,    4,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.Z.TEST",                 "Z.TEST",              NOID,   NOID,    2,  3,  V, { RX, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CEILING.PRECISE",        "CEILING.PRECISE",     NOID,   NOID,    1,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FLOOR.PRECISE",          "FLOOR.PRECISE",       NOID,   NOID,    1,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.ERF.PRECISE",            "ERF.PRECISE",         NOID,   NOID,    1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.ERFC.PRECISE",           "ERFC.PRECISE",        NOID,   NOID,    1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.AGGREGATE",              "AGGREGATE",           NOID,   NOID,    3,  MX, V, { VR, RO }, FuncFlags::MACROCALL_NEW }
};
 
/** Functions new in Excel 2013.
 
    See http://office.microsoft.com/en-us/excel-help/new-functions-in-excel-2013-HA103980604.aspx
    Most functions apparently were added for ODF1.2 ODFF / OpenFormula
    compatibility.
 
    Functions with FuncFlags::IMPORTONLY are rewritten in
    sc/source/filter/excel/xeformula.cxx during export for
    BIFF, OOXML export uses this different mapping here but still uses the
    mapping there to determine the feature set.
 
    FIXME: either have the exporter determine the feature set from the active
    mapping, preferred, or enhance that mapping there such that for OOXML the
    rewrite can be overridden.
 
    @See sc/source/filter/excel/xlformula.cxx saFuncTable_2013
 */
/* FIXME: BIFF12 function identifiers available? Where to obtain? */
const FunctionData saFuncTable2013[] =
{
    { "ACOT",                   "ACOT",                 NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ACOTH",                  "ACOTH",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ARABIC",                 "ARABIC",               NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BASE",                   "BASE",                 NOID,   NOID,   2,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BINOM.DIST.RANGE",       "BINOM.DIST.RANGE",     NOID,   NOID,   3,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BITAND",                 "BITAND",               NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BITLSHIFT",              "BITLSHIFT",            NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BITOR",                  "BITOR",                NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BITRSHIFT",              "BITRSHIFT",            NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "BITXOR",                 "BITXOR",               NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CEILING.MATH", "CEILING.MATH",     NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "CEILING",                "CEILING.MATH",         NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::EXPORTONLY | FuncFlags::MACROCALL_NEW },
    { "COMBINA",                "COMBINA",              NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COT",                    "COT",                  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COTH",                   "COTH",                 NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "CSC",                    "CSC",                  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "CSCH",                   "CSCH",                 NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "DAYS",                   "DAYS",                 NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "DECIMAL",                "DECIMAL",              NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.ENCODEURL","ENCODEURL",            NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FILTERXML","FILTERXML",            NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FLOOR.MATH", "FLOOR.MATH",         NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "FLOOR",                  "FLOOR.MATH",           NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::EXPORTONLY | FuncFlags::MACROCALL_NEW },
    // NOTE: this FDIST is not our LEGACY.FDIST
    { nullptr/*"FDIST"*/,             "FDIST",                NOID,   NOID,   3,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    // NOTE: this FINV is not our LEGACY.FINV
    { nullptr/*"FINV"*/,              "FINV",                 NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "FORMULA",                "FORMULATEXT",          NOID,   NOID,   1,  1,  V, { RO }, FuncFlags::MACROCALL_NEW },
    { "GAMMA",                  "GAMMA",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "GAUSS",                  "GAUSS",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "IFNA",                   "IFNA",                 NOID,   NOID,   2,  2,  V, { VO, RO }, FuncFlags::MACROCALL_NEW },
    { "IMCOSH",                 "IMCOSH",               NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMCOT",                  "IMCOT",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMCSC",                  "IMCSC",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMCSCH",                 "IMCSCH",               NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMSEC",                  "IMSEC",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMSECH",                 "IMSECH",               NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMSINH",                 "IMSINH",               NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "IMTAN",                  "IMTAN",                NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ISFORMULA",              "ISFORMULA",            NOID,   NOID,   1,  1,  V, { RO }, FuncFlags::MACROCALL_NEW },
    { "ISOWEEKNUM",             "ISOWEEKNUM",           NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "MUNIT",                  "MUNIT",                NOID,   NOID,   1,  1,  A, { VR }, FuncFlags::MACROCALL_NEW },
    { "NUMBERVALUE",            "NUMBERVALUE",          NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "PDURATION",              "PDURATION",            NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "PERMUTATIONA",           "PERMUTATIONA",         NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "PHI",                    "PHI",                  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "RRI",                    "RRI",                  NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "SEC",                    "SEC",                  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "SECH",                   "SECH",                 NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "SHEET",                  "SHEET",                NOID,   NOID,   0,  1,  V, { RO }, FuncFlags::MACROCALL_NEW },
    { "SHEETS",                 "SHEETS",               NOID,   NOID,   0,  1,  V, { RO }, FuncFlags::MACROCALL_NEW },
    { "SKEWP",                  "SKEW.P",               NOID,   NOID,   1,  MX, V, { RX }, FuncFlags::MACROCALL_NEW },
    { "UNICHAR",                "UNICHAR",              NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "UNICODE",                "UNICODE",              NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.WEBSERVICE","WEBSERVICE",          NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "XOR",                    "XOR",                  NOID,   NOID,   1,  MX, V, { RX }, FuncFlags::MACROCALL_NEW }
};
 
/** Functions new in Excel 2016.
 
    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
    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
 
    @See sc/source/filter/excel/xlformula.cxx saFuncTable_2016
 */
/* FIXME: BIFF12 function identifiers available? Where to obtain? */
const FunctionData saFuncTable2016[] =
{
    { "COM.MICROSOFT.FORECAST.ETS",             "FORECAST.ETS",             NOID,   NOID,   3,  6,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FORECAST.ETS.CONFINT",     "FORECAST.ETS.CONFINT",     NOID,   NOID,   4,  7,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FORECAST.ETS.SEASONALITY", "FORECAST.ETS.SEASONALITY", NOID,   NOID,   2,  4,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FORECAST.ETS.STAT",        "FORECAST.ETS.STAT",        NOID,   NOID,   3,  6,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FORECAST.LINEAR",          "FORECAST.LINEAR",          NOID,   NOID,   3,  3,  V, { VR, VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.CONCAT",                   "CONCAT",                   NOID,   NOID,   1,  MX, V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.TEXTJOIN",                 "TEXTJOIN",                 NOID,   NOID,   3,  MX, V, { VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.IFS",                      "IFS",                      NOID,   NOID,   2,  MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.SWITCH",                   "SWITCH",                   NOID,   NOID,   3,  MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.MINIFS",                   "MINIFS",                   NOID,   NOID,   3,  MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.MAXIFS",                   "MAXIFS",                   NOID,   NOID,   3,  MX, R, { VO, RO }, FuncFlags::MACROCALL_NEW }
};
 
 
 
/** Functions new in Excel 2021.
 
 
    @See sc/source/filter/excel/xlformula.cxx saFuncTable_2021
 */
/* FIXME: BIFF?? function identifiers available? Where to obtain? */
const FunctionData saFuncTable2021[] =
{
    { "COM.MICROSOFT.XLOOKUP",             "XLOOKUP",             NOID,   NOID,   3,  6,  R, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.XMATCH",              "XMATCH",              NOID,   NOID,   2,  4,  V, { VR, VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.FILTER",              "FILTER",              NOID,   NOID,   2,  3,  A, { VR, VA }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.SORT",                "SORT",                NOID,   NOID,   1,  4,  A, { VO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.SORTBY",              "SORTBY",              NOID,   NOID,   2,  MX, V, { RO, RO, VR }, FuncFlags::MACROCALL_NEW | FuncFlags::PARAMPAIRS },
    { "COM.MICROSOFT.SEQUENCE",            "SEQUENCE",            NOID,   NOID,   1,  4,  A, { VO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.RANDARRAY",           "RANDARRAY",           NOID,   NOID,   0,  5,  A, { VO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.UNIQUE",              "UNIQUE",              NOID,   NOID,   1,  3,  A, { VO }, FuncFlags::MACROCALL_NEW },
    { "COM.MICROSOFT.LET",                 "LET",                 NOID,   NOID,   3,  MX, R, { VR, VR, VA }, FuncFlags::MACROCALL_NEW | FuncFlags::PARAMPAIRS },
};
 
 
 
/** Functions defined by OpenFormula, but not supported by Calc or by Excel. */
const FunctionData saFuncTableOdf[] =
{
    { "CHISQDIST",              nullptr,                      NOID,   NOID,   2,  3,  V, { VR }, FuncFlags::MACROCALLODF },
    { "CHISQINV",               nullptr,                      NOID,   NOID,   2,  2,  V, { VR }, FuncFlags::MACROCALLODF }
};
 
/** Functions defined by Calc, but not in OpenFormula nor supported by Excel. */
const FunctionData saFuncTableOOoLO[] =
{
    { "ORG.OPENOFFICE.WEEKS",       "ORG.OPENOFFICE.WEEKS",       NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.MONTHS",      "ORG.OPENOFFICE.MONTHS",      NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.YEARS",       "ORG.OPENOFFICE.YEARS",       NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.ISLEAPYEAR",  "ORG.OPENOFFICE.ISLEAPYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.DAYSINMONTH", "ORG.OPENOFFICE.DAYSINMONTH", NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.DAYSINYEAR",  "ORG.OPENOFFICE.DAYSINYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.WEEKSINYEAR", "ORG.OPENOFFICE.WEEKSINYEAR", NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.ROT13",       "ORG.OPENOFFICE.ROT13",       NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW | FuncFlags::EXTERNAL },
    /* Next 8 lines are for importing from .xlsx files saved by Calc before
     * fdo#59727 was patched with the entries above. */
    { "ORG.OPENOFFICE.WEEKS",       "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFWEEKS",   NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.MONTHS",      "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFMONTHS",  NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.YEARS",       "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFYEARS",   NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.ISLEAPYEAR",  "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETISLEAPYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.DAYSINMONTH", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINMONTH", NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.DAYSINYEAR",  "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.WEEKSINYEAR", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETWEEKSINYEAR", NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    { "ORG.OPENOFFICE.ROT13",       "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETROT13",       NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY | FuncFlags::EXTERNAL },
    // More functions written wrongly in the past.
    { "ORG.OPENOFFICE.ERRORTYPE",   "ORG.OPENOFFICE.ERRORTYPE",     NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW  },
    { "ORG.OPENOFFICE.MULTIRANGE",  "ORG.OPENOFFICE.MULTIRANGE",    NOID,   NOID,   1, MX,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "ORG.OPENOFFICE.GOALSEEK",    "ORG.OPENOFFICE.GOALSEEK",      NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.OPENOFFICE.EASTERSUNDAY","ORG.OPENOFFICE.EASTERSUNDAY",  NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.OPENOFFICE.CURRENT",     "ORG.OPENOFFICE.CURRENT",       NOID,   NOID,   0,  0,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.OPENOFFICE.STYLE",       "ORG.OPENOFFICE.STYLE",         NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    // And the import for the wrongly written functions even without _xlfn.
    { "ORG.OPENOFFICE.ERRORTYPE",   "ERRORTYPE",    NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY },
    { "ORG.OPENOFFICE.MULTIRANGE",  "MULTIRANGE",   NOID,   NOID,   1, MX,  V, { RX }, FuncFlags::IMPORTONLY },
    { "ORG.OPENOFFICE.GOALSEEK",    "GOALSEEK",     NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::IMPORTONLY },
    { "ORG.OPENOFFICE.EASTERSUNDAY","EASTERSUNDAY", NOID,   NOID,   1,  1,  V, { VR }, FuncFlags::IMPORTONLY },
    { "ORG.OPENOFFICE.CURRENT",     "CURRENT",      NOID,   NOID,   0,  0,  V, { VR }, FuncFlags::IMPORTONLY },
    { "ORG.OPENOFFICE.STYLE",       "STYLE",        NOID,   NOID,   1,  3,  V, { VR }, FuncFlags::IMPORTONLY },
    // Other functions.
    { "ORG.OPENOFFICE.CONVERT",     "ORG.OPENOFFICE.CONVERT",   NOID,   NOID,   3,  3,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.COLOR",      "ORG.LIBREOFFICE.COLOR",    NOID,   NOID,   3,  4,  V, { VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.RAWSUBTRACT","ORG.LIBREOFFICE.RAWSUBTRACT",NOID, NOID,   1, MX,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.FORECAST.ETS.MULT",      "ORG.LIBREOFFICE.FORECAST.ETS.MULT",      NOID,   NOID,   3,  6,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT",   "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT",   NOID,   NOID,   4,  7,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", NOID,   NOID,   3,  6,  V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.ROUNDSIG",   "ORG.LIBREOFFICE.ROUNDSIG", NOID, NOID,  2,  2,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.REGEX",      "ORG.LIBREOFFICE.REGEX", NOID, NOID,  2,  4,  V, { RX }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.FOURIER",    "ORG.LIBREOFFICE.FOURIER", NOID, NOID,  2,  5,  A, { RX }, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.RAND.NV",    "ORG.LIBREOFFICE.RAND.NV", NOID, NOID,  0,  0,  V, {}, FuncFlags::MACROCALL_NEW },
    { "ORG.LIBREOFFICE.RANDBETWEEN.NV", "ORG.LIBREOFFICE.RANDBETWEEN.NV", NOID, NOID,  2,  2,  V, { VR }, FuncFlags::MACROCALL_NEW }
 
};
 
const sal_Unicode API_TOKEN_OPEN            = '(';
const sal_Unicode API_TOKEN_CLOSE           = ')';
const sal_Unicode API_TOKEN_SEP             = ';';
 
const sal_Unicode API_TOKEN_ARRAY_OPEN      = '{';
const sal_Unicode API_TOKEN_ARRAY_CLOSE     = '}';
const sal_Unicode API_TOKEN_ARRAY_ROWSEP    = '|';
const sal_Unicode API_TOKEN_ARRAY_COLSEP    = ';';
 
} // namespace
 
// function info parameter class iterator =====================================
 
FunctionParamInfoIterator::FunctionParamInfoIterator( const FunctionInfo& rFuncInfo ) :
    mpParamInfo( rFuncInfo.mpParamInfos ),
    mpParamInfoEnd( rFuncInfo.mpParamInfos + FUNCINFO_PARAMINFOCOUNT ),
    mbParamPairs( rFuncInfo.mbParamPairs )
{
}
 
bool FunctionParamInfoIterator::isCalcOnlyParam() const
{
    return mpParamInfo && (mpParamInfo->meValid == FuncParamValidity::CalcOnly);
}
 
bool FunctionParamInfoIterator::isExcelOnlyParam() const
{
    return mpParamInfo && (mpParamInfo->meValid == FuncParamValidity::ExcelOnly);
}
 
FunctionParamInfoIterator& FunctionParamInfoIterator::operator++()
{
    if( mpParamInfo )
    {
        // move pointer to next entry, if something explicit follows
        if( mpParamInfo + 1 < mpParamInfoEnd )
            ++mpParamInfo;
        // if last parameter type is 'Excel-only' or 'Calc-only', do not repeat it
        else if( isExcelOnlyParam() || isCalcOnlyParam() )
            mpParamInfo = nullptr;
        // points to last info, but parameter pairs expected, move to previous info
        else if( mbParamPairs )
            --mpParamInfo;
        // otherwise: repeat last parameter class
    }
    return *this;
}
 
// function provider ==========================================================
 
struct FunctionProviderImpl
{
    typedef RefMap< OUString, FunctionInfo >    FuncNameMap;
    typedef RefMap< sal_uInt16, FunctionInfo >  FuncIdMap;
 
    FunctionInfoVector  maFuncs;            /// All function infos in one list.
    FuncNameMap         maOoxFuncs;         /// Maps OOXML function names to function data.
    FuncIdMap           maBiff12Funcs;      /// Maps BIFF12 function indexes to function data.
    FuncIdMap           maBiffFuncs;        /// Maps BIFF2-BIFF8 function indexes to function data.
    FuncNameMap         maMacroFuncs;       /// Maps macro function names to function data.
 
    explicit            FunctionProviderImpl(bool bImportFilter);
 
private:
    /** Creates and inserts a function info struct from the passed function data. */
    void                initFunc(const FunctionData& rFuncData);
 
    /** Initializes the members from the passed function data list. */
    void                initFuncs(const FunctionData* pBeg, const FunctionData* pEnd, bool bImportFilter);
};
 
FunctionProviderImpl::FunctionProviderImpl( bool bImportFilter )
{
    /*  Add functions supported in the current BIFF version only. Function
        tables from later BIFF versions may overwrite single functions from
        earlier tables. */
    initFuncs(saFuncTableBiff2, std::end(saFuncTableBiff2), bImportFilter);
    initFuncs(saFuncTableBiff3, std::end(saFuncTableBiff3), bImportFilter);
    initFuncs(saFuncTableBiff4, std::end(saFuncTableBiff4), bImportFilter);
    initFuncs(saFuncTableBiff5, std::end(saFuncTableBiff5), bImportFilter);
    initFuncs(saFuncTableBiff8, std::end(saFuncTableBiff8), bImportFilter);
    initFuncs(saFuncTableOox  , std::end(saFuncTableOox)  , bImportFilter);
    initFuncs(saFuncTable2010 , std::end(saFuncTable2010) , bImportFilter);
    initFuncs(saFuncTable2013 , std::end(saFuncTable2013) , bImportFilter);
    initFuncs(saFuncTable2016 , std::end(saFuncTable2016) , bImportFilter);
    initFuncs(saFuncTable2021 , std::end(saFuncTable2021 ), bImportFilter);
    initFuncs(saFuncTableOdf  , std::end(saFuncTableOdf)  , bImportFilter);
    initFuncs(saFuncTableOOoLO, std::end(saFuncTableOOoLO), bImportFilter);
}
 
void FunctionProviderImpl::initFunc(const FunctionData& rFuncData)
{
    // create a function info object
    FunctionInfoRef xFuncInfo = std::make_shared<FunctionInfo>();
    if( rFuncData.mpcOdfFuncName )
        xFuncInfo->maOdfFuncName = OUString::createFromAscii( rFuncData.mpcOdfFuncName );
    if( rFuncData.mpcOoxFuncName )
        xFuncInfo->maOoxFuncName = OUString::createFromAscii( rFuncData.mpcOoxFuncName );
 
    if( rFuncData.mnFlags & FuncFlags::MACROCALL )
    {
        OSL_ENSURE( !xFuncInfo->maOoxFuncName.isEmpty(), "FunctionProviderImpl::initFunc - missing OOXML function name" );
        OSL_ENSURE( !(rFuncData.mnFlags & FuncFlags::MACROCALLODF ), "FunctionProviderImpl::initFunc - unexpected flag FuncFlags::MACROCALLODF" );
        xFuncInfo->maBiffMacroName = "_xlfn." + xFuncInfo->maOoxFuncName;
        if( rFuncData.mnFlags & FuncFlags::MACROCALL_FN )
        {
            xFuncInfo->maOoxFuncName = "_xlfn." + xFuncInfo->maOoxFuncName;
            //! From here on maOoxFuncName contains the _xlfn. prefix!
        }
    }
    else if( rFuncData.mnFlags & FuncFlags::MACROCALLODF )
    {
        OSL_ENSURE( !xFuncInfo->maOdfFuncName.isEmpty(), "FunctionProviderImpl::initFunc - missing ODF function name" );
        xFuncInfo->maBiffMacroName = "_xlfnodf." + xFuncInfo->maOdfFuncName;
    }
    xFuncInfo->meFuncLibType = (rFuncData.mnFlags & FuncFlags::EUROTOOL) ? FUNCLIB_EUROTOOL : FUNCLIB_UNKNOWN;
    xFuncInfo->mnApiOpCode = -1;
    xFuncInfo->mnBiff12FuncId = rFuncData.mnBiff12FuncId;
    xFuncInfo->mnBiffFuncId = rFuncData.mnBiffFuncId;
    xFuncInfo->mnMinParamCount = rFuncData.mnMinParamCount;
    xFuncInfo->mnMaxParamCount = (rFuncData.mnMaxParamCount == MX) ? OOX_MAX_PARAMCOUNT : rFuncData.mnMaxParamCount;
    xFuncInfo->mnRetClass = rFuncData.mnRetClass;
    xFuncInfo->mpParamInfos = rFuncData.mpParamInfos;
    xFuncInfo->mbParamPairs = bool(rFuncData.mnFlags & FuncFlags::PARAMPAIRS);
    xFuncInfo->mbVolatile = bool(rFuncData.mnFlags & FuncFlags::VOLATILE);
    xFuncInfo->mbExternal = bool(rFuncData.mnFlags & FuncFlags::EXTERNAL);
    xFuncInfo->mbInternal = !xFuncInfo->mbExternal || ( rFuncData.mnFlags & FuncFlags::INTERNAL );
    bool bMacroCmd(rFuncData.mnFlags & FuncFlags::MACROCMD);
    xFuncInfo->mbMacroFunc = bMacroCmd || ( rFuncData.mnFlags & FuncFlags::MACROFUNC );
    xFuncInfo->mbVarParam = bMacroCmd || (rFuncData.mnMinParamCount != rFuncData.mnMaxParamCount) || ( rFuncData.mnFlags & FuncFlags::ALWAYSVAR );
 
    setFlag( xFuncInfo->mnBiff12FuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
    setFlag( xFuncInfo->mnBiffFuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
 
    // insert the function info into the member maps
    maFuncs.push_back( xFuncInfo );
    if( !xFuncInfo->maOoxFuncName.isEmpty() )
        maOoxFuncs[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
    if( xFuncInfo->mnBiff12FuncId != NOID )
        maBiff12Funcs[ xFuncInfo->mnBiff12FuncId ] = xFuncInfo;
    if( xFuncInfo->mnBiffFuncId != NOID )
        maBiffFuncs[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
    if( !xFuncInfo->maBiffMacroName.isEmpty() )
        maMacroFuncs[ xFuncInfo->maBiffMacroName ] = xFuncInfo;
}
 
void FunctionProviderImpl::initFuncs(const FunctionData* pBeg, const FunctionData* pEnd, bool bImportFilter)
{
    for( const FunctionData* pIt = pBeg; pIt != pEnd; ++pIt )
        if( pIt->isSupported(bImportFilter) )
            initFunc(*pIt);
}
 
FunctionProvider::FunctionProvider(  bool bImportFilter ) :
    mxFuncImpl( std::make_shared<FunctionProviderImpl>( bImportFilter ) )
{
}
 
FunctionProvider::~FunctionProvider()
{
}
 
const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
{
    return mxFuncImpl->maOoxFuncs.get( rFuncName ).get();
}
 
const FunctionInfo* FunctionProvider::getFuncInfoFromBiff12FuncId( sal_uInt16 nFuncId ) const
{
    return mxFuncImpl->maBiff12Funcs.get( nFuncId ).get();
}
 
const FunctionInfo* FunctionProvider::getFuncInfoFromMacroName( const OUString& rFuncName ) const
{
    return mxFuncImpl->maMacroFuncs.get( rFuncName ).get();
}
 
FunctionLibraryType FunctionProvider::getFuncLibTypeFromLibraryName( std::u16string_view rLibraryName )
{
    // the EUROTOOL add-in containing the EUROCONVERT function
    if(   o3tl::equalsIgnoreAsciiCase(rLibraryName, u"EUROTOOL.XLA")
       || o3tl::equalsIgnoreAsciiCase(rLibraryName, u"EUROTOOL.XLAM"))
        return FUNCLIB_EUROTOOL;
 
    // default: unknown library
    return FUNCLIB_UNKNOWN;
}
 
const FunctionInfoVector& FunctionProvider::getFuncs() const
{
    return mxFuncImpl->maFuncs;
}
 
// op-code and function provider ==============================================
 
struct OpCodeProviderImpl : public ApiOpCodes
{
    typedef RefMap< sal_Int32, FunctionInfo >       OpCodeFuncMap;
    typedef RefMap< OUString, FunctionInfo >        FuncNameMap;
    typedef ::std::vector< FormulaOpCodeMapEntry >  OpCodeEntryVector;
 
    OpCodeFuncMap       maOpCodeFuncs;      /// Maps API function op-codes to function data.
    FuncNameMap         maExtProgFuncs;     /// Maps programmatical API function names to function data.
    OpCodeEntryVector   maParserMap;        /// OOXML token mapping for formula parser service.
 
    explicit            OpCodeProviderImpl(
                            const FunctionInfoVector& rFuncInfos,
                            const Reference< XMultiServiceFactory >& rxModelFactory );
 
private:
    typedef ::std::map< OUString, ApiToken >    ApiTokenMap;
    typedef Sequence< FormulaOpCodeMapEntry >   OpCodeEntrySequence;
 
    static bool         fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
    static bool         fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
    bool                fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const;
 
    static bool         initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName );
    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const char* pcOdfName, const char* pcOoxName );
    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName );
 
    bool                initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap );
    bool                initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos );
};
 
OpCodeProviderImpl::OpCodeProviderImpl( const FunctionInfoVector& rFuncInfos,
        const Reference< XMultiServiceFactory >& rxModelFactory )
{
    if( !rxModelFactory.is() )
        return;
 
    try
    {
        Reference< XFormulaOpCodeMapper > xMapper( rxModelFactory->createInstance(
            u"com.sun.star.sheet.FormulaOpCodeMapper"_ustr ), UNO_QUERY_THROW );
 
        // op-codes provided as attributes
        OPCODE_UNKNOWN = xMapper->getOpCodeUnknown();
        OPCODE_EXTERNAL = xMapper->getOpCodeExternal();
 
        using namespace ::com::sun::star::sheet::FormulaMapGroup;
        using namespace ::com::sun::star::sheet::FormulaMapGroupSpecialOffset;
 
        OpCodeEntrySequence aEntrySeq;
        ApiTokenMap aTokenMap, aExtFuncTokenMap;
        bool bIsValid =
            // special
            fillEntrySeq( aEntrySeq, xMapper, SPECIAL ) &&
            initOpCode( OPCODE_PUSH,          aEntrySeq, PUSH ) &&
            initOpCode( OPCODE_MISSING,       aEntrySeq, MISSING ) &&
            initOpCode( OPCODE_SPACES,        aEntrySeq, SPACES ) &&
            initOpCode( OPCODE_NAME,          aEntrySeq, NAME ) &&
            initOpCode( OPCODE_DBAREA,        aEntrySeq, DB_AREA ) &&
            initOpCode( OPCODE_NLR,           aEntrySeq, COL_ROW_NAME ) &&
            initOpCode( OPCODE_MACRO,         aEntrySeq, MACRO ) &&
            initOpCode( OPCODE_BAD,           aEntrySeq, BAD ) &&
            initOpCode( OPCODE_NONAME,        aEntrySeq, NO_NAME ) &&
            // separators
            fillTokenMap( aTokenMap, aEntrySeq, xMapper, SEPARATORS ) &&
            initOpCode( OPCODE_OPEN,          aTokenMap, API_TOKEN_OPEN,  '('  ) &&
            initOpCode( OPCODE_CLOSE,         aTokenMap, API_TOKEN_CLOSE, ')'  ) &&
            initOpCode( OPCODE_SEP,           aTokenMap, API_TOKEN_SEP,   ','  ) &&
            // array separators
            fillTokenMap( aTokenMap, aEntrySeq, xMapper, ARRAY_SEPARATORS ) &&
            initOpCode( OPCODE_ARRAY_OPEN,    aTokenMap, API_TOKEN_ARRAY_OPEN,   '{'  ) &&
            initOpCode( OPCODE_ARRAY_CLOSE,   aTokenMap, API_TOKEN_ARRAY_CLOSE,  '}'  ) &&
            initOpCode( OPCODE_ARRAY_ROWSEP,  aTokenMap, API_TOKEN_ARRAY_ROWSEP, ';'  ) &&
            initOpCode( OPCODE_ARRAY_COLSEP,  aTokenMap, API_TOKEN_ARRAY_COLSEP, ','  ) &&
            // unary operators
            fillTokenMap( aTokenMap, aEntrySeq, xMapper, UNARY_OPERATORS ) &&
            initOpCode( OPCODE_PLUS_SIGN,     aTokenMap, '+',  '\0' ) && // same op-code as OPCODE_ADD
            initOpCode( OPCODE_MINUS_SIGN,    aTokenMap, '-',  '-'  ) &&
            initOpCode( OPCODE_PERCENT,       aTokenMap, '%',  '%'  ) &&
            // binary operators
            fillTokenMap( aTokenMap, aEntrySeq, xMapper, BINARY_OPERATORS ) &&
            initOpCode( OPCODE_ADD,           aTokenMap, '+',  '+'  ) &&
            initOpCode( OPCODE_SUB,           aTokenMap, '-',  '-'  ) &&
            initOpCode( OPCODE_MULT,          aTokenMap, '*',  '*'  ) &&
            initOpCode( OPCODE_DIV,           aTokenMap, '/',  '/'  ) &&
            initOpCode( OPCODE_POWER,         aTokenMap, '^',  '^'  ) &&
            initOpCode( OPCODE_CONCAT,        aTokenMap, '&',  '&'  ) &&
            initOpCode( OPCODE_EQUAL,         aTokenMap, '=',  '='  ) &&
            initOpCode( OPCODE_NOT_EQUAL,     aTokenMap, "<>", "<>" ) &&
            initOpCode( OPCODE_LESS,          aTokenMap, '<',  '<'  ) &&
            initOpCode( OPCODE_LESS_EQUAL,    aTokenMap, "<=", "<=" ) &&
            initOpCode( OPCODE_GREATER,       aTokenMap, '>',  '>'  ) &&
            initOpCode( OPCODE_GREATER_EQUAL, aTokenMap, ">=", ">=" ) &&
            initOpCode( OPCODE_INTERSECT,     aTokenMap, '!',  ' '  ) &&
            initOpCode( OPCODE_LIST,          aTokenMap, '~',  ','  ) &&
            initOpCode( OPCODE_RANGE,         aTokenMap, ':',  ':'  ) &&
            // functions
            fillFuncTokenMaps( aTokenMap, aExtFuncTokenMap, aEntrySeq, xMapper ) &&
            initFuncOpCodes( aTokenMap, aExtFuncTokenMap, rFuncInfos ) &&
            initOpCode( OPCODE_DDE,           aTokenMap, "DDE", nullptr );
 
        OSL_ENSURE( bIsValid, "OpCodeProviderImpl::OpCodeProviderImpl - opcodes not initialized" );
 
        // OPCODE_PLUS_SIGN and OPCODE_ADD should be equal, otherwise "+" has to be passed above
        OSL_ENSURE( OPCODE_PLUS_SIGN == OPCODE_ADD, "OpCodeProviderImpl::OpCodeProviderImpl - need opcode mapping for OPCODE_PLUS_SIGN" );
    }
    catch( Exception& )
    {
        OSL_FAIL( "OpCodeProviderImpl::OpCodeProviderImpl - cannot receive formula opcode mapper" );
    }
}
 
bool OpCodeProviderImpl::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
        const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
{
    try
    {
        orEntrySeq = rxMapper->getAvailableMappings( css::sheet::FormulaLanguage::ODFF, nMapGroup );
        return orEntrySeq.hasElements();
    }
    catch( Exception& )
    {
    }
    return false;
}
 
bool OpCodeProviderImpl::fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq,
        const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
{
    orTokenMap.clear();
    if( fillEntrySeq( orEntrySeq, rxMapper, nMapGroup ) )
    {
        for (const FormulaOpCodeMapEntry& rEntry : orEntrySeq)
            orTokenMap[ rEntry.Name ] = rEntry.Token;
    }
    return orEntrySeq.hasElements();
}
 
bool OpCodeProviderImpl::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const
{
    orIntFuncTokenMap.clear();
    orExtFuncTokenMap.clear();
    if( fillEntrySeq( orEntrySeq, rxMapper, css::sheet::FormulaMapGroup::FUNCTIONS ) )
    {
        for (const FormulaOpCodeMapEntry& rEntry : orEntrySeq)
            ((rEntry.Token.OpCode == OPCODE_EXTERNAL) ? orExtFuncTokenMap : orIntFuncTokenMap)[ rEntry.Name ] = rEntry.Token;
    }
    return orEntrySeq.hasElements();
}
 
bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId )
{
    if( (0 <= nSpecialId) && (nSpecialId < rEntrySeq.getLength()) )
    {
        ornOpCode = rEntrySeq[ nSpecialId ].Token.OpCode;
        return true;
    }
    OSL_FAIL( OString( OString::Concat("OpCodeProviderImpl::initOpCode - opcode for special offset ") +
                       OString::number( nSpecialId ) + " not found" ).getStr() );
    return false;
}
 
bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName )
{
    ApiTokenMap::const_iterator aIt = rTokenMap.find( rOdfName );
    if( aIt != rTokenMap.end() )
    {
        ornOpCode = aIt->second.OpCode;
        if( !rOoxName.isEmpty() )
        {
            FormulaOpCodeMapEntry aEntry;
            aEntry.Name = rOoxName;
            aEntry.Token.OpCode = ornOpCode;
            maParserMap.push_back( aEntry );
        }
        return true;
    }
    OSL_FAIL( OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for \"" +
            OUStringToOString( rOdfName, RTL_TEXTENCODING_ASCII_US ) +
            "\" not found" ).getStr() );
    return false;
}
 
bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const char* pcOdfName, const char* pcOoxName )
{
    OUString aOoxName;
    if( pcOoxName ) aOoxName = OUString::createFromAscii( pcOoxName );
    return initOpCode( ornOpCode, rTokenMap, OUString::createFromAscii( pcOdfName ), aOoxName );
}
 
bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName )
{
    OUString aOoxName;
    if( cOoxName ) aOoxName = OUString( cOoxName );
    return initOpCode( ornOpCode, rTokenMap, OUString( cOdfName ), aOoxName );
}
 
bool OpCodeProviderImpl::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap )
{
    bool bIsValid = false;
    if( !orFuncInfo.maOdfFuncName.isEmpty() )
    {
        ApiTokenMap::const_iterator aIt = rFuncTokenMap.find( orFuncInfo.maOdfFuncName );
        if( aIt != rFuncTokenMap.end() )
        {
            orFuncInfo.mnApiOpCode = aIt->second.OpCode;
            bIsValid =
                (orFuncInfo.mnApiOpCode >= 0) &&
                (orFuncInfo.mnApiOpCode != OPCODE_UNKNOWN) &&
                (orFuncInfo.mnApiOpCode != OPCODE_NONAME);
            OSL_ENSURE( bIsValid,
                OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no valid opcode for ODF function \""
                    + OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US )
                    + "\"" ).getStr() );
 
            if( bIsValid && (orFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) )
            {
                bIsValid = (aIt->second.Data >>= orFuncInfo.maExtProgName) && !orFuncInfo.maExtProgName.isEmpty();
                OSL_ENSURE( bIsValid,
                    OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no programmatical name for external function \""
                        + OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US )
                        + "\"" ).getStr() );
            }
 
            // add to parser map, if OOXML function name exists
            if( bIsValid && !orFuncInfo.maOoxFuncName.isEmpty() )
            {
                // create the parser map entry
                FormulaOpCodeMapEntry aEntry;
                aEntry.Name = orFuncInfo.maOoxFuncName;
                aEntry.Token = aIt->second;
                maParserMap.push_back( aEntry );
            }
        }
        else
        {
            // ignore entries for functions unknown by Calc *and* by Excel
            bIsValid = orFuncInfo.maOoxFuncName.isEmpty();
            SAL_WARN_IF( !bIsValid, "sc",
                    "OpCodeProviderImpl::initFuncOpCode - no opcode mapping for function ODF '" <<
                    orFuncInfo.maOdfFuncName << "' <-> OOXML '" << orFuncInfo.maOoxFuncName << "'");
        }
    }
    else if( orFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
    {
        orFuncInfo.mnApiOpCode = OPCODE_EXTERNAL;
        bIsValid = true;
    }
    else if( !orFuncInfo.maOoxFuncName.isEmpty() )
    {
        orFuncInfo.mnApiOpCode = OPCODE_BAD;
        bIsValid = true;
    }
 
    if( !bIsValid || (orFuncInfo.mnApiOpCode == OPCODE_UNKNOWN) || (orFuncInfo.mnApiOpCode < 0) )
        orFuncInfo.mnApiOpCode = OPCODE_NONAME;
    return bIsValid;
}
 
bool OpCodeProviderImpl::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos )
{
    bool bIsValid = true;
    for( const FunctionInfoRef& xFuncInfo : rFuncInfos )
    {
        // set API opcode from ODF function name
        if (xFuncInfo->mbExternal)
            bIsValid &= initFuncOpCode( *xFuncInfo, rExtFuncTokenMap );
        if (xFuncInfo->mbInternal)
            bIsValid &= initFuncOpCode( *xFuncInfo, rIntFuncTokenMap );
        // insert the function info into the maps
        if( (xFuncInfo->mnApiOpCode != OPCODE_NONAME) && (xFuncInfo->mnApiOpCode != OPCODE_BAD) )
        {
            if( (xFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && !xFuncInfo->maExtProgName.isEmpty() )
                maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
            else
                maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
        }
    }
    return bIsValid;
}
 
OpCodeProvider::OpCodeProvider( const Reference< XMultiServiceFactory >& rxModelFactory,
         bool bImportFilter ) :
    FunctionProvider( bImportFilter ),
    mxOpCodeImpl( std::make_shared<OpCodeProviderImpl>( getFuncs(), rxModelFactory ) )
{
}
 
OpCodeProvider::~OpCodeProvider()
{
}
 
const ApiOpCodes& OpCodeProvider::getOpCodes() const
{
    return *mxOpCodeImpl;
}
 
const FunctionInfo* OpCodeProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
{
    const FunctionInfo* pFuncInfo = nullptr;
    if( (rToken.OpCode == mxOpCodeImpl->OPCODE_EXTERNAL) && rToken.Data.has< OUString >() )
        pFuncInfo = mxOpCodeImpl->maExtProgFuncs.get( rToken.Data.get< OUString >() ).get();
    else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_MACRO) && rToken.Data.has< OUString >() )
        pFuncInfo = getFuncInfoFromMacroName( rToken.Data.get< OUString >() );
    else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_BAD) && rToken.Data.has< OUString >() )
        pFuncInfo = getFuncInfoFromOoxFuncName( rToken.Data.get< OUString >() );
    else
        pFuncInfo = mxOpCodeImpl->maOpCodeFuncs.get( rToken.OpCode ).get();
    return pFuncInfo;
}
 
Sequence< FormulaOpCodeMapEntry > OpCodeProvider::getOoxParserMap() const
{
    return comphelper::containerToSequence( mxOpCodeImpl->maParserMap );
}
 
// API formula parser wrapper =================================================
 
ApiParserWrapper::ApiParserWrapper(
        const Reference< XMultiServiceFactory >& rxModelFactory, const OpCodeProvider& rOpCodeProv ) :
    OpCodeProvider( rOpCodeProv )
{
    if( rxModelFactory.is() ) try
    {
        mxParser.set( rxModelFactory->createInstance( u"com.sun.star.sheet.FormulaParser"_ustr ), UNO_QUERY_THROW );
    }
    catch( Exception& )
    {
    }
    OSL_ENSURE( mxParser.is(), "ApiParserWrapper::ApiParserWrapper - cannot create API formula parser object" );
    maParserProps.set( mxParser );
    maParserProps.setProperty( PROP_CompileEnglish, true );
    maParserProps.setProperty( PROP_FormulaConvention, css::sheet::AddressConvention::XL_OOX );
    maParserProps.setProperty( PROP_IgnoreLeadingSpaces, false );
    maParserProps.setProperty( PROP_OpCodeMap, getOoxParserMap() );
}
 
ApiTokenSequence ApiParserWrapper::parseFormula( const OUString& rFormula, const ScAddress& rRefPos )
{
    ApiTokenSequence aTokenSeq;
    if( mxParser.is() ) try
    {
        aTokenSeq = mxParser->parseFormula( rFormula,
                                            CellAddress(rRefPos.Tab(), rRefPos.Col(), rRefPos.Row()) );
    }
    catch( Exception& )
    {
    }
    return aTokenSeq;
}
 
// formula parser/printer base class for filters ==============================
 
namespace {
 
bool lclConvertToCellAddress( ScAddress& orAddress, const SingleReference& rSingleRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
{
    orAddress = ScAddress( rSingleRef.Column, rSingleRef.Row, rSingleRef.Sheet );
    return
        !getFlag( rSingleRef.Flags, nForbiddenFlags ) &&
        ((nFilterBySheet < 0) || (nFilterBySheet == rSingleRef.Sheet));
}
 
bool lclConvertToCellRange( ScRange& orRange, const ComplexReference& rComplexRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
{
    orRange = ScRange( rComplexRef.Reference1.Column, rComplexRef.Reference1.Row, rComplexRef.Reference1.Sheet,
                       rComplexRef.Reference2.Column, rComplexRef.Reference2.Row, rComplexRef.Reference2.Sheet );
    return
        !getFlag( rComplexRef.Reference1.Flags, nForbiddenFlags ) &&
        !getFlag( rComplexRef.Reference2.Flags, nForbiddenFlags ) &&
        (rComplexRef.Reference1.Sheet == rComplexRef.Reference2.Sheet) &&
        ((nFilterBySheet < 0) || (nFilterBySheet == rComplexRef.Reference1.Sheet));
}
 
enum TokenToRangeListState { STATE_REF, STATE_SEP, STATE_OPEN, STATE_CLOSE, STATE_ERROR };
 
TokenToRangeListState lclProcessRef( ScRangeList& orRanges, const Any& rData, sal_Int32 nFilterBySheet )
{
    using namespace ::com::sun::star::sheet::ReferenceFlags;
    const sal_Int32 FORBIDDEN_FLAGS_REL = COLUMN_DELETED | ROW_DELETED | SHEET_DELETED |
                                          COLUMN_RELATIVE | ROW_RELATIVE | SHEET_RELATIVE | RELATIVE_NAME;
 
    sal_Int32 nForbiddenFlags = FORBIDDEN_FLAGS_REL;
    SingleReference aSingleRef;
    if( rData >>= aSingleRef )
    {
        ScAddress aAddress;
        // ignore invalid addresses (with #REF! errors), but do not stop parsing
        if( lclConvertToCellAddress( aAddress, aSingleRef, nForbiddenFlags, nFilterBySheet ) )
            orRanges.push_back( ScRange(aAddress, aAddress) );
        return STATE_REF;
    }
    ComplexReference aComplexRef;
    if( rData >>= aComplexRef )
    {
        ScRange aRange;
        // ignore invalid ranges (with #REF! errors), but do not stop parsing
        if( lclConvertToCellRange( aRange, aComplexRef, nForbiddenFlags, nFilterBySheet ) )
            orRanges.push_back( aRange );
        return STATE_REF;
    }
    return STATE_ERROR;
}
 
TokenToRangeListState lclProcessOpen( sal_Int32& ornParenLevel )
{
    ++ornParenLevel;
    return STATE_OPEN;
}
 
TokenToRangeListState lclProcessClose( sal_Int32& ornParenLevel )
{
    --ornParenLevel;
    return (ornParenLevel >= 0) ? STATE_CLOSE : STATE_ERROR;
}
 
} // namespace
 
FormulaProcessorBase::FormulaProcessorBase( const WorkbookHelper& rHelper ) :
    OpCodeProvider( rHelper.getBaseFilter().getModelFactory(), rHelper.getBaseFilter().isImportFilter() ),
    ApiOpCodes( getOpCodes() ),
    WorkbookHelper( rHelper )
{
}
 
OUString FormulaProcessorBase::generateAddress2dString( const ScAddress& rAddress, bool bAbsolute )
{
    return generateAddress2dString( BinAddress( rAddress ), bAbsolute );
}
 
OUString FormulaProcessorBase::generateAddress2dString( const BinAddress& rAddress, bool bAbsolute )
{
    OUStringBuffer aBuffer;
    // column
    for( sal_Int32 nTemp = rAddress.mnCol; nTemp >= 0; nTemp = (nTemp / 26) - 1 )
        aBuffer.insert( 0, sal_Unicode( 'A' + (nTemp % 26) ) );
    if( bAbsolute )
        aBuffer.insert( 0, '$' );
    // row
    if( bAbsolute )
        aBuffer.append( '$' );
    aBuffer.append( static_cast< sal_Int32 >( rAddress.mnRow + 1 ) );
    return aBuffer.makeStringAndClear();
}
 
OUString FormulaProcessorBase::generateApiArray( const Matrix< Any >& rMatrix )
{
    OSL_ENSURE( !rMatrix.empty(), "FormulaProcessorBase::generateApiArray - missing matrix values" );
    OUStringBuffer aBuffer(( OUStringChar(API_TOKEN_ARRAY_OPEN) ));
    for( size_t nRow = 0, nHeight = rMatrix.height(); nRow < nHeight; ++nRow )
    {
        if( nRow > 0 )
            aBuffer.append( API_TOKEN_ARRAY_ROWSEP );
        for( Matrix< Any >::const_iterator aBeg = rMatrix.row_begin( nRow ), aIt = aBeg, aEnd = rMatrix.row_end( nRow ); aIt != aEnd; ++aIt )
        {
            double fValue = 0.0;
            OUString aString;
            if( aIt != aBeg )
                aBuffer.append( API_TOKEN_ARRAY_COLSEP );
            if( *aIt >>= fValue )
                aBuffer.append( fValue );
            else if( *aIt >>= aString )
            {
                // generate Api String
                aBuffer.append( "\"" + aString.replaceAll(u"\"", u"\"\"") + "\"" );
            }
            else
                aBuffer.append( "\"\"" );
        }
    }
    aBuffer.append( API_TOKEN_ARRAY_CLOSE );
    return aBuffer.makeStringAndClear();
}
 
Any FormulaProcessorBase::extractReference( const ApiTokenSequence& rTokens ) const
{
    ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES );
    if( aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) )
    {
        Any aRefAny = aTokenIt->Data;
        if( !(++aTokenIt).is() && (aRefAny.has< SingleReference >() || aRefAny.has< ComplexReference >()) )
            return aRefAny;
    }
    return Any();
}
 
bool FormulaProcessorBase::extractCellRange( ScRange& orRange,
        const ApiTokenSequence& rTokens ) const
{
    ScRangeList aRanges;
    lclProcessRef( aRanges, extractReference( rTokens ), -1 );
    if( !aRanges.empty() )
    {
        orRange = aRanges.front();
        return true;
    }
    return false;
}
 
void FormulaProcessorBase::extractCellRangeList( ScRangeList& orRanges,
        const ApiTokenSequence& rTokens, sal_Int32 nFilterBySheet ) const
{
    orRanges.RemoveAll();
    TokenToRangeListState eState = STATE_OPEN;
    sal_Int32 nParenLevel = 0;
    for( ApiTokenIterator aIt( rTokens, OPCODE_SPACES ); aIt.is() && (eState != STATE_ERROR); ++aIt )
    {
        sal_Int32 nOpCode = aIt->OpCode;
        switch( eState )
        {
            // #i107275# accept OPCODE_SEP and OPCODE_LIST as separator token
            case STATE_REF:
                     if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
                else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
                else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
                else                               eState = STATE_ERROR;
            break;
            case STATE_SEP:
                     if( nOpCode == OPCODE_PUSH )  eState = lclProcessRef( orRanges, aIt->Data, nFilterBySheet );
                else if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
                else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
                else if( nOpCode == OPCODE_OPEN )  eState = lclProcessOpen( nParenLevel );
                else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
                else                               eState = STATE_ERROR;
            break;
            case STATE_OPEN:
                     if( nOpCode == OPCODE_PUSH )  eState = lclProcessRef( orRanges, aIt->Data, nFilterBySheet );
                else if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
                else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
                else if( nOpCode == OPCODE_OPEN )  eState = lclProcessOpen( nParenLevel );
                else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
                else                               eState = STATE_ERROR;
            break;
            case STATE_CLOSE:
                     if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
                else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
                else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
                else                               eState = STATE_ERROR;
            break;
            default:;
        }
    }
 
    if( eState == STATE_ERROR )
        orRanges.RemoveAll();
    else
        getAddressConverter().validateCellRangeList( orRanges, false );
}
 
bool FormulaProcessorBase::extractString( OUString& orString, const ApiTokenSequence& rTokens ) const
{
    ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES );
    return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) && (aTokenIt->Data >>= orString) && !(++aTokenIt).is();
}
 
bool FormulaProcessorBase::extractSpecialTokenInfo( ApiSpecialTokenInfo& orTokenInfo, const ApiTokenSequence& rTokens ) const
{
    ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES );
    return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_BAD) && (aTokenIt->Data >>= orTokenInfo);
}
 
void FormulaProcessorBase::convertStringToStringList(
        ApiTokenSequence& orTokens, sal_Unicode cStringSep, bool bTrimLeadingSpaces ) const
{
    OUString aString;
    if( !extractString( aString, orTokens ) || aString.isEmpty() )
        return;
 
    ::std::vector< ApiToken > aNewTokens;
    for( sal_Int32 nPos{ 0 }; nPos>=0; )
    {
        OUString aEntry = aString.getToken( 0, cStringSep, nPos );
        if( bTrimLeadingSpaces )
        {
            sal_Int32 nStart = 0;
            while( (nStart < aEntry.getLength()) && (aEntry[ nStart ] == ' ') ) ++nStart;
            aEntry = aEntry.copy( nStart );
        }
        if( !aNewTokens.empty() )
            aNewTokens.emplace_back( OPCODE_SEP, Any() );
        aNewTokens.emplace_back( OPCODE_PUSH, Any( aEntry ) );
    }
    orTokens = comphelper::containerToSequence( aNewTokens );
}
 
} // namespace oox
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'insert' is required to be utilized.

V530 The return value of function 'insert' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 1579, 1582.

V1037 Two or more case-branches perform the same actions. Check lines: 1655, 1677

V1037 Two or more case-branches perform the same actions. Check lines: 1661, 1669

V1048 The 'eState' variable was assigned the same value.

V1048 The 'eState' variable was assigned the same value.

V1048 The 'eState' variable was assigned the same value.