/* -*- 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 <xlformula.hxx>
 
#include <refdata.hxx>
#include <tokenarray.hxx>
#include <xestream.hxx>
#include <xistream.hxx>
#include <xlroot.hxx>
 
#include <comphelper/string.hxx>
#include <svl/sharedstringpool.hxx>
 
using namespace ::formula;
 
// Function data ==============================================================
 
OUString XclFunctionInfo::GetMacroFuncName() const
{
    if( IsMacroFunc() )
        return OUString( mpcMacroName, strlen(mpcMacroName), RTL_TEXTENCODING_UTF8 );
    return OUString();
}
 
OUString XclFunctionInfo::GetAddInEquivalentFuncName() const
{
    if( IsAddInEquivalent() )
        return OUString( mpcMacroName, strlen(mpcMacroName), RTL_TEXTENCODING_UTF8 );
    return OUString();
}
 
// abbreviations for function return token class
const sal_uInt8 R = EXC_TOKCLASS_REF;
const sal_uInt8 V = EXC_TOKCLASS_VAL;
const sal_uInt8 A = EXC_TOKCLASS_ARR;
 
// abbreviations for parameter infos
#define RO   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_ORG, false }
#define RA   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_ARR, false }
#define RR   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_RPT, false }
#define RX   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_RPX, false }
#define VO   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_ORG, true  }
#define VV   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_VAL, true  }
#define VA   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_ARR, true  }
#define VR   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_RPT, true  }
#define VX   { EXC_PARAM_REGULAR,   EXC_PARAMCONV_RPX, true  }
#define RO_E { EXC_PARAM_EXCELONLY, EXC_PARAMCONV_ORG, false }
#define VR_E { EXC_PARAM_EXCELONLY, EXC_PARAMCONV_RPT, true  }
#define C    { EXC_PARAM_CALCONLY,  EXC_PARAMCONV_ORG, false }
 
const sal_uInt16 NOID = SAL_MAX_UINT16;     /// No BIFF/OOBIN function identifier available.
const sal_uInt8 MX    = 30;                 /// Maximum parameter count.
 
#define EXC_FUNCNAME( ascii )       "_xlfn." ascii
#define EXC_FUNCNAME_ODF( ascii )   "_xlfnodf." ascii
#define EXC_FUNCNAME_ADDIN( ascii )   "com.sun.star.sheet.addin." ascii
 
/** Functions new in BIFF2. */
const XclFunctionInfo saFuncTable_2[] =
{
    { ocCount,              0,      0,  MX, V, { RX }, 0, nullptr },
    { ocIf,                 1,      2,  3,  R, { VO, RO }, 0, nullptr },
    { ocIsNA,               2,      1,  1,  V, { VR }, 0, nullptr },
    { ocIsError,            3,      1,  1,  V, { VR }, 0, nullptr },
    { ocSum,                4,      0,  MX, V, { RX }, 0, nullptr },
    { ocAverage,            5,      1,  MX, V, { RX }, 0, nullptr },
    { ocMin,                6,      1,  MX, V, { RX }, 0, nullptr },
    { ocMax,                7,      1,  MX, V, { RX }, 0, nullptr },
    { ocRow,                8,      0,  1,  V, { RO }, 0, nullptr },
    { ocColumn,             9,      0,  1,  V, { RO }, 0, nullptr },
    { ocNotAvail,           10,     0,  0,  V, {}, 0, nullptr },
    { ocNPV,                11,     2,  MX, V, { VR, RX }, 0, nullptr },
    { ocStDev,              12,     1,  MX, V, { RX }, 0, nullptr },
    { ocCurrency,           13,     1,  2,  V, { VR }, 0, nullptr },
    { ocFixed,              14,     1,  2,  V, { VR, VR, C }, 0, nullptr },
    { ocSin,                15,     1,  1,  V, { VR }, 0, nullptr },
    { ocCosecant,           15,     1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocCos,                16,     1,  1,  V, { VR }, 0, nullptr },
    { ocSecant,             16,     1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocTan,                17,     1,  1,  V, { VR }, 0, nullptr },
    { ocCot,                17,     1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocArcTan,             18,     1,  1,  V, { VR }, 0, nullptr },
    { ocArcCot,             18,     1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocPi,                 19,     0,  0,  V, {}, 0, nullptr },
    { ocSqrt,               20,     1,  1,  V, { VR }, 0, nullptr },
    { ocExp,                21,     1,  1,  V, { VR }, 0, nullptr },
    { ocLn,                 22,     1,  1,  V, { VR }, 0, nullptr },
    { ocLog10,              23,     1,  1,  V, { VR }, 0, nullptr },
    { ocAbs,                24,     1,  1,  V, { VR }, 0, nullptr },
    { ocInt,                25,     1,  1,  V, { VR }, 0, nullptr },
    { ocPlusMinus,          26,     1,  1,  V, { VR }, 0, nullptr },
    { ocRound,              27,     2,  2,  V, { VR }, 0, nullptr },
    { ocLookup,             28,     2,  3,  V, { VR, RA }, 0, nullptr },
    { ocIndex,              29,     2,  4,  R, { RA, VV }, 0, nullptr },
    { ocRept,               30,     2,  2,  V, { VR }, 0, nullptr },
    { ocMid,                31,     3,  3,  V, { VR }, 0, nullptr },
    { ocLen,                32,     1,  1,  V, { VR }, 0, nullptr },
    { ocValue,              33,     1,  1,  V, { VR }, 0, nullptr },
    { ocTrue,               34,     0,  0,  V, {}, 0, nullptr },
    { ocFalse,              35,     0,  0,  V, {}, 0, nullptr },
    { ocAnd,                36,     1,  MX, V, { RX }, 0, nullptr },
    { ocOr,                 37,     1,  MX, V, { RX }, 0, nullptr },
    { ocNot,                38,     1,  1,  V, { VR }, 0, nullptr },
    { ocMod,                39,     2,  2,  V, { VR }, 0, nullptr },
    { ocDBCount,            40,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocDBSum,              41,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocDBAverage,          42,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocDBMin,              43,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocDBMax,              44,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocDBStdDev,           45,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocVar,                46,     1,  MX, V, { RX }, 0, nullptr },
    { ocDBVar,              47,     3,  3,  V, { RO, RR }, 0, nullptr },
    { ocText,               48,     2,  2,  V, { VR }, 0, nullptr },
    { ocLinest,             49,     1,  2,  A, { RA, RA, C, C }, 0, nullptr },
    { ocTrend,              50,     1,  3,  A, { RA, RA, RA, C }, 0, nullptr },
    { ocLogest,             51,     1,  2,  A, { RA, RA, C, C }, 0, nullptr },
    { ocGrowth,             52,     1,  3,  A, { RA, RA, RA, C }, 0, nullptr },
    { ocPV,                 56,     3,  5,  V, { VR }, 0, nullptr },
    { ocFV,                 57,     3,  5,  V, { VR }, 0, nullptr },
    { ocNper,               58,     3,  5,  V, { VR }, 0, nullptr },
    { ocPMT,                59,     3,  5,  V, { VR }, 0, nullptr },
    { ocRate,               60,     3,  6,  V, { VR }, 0, nullptr },
    { ocMIRR,               61,     3,  3,  V, { RA, VR }, 0, nullptr },
    { ocIRR,                62,     1,  2,  V, { RA, VR }, 0, nullptr },
    { ocRandom,             63,     0,  0,  V, {}, EXC_FUNCFLAG_VOLATILE, nullptr },
    { ocMatch,              64,     2,  3,  V, { VR, RX, RR }, 0, nullptr },
    { ocGetDate,            65,     3,  3,  V, { VR }, 0, nullptr },
    { ocGetTime,            66,     3,  3,  V, { VR }, 0, nullptr },
    { ocGetDay,             67,     1,  1,  V, { VR }, 0, nullptr },
    { ocGetMonth,           68,     1,  1,  V, { VR }, 0, nullptr },
    { ocGetYear,            69,     1,  1,  V, { VR }, 0, nullptr },
    { ocGetDayOfWeek,       70,     1,  1,  V, { VR, C }, 0, nullptr },
    { ocGetHour,            71,     1,  1,  V, { VR }, 0, nullptr },
    { ocGetMin,             72,     1,  1,  V, { VR }, 0, nullptr },
    { ocGetSec,             73,     1,  1,  V, { VR }, 0, nullptr },
    { ocGetActTime,         74,     0,  0,  V, {}, EXC_FUNCFLAG_VOLATILE, nullptr },
    { ocAreas,              75,     1,  1,  V, { RO }, 0, nullptr },
    { ocRows,               76,     1,  1,  V, { RO }, 0, nullptr },
    { ocColumns,            77,     1,  1,  V, { RO }, 0, nullptr },
    { ocOffset,             78,     3,  5,  R, { RO, VR }, EXC_FUNCFLAG_VOLATILE, nullptr },
    { ocSearch,             82,     2,  3,  V, { VR }, 0, nullptr },
    { ocMatTrans,           83,     1,  1,  A, { VO }, 0, nullptr },
    { ocType,               86,     1,  1,  V, { VX }, 0, nullptr },
    { ocArcTan2,            97,     2,  2,  V, { VR }, 0, nullptr },
    { ocArcSin,             98,     1,  1,  V, { VR }, 0, nullptr },
    { ocArcCos,             99,     1,  1,  V, { VR }, 0, nullptr },
    { ocChoose,             100,    2,  MX, R, { VO, RO }, 0, nullptr },
    { ocHLookup,            101,    3,  3,  V, { VV, RO, RO, C }, 0, nullptr },
    { ocVLookup,            102,    3,  3,  V, { VV, RO, RO, C }, 0, nullptr },
    { ocIsRef,              105,    1,  1,  V, { RX }, 0, nullptr },
    { ocLog,                109,    1,  2,  V, { VR }, 0, nullptr },
    { ocChar,               111,    1,  1,  V, { VR }, 0, nullptr },
    { ocLower,              112,    1,  1,  V, { VR }, 0, nullptr },
    { ocUpper,              113,    1,  1,  V, { VR }, 0, nullptr },
    { ocProper,             114,    1,  1,  V, { VR }, 0, nullptr },
    { ocLeft,               115,    1,  2,  V, { VR }, 0, nullptr },
    { ocRight,              116,    1,  2,  V, { VR }, 0, nullptr },
    { ocExact,              117,    2,  2,  V, { VR }, 0, nullptr },
    { ocTrim,               118,    1,  1,  V, { VR }, 0, nullptr },
    { ocReplace,            119,    4,  4,  V, { VR }, 0, nullptr },
    { ocSubstitute,         120,    3,  4,  V, { VR }, 0, nullptr },
    { ocCode,               121,    1,  1,  V, { VR }, 0, nullptr },
    { ocFind,               124,    2,  3,  V, { VR }, 0, nullptr },
    { ocCell,               125,    1,  2,  V, { VV, RO }, EXC_FUNCFLAG_VOLATILE, nullptr },
    { ocIsErr,              126,    1,  1,  V, { VR }, 0, nullptr },
    { ocIsString,           127,    1,  1,  V, { VR }, 0, nullptr },
    { ocIsValue,            128,    1,  1,  V, { VR }, 0, nullptr },
    { ocIsEmpty,            129,    1,  1,  V, { VR }, 0, nullptr },
    { ocT,                  130,    1,  1,  V, { RO }, 0, nullptr },
    { ocN,                  131,    1,  1,  V, { RO }, 0, nullptr },
    { ocGetDateValue,       140,    1,  1,  V, { VR }, 0, nullptr },
    { ocGetTimeValue,       141,    1,  1,  V, { VR }, 0, nullptr },
    { ocSLN,                142,    3,  3,  V, { VR }, 0, nullptr },
    { ocSYD,                143,    4,  4,  V, { VR }, 0, nullptr },
    { ocDDB,                144,    4,  5,  V, { VR }, 0, nullptr },
    { ocIndirect,           148,    1,  2,  R, { VR }, EXC_FUNCFLAG_VOLATILE, nullptr },
    { ocClean,              162,    1,  1,  V, { VR }, 0, nullptr },
    { ocMatDet,             163,    1,  1,  V, { VA }, 0, nullptr },
    { ocMatInv,             164,    1,  1,  A, { VA }, 0, nullptr },
    { ocMatMult,            165,    2,  2,  A, { VA }, 0, nullptr },
    { ocIpmt,               167,    4,  6,  V, { VR }, 0, nullptr },
    { ocPpmt,               168,    4,  6,  V, { VR }, 0, nullptr },
    { ocCount2,             169,    0,  MX, V, { RX }, 0, nullptr },
    { ocProduct,            183,    0,  MX, V, { RX }, 0, nullptr },
    { ocFact,               184,    1,  1,  V, { VR }, 0, nullptr },
    { ocDBProduct,          189,    3,  3,  V, { RO, RR }, 0, nullptr },
    { ocIsNonString,        190,    1,  1,  V, { VR }, 0, nullptr },
    { ocStDevP,             193,    1,  MX, V, { RX }, 0, nullptr },
    { ocVarP,               194,    1,  MX, V, { RX }, 0, nullptr },
    { ocDBStdDevP,          195,    3,  3,  V, { RO, RR }, 0, nullptr },
    { ocDBVarP,             196,    3,  3,  V, { RO, RR }, 0, nullptr },
    { ocTrunc,              197,    1,  1,  V, { VR, C }, 0, nullptr },
    { ocIsLogical,          198,    1,  1,  V, { VR }, 0, nullptr },
    { ocDBCount2,           199,    3,  3,  V, { RO, RR }, 0, nullptr },
    { ocCurrency,           204,    1,  2,  V, { VR }, EXC_FUNCFLAG_IMPORTONLY, nullptr },
    { ocFindB,              205,    2,  3,  V, { VR }, 0, nullptr },
    { ocSearchB,            206,    2,  3,  V, { VR }, 0, nullptr },
    { ocReplaceB,           207,    4,  4,  V, { VR }, 0, nullptr },
    { ocLeftB,              208,    1,  2,  V, { VR }, 0, nullptr },
    { ocRightB,             209,    1,  2,  V, { VR }, 0, nullptr },
    { ocMidB,               210,    3,  3,  V, { VR }, 0, nullptr },
    { ocLenB,               211,    1,  1,  V, { VR }, 0, nullptr },
    { ocRoundUp,            212,    2,  2,  V, { VR }, 0, nullptr },
    { ocRoundDown,          213,    2,  2,  V, { VR }, 0, nullptr },
    { ocExternal,           255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_IMPORTONLY, nullptr }
};
 
/** Functions new in BIFF3. */
const XclFunctionInfo saFuncTable_3[] =
{
    { ocLinest,             49,     1,  4,  A, { RA, RA, VV }, 0, nullptr },          // BIFF2: 1-2, BIFF3: 1-4
    { ocTrend,              50,     1,  4,  A, { RA, RA, RA, VV }, 0, nullptr },      // BIFF2: 1-3, BIFF3: 1-4
    { ocLogest,             51,     1,  4,  A, { RA, RA, VV }, 0, nullptr },          // BIFF2: 1-2, BIFF3: 1-4
    { ocGrowth,             52,     1,  4,  A, { RA, RA, RA, VV }, 0, nullptr },      // BIFF2: 1-3, BIFF3: 1-4
    { ocTrunc,              197,    1,  2,  V, { VR }, 0, nullptr },                  // BIFF2: 1,   BIFF3: 1-2
    { ocAddress,            219,    2,  5,  V, { VR }, 0, nullptr },
    { ocGetDiffDate360,     220,    2,  2,  V, { VR, VR, C }, 0, nullptr },
    { ocGetActDate,         221,    0,  0,  V, {}, EXC_FUNCFLAG_VOLATILE, nullptr },
    { ocVBD,                222,    5,  7,  V, { VR }, 0, nullptr },
    { ocMedian,             227,    1,  MX, V, { RX }, 0, nullptr },
    { ocSumProduct,         228,    1,  MX, V, { VA }, 0, nullptr },
    { ocSinHyp,             229,    1,  1,  V, { VR }, 0, nullptr },
    { ocCosecantHyp,        229,    1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocCosHyp,             230,    1,  1,  V, { VR }, 0, nullptr },
    { ocSecantHyp,          230,    1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocTanHyp,             231,    1,  1,  V, { VR }, 0, nullptr },
    { ocCotHyp,             231,    1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocArcSinHyp,          232,    1,  1,  V, { VR }, 0, nullptr },
    { ocArcCosHyp,          233,    1,  1,  V, { VR }, 0, nullptr },
    { ocArcTanHyp,          234,    1,  1,  V, { VR }, 0, nullptr },
    { ocArcCotHyp,          234,    1,  1,  V, { VR }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocDBGet,              235,    3,  3,  V, { RO, RR }, 0, nullptr },
    { ocInfo,               244,    1,  1,  V, { VR }, EXC_FUNCFLAG_VOLATILE, nullptr }
};
 
/** Functions new in BIFF4. */
const XclFunctionInfo saFuncTable_4[] =
{
    { ocFixed,              14,     1,  3,  V, { VR }, 0, nullptr },                  // BIFF2-3: 1-2, BIFF4: 1-3
    { ocAsc,                214,    1,  1,  V, { VR }, 0, nullptr },
    { ocJis,                215,    1,  1,  V, { VR }, 0, nullptr },
    { ocRank,               216,    2,  3,  V, { VR, RO, VR }, 0, nullptr },
    { ocDB,                 247,    4,  5,  V, { VR }, 0, nullptr },
    { ocFrequency,          252,    2,  2,  A, { RA }, 0, nullptr },
    { ocErrorType_ODF,      261,    1,  1,  V, { VR }, 0, nullptr },
    { ocAveDev,             269,    1,  MX, V, { RX }, 0, nullptr },
    { ocBetaDist,           270,    3,  5,  V, { VR }, 0, nullptr },
    { ocGammaLn,            271,    1,  1,  V, { VR }, 0, nullptr },
    { ocBetaInv,            272,    3,  5,  V, { VR }, 0, nullptr },
    { ocBinomDist,          273,    4,  4,  V, { VR }, 0, nullptr },
    { ocChiDist,            274,    2,  2,  V, { VR }, 0, nullptr },
    { ocChiInv,             275,    2,  2,  V, { VR }, 0, nullptr },
    { ocCombin,             276,    2,  2,  V, { VR }, 0, nullptr },
    { ocConfidence,         277,    3,  3,  V, { VR }, 0, nullptr },
    { ocCritBinom,          278,    3,  3,  V, { VR }, 0, nullptr },
    { ocEven,               279,    1,  1,  V, { VR }, 0, nullptr },
    { ocExpDist,            280,    3,  3,  V, { VR }, 0, nullptr },
    { ocFDist,              281,    3,  3,  V, { VR }, 0, nullptr },
    { ocFInv,               282,    3,  3,  V, { VR }, 0, nullptr },
    { ocFisher,             283,    1,  1,  V, { VR }, 0, nullptr },
    { ocFisherInv,          284,    1,  1,  V, { VR }, 0, nullptr },
    { ocFloor_MS,           285,    2,  2,  V, { VR }, 0, nullptr },
    { ocGammaDist,          286,    4,  4,  V, { VR }, 0, nullptr },
    { ocGammaInv,           287,    3,  3,  V, { VR }, 0, nullptr },
    { ocCeil_MS,            288,    2,  2,  V, { VR }, 0, nullptr },
    { ocHypGeomDist,        289,    4,  4,  V, { VR }, 0, nullptr },
    { ocLogNormDist,        290,    3,  3,  V, { VR }, 0, nullptr },
    { ocLogInv,             291,    3,  3,  V, { VR }, 0, nullptr },
    { ocNegBinomVert,       292,    3,  3,  V, { VR }, 0, nullptr },
    { ocNormDist,           293,    4,  4,  V, { VR }, 0, nullptr },
    { ocStdNormDist,        294,    1,  1,  V, { VR }, 0, nullptr },
    { ocNormInv,            295,    3,  3,  V, { VR }, 0, nullptr },
    { ocSNormInv,           296,    1,  1,  V, { VR }, 0, nullptr },
    { ocStandard,           297,    3,  3,  V, { VR }, 0, nullptr },
    { ocOdd,                298,    1,  1,  V, { VR }, 0, nullptr },
    { ocPermut,             299,    2,  2,  V, { VR }, 0, nullptr },
    { ocPoissonDist,        300,    3,  3,  V, { VR }, 0, nullptr },
    { ocTDist,              301,    3,  3,  V, { VR }, 0, nullptr },
    { ocWeibull,            302,    4,  4,  V, { VR }, 0, nullptr },
    { ocSumXMY2,            303,    2,  2,  V, { VA }, 0, nullptr },
    { ocSumX2MY2,           304,    2,  2,  V, { VA }, 0, nullptr },
    { ocSumX2DY2,           305,    2,  2,  V, { VA }, 0, nullptr },
    { ocChiTest,            306,    2,  2,  V, { VA }, 0, nullptr },
    { ocCorrel,             307,    2,  2,  V, { VA }, 0, nullptr },
    { ocCovar,              308,    2,  2,  V, { VA }, 0, nullptr },
    { ocForecast,           309,    3,  3,  V, { VR, VA }, 0, nullptr },
    { ocFTest,              310,    2,  2,  V, { VA }, 0, nullptr },
    { ocIntercept,          311,    2,  2,  V, { VA }, 0, nullptr },
    { ocPearson,            312,    2,  2,  V, { VA }, 0, nullptr },
    { ocRSQ,                313,    2,  2,  V, { VA }, 0, nullptr },
    { ocSTEYX,              314,    2,  2,  V, { VA }, 0, nullptr },
    { ocSlope,              315,    2,  2,  V, { VA }, 0, nullptr },
    { ocTTest,              316,    4,  4,  V, { VA, VA, VR }, 0, nullptr },
    { ocProb,               317,    3,  4,  V, { VA, VA, VR }, 0, nullptr },
    { ocDevSq,              318,    1,  MX, V, { RX }, 0, nullptr },
    { ocGeoMean,            319,    1,  MX, V, { RX }, 0, nullptr },
    { ocHarMean,            320,    1,  MX, V, { RX }, 0, nullptr },
    { ocSumSQ,              321,    0,  MX, V, { RX }, 0, nullptr },
    { ocKurt,               322,    1,  MX, V, { RX }, 0, nullptr },
    { ocSkew,               323,    1,  MX, V, { RX }, 0, nullptr },
    { ocZTest,              324,    2,  3,  V, { RX, VR }, 0, nullptr },
    { ocLarge,              325,    2,  2,  V, { RX, VR }, 0, nullptr },
    { ocSmall,              326,    2,  2,  V, { RX, VR }, 0, nullptr },
    { ocQuartile,           327,    2,  2,  V, { RX, VR }, 0, nullptr },
    { ocPercentile,         328,    2,  2,  V, { RX, VR }, 0, nullptr },
    { ocPercentrank,        329,    2,  3,  V, { RX, VR, VR_E }, 0, nullptr },
    { ocModalValue,         330,    1,  MX, V, { VA }, 0, nullptr },
    { ocTrimMean,           331,    2,  2,  V, { RX, VR }, 0, nullptr },
    { ocTInv,               332,    2,  2,  V, { VR }, 0, nullptr },
    // Functions equivalent to add-in functions, use same parameters as
    // ocExternal but add programmatical function name (here without
    // "com.sun.star.sheet.addin.") so it can be looked up and stored as
    // add-in, as older Excel versions only know them as add-in.
    { ocIsEven,             255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getIseven" ) },
    { ocIsOdd,              255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getIsodd" ) },
    { ocGCD,                255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getGcd" ) },
    { ocLCM,                255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getLcm" ) },
    { ocEffect,             255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getEffect" ) },
    { ocCumPrinc,           255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getCumprinc" ) },
    { ocCumIpmt,            255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getCumipmt" ) },
    { ocNominal,            255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getNominal" ) },
    { ocNetWorkdays,        255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY | EXC_FUNCFLAG_ADDINEQUIV, EXC_FUNCNAME_ADDIN( "Analysis.getNetworkdays" ) }
};
 
/** Functions new in BIFF5/BIFF7. Unsupported functions: DATESTRING, NUMBERSTRING. */
const XclFunctionInfo saFuncTable_5[] =
{
    { ocGetDayOfWeek,       70,     1,  2,  V, { VR }, 0, nullptr },                  // BIFF2-4: 1, BIFF5: 1-2
    { ocHLookup,            101,    3,  4,  V, { VV, RO, RO, VV }, 0, nullptr },      // BIFF2-4: 3, BIFF5: 3-4
    { ocVLookup,            102,    3,  4,  V, { VV, RO, RO, VV }, 0, nullptr },      // BIFF2-4: 3, BIFF5: 3-4
    { ocGetDiffDate360,     220,    2,  3,  V, { VR }, 0, nullptr },                  // BIFF3-4: 2, BIFF5: 2-3
    { ocMacro,              255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocExternal,           255,    1,  MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, nullptr },
    { ocConcat,             336,    0,  MX, V, { VR }, 0, nullptr },
    { ocPower,              337,    2,  2,  V, { VR }, 0, nullptr },
    { ocRad,                342,    1,  1,  V, { VR }, 0, nullptr },
    { ocDeg,                343,    1,  1,  V, { VR }, 0, nullptr },
    { ocSubTotal,           344,    2,  MX, V, { VR, RO }, 0, nullptr },
    { ocSumIf,              345,    2,  3,  V, { RO, VR, RO }, 0, nullptr },
    { ocCountIf,            346,    2,  2,  V, { RO, VR }, 0, nullptr },
    { ocCountEmptyCells,    347,    1,  1,  V, { RO }, 0, nullptr },
    { ocISPMT,              350,    4,  4,  V, { VR }, 0, nullptr },
    { ocGetDateDif,         351,    3,  3,  V, { VR }, 0, nullptr },
    { ocNoName,             352,    1,  1,  V, { VR }, EXC_FUNCFLAG_IMPORTONLY, nullptr },    // DATESTRING
    { ocNoName,             353,    2,  2,  V, { VR }, EXC_FUNCFLAG_IMPORTONLY, nullptr },    // NUMBERSTRING
    { ocRoman,              354,    1,  2,  V, { VR }, 0, nullptr }
};
 
/** Functions new in BIFF8. Unsupported functions: PHONETIC. */
const XclFunctionInfo saFuncTable_8[] =
{
    { ocGetPivotData,       358,    2,  MX, V, { RR, RR, VR }, 0, nullptr },
    { ocHyperLink,          359,    1,  2,  V, { VV, VO }, 0, nullptr },
    { ocNoName,             360,    1,  1,  V, { RO }, EXC_FUNCFLAG_IMPORTONLY, nullptr },    // PHONETIC
    { ocAverageA,           361,    1,  MX, V, { RX }, 0, nullptr },
    { ocMaxA,               362,    1,  MX, V, { RX }, 0, nullptr },
    { ocMinA,               363,    1,  MX, V, { RX }, 0, nullptr },
    { ocStDevPA,            364,    1,  MX, V, { RX }, 0, nullptr },
    { ocVarPA,              365,    1,  MX, V, { RX }, 0, nullptr },
    { ocStDevA,             366,    1,  MX, V, { RX }, 0, nullptr },
    { ocVarA,               367,    1,  MX, V, { RX }, 0, nullptr },
    { ocBahtText,           368,    1,  1,  V, { VR }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "BAHTTEXT" ) },
    { ocBahtText,           255,    2,  2,  V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "BAHTTEXT" ) },
    { ocEuroConvert,        255,    4,  6,  V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, "EUROCONVERT" }
};
 
#define EXC_FUNCENTRY_V_VR( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
/** Functions new in OOXML. */
const XclFunctionInfo saFuncTable_Oox[] =
{
    { ocCountIfs,           NOID,   2,  MX, V, { RO, VR }, EXC_FUNCFLAG_IMPORTONLY|EXC_FUNCFLAG_PARAMPAIRS, EXC_FUNCNAME( "COUNTIFS" ) },
    { ocCountIfs,           255,    3,  MX, V, { RO_E, RO, VR }, EXC_FUNCFLAG_EXPORTONLY|EXC_FUNCFLAG_PARAMPAIRS, EXC_FUNCNAME( "COUNTIFS" ) },
    { ocSumIfs,             NOID,   3,  MX, V, { RO, RO, VR }, EXC_FUNCFLAG_IMPORTONLY|EXC_FUNCFLAG_PARAMPAIRS, EXC_FUNCNAME( "SUMIFS" ) },
    { ocSumIfs,             255,    4,  MX, V, { RO_E, RO, RO, VR }, EXC_FUNCFLAG_EXPORTONLY|EXC_FUNCFLAG_PARAMPAIRS, EXC_FUNCNAME( "SUMIFS" ) },
    { ocAverageIf,          NOID,   2,  3,  V, { RO, VR, RO }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "AVERAGEIF" ) },
    { ocAverageIf,          255,    3,  4,  V, { RO_E, RO, VR, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "AVERAGEIF" ) },
    { ocAverageIfs,         NOID,   3,  MX, V, { RO, RO, VR }, EXC_FUNCFLAG_IMPORTONLY|EXC_FUNCFLAG_PARAMPAIRS, EXC_FUNCNAME( "AVERAGEIFS" ) },
    { ocAverageIfs,         255,    4,  MX, V, { RO_E, RO, RO, VR }, EXC_FUNCFLAG_EXPORTONLY|EXC_FUNCFLAG_PARAMPAIRS, EXC_FUNCNAME( "AVERAGEIFS" ) },
    { ocIfError,            NOID,   2,  2,  V, { VO, RO }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "IFERROR" ) },
    { ocIfError,            255,    3,  3,  V, { RO_E, VO, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "IFERROR" ) },
    { ocNetWorkdays_MS,     NOID,   2,  4,  V, { VR, VR, RO, RO }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "NETWORKDAYS.INTL" ) },
    { ocNetWorkdays_MS,     255,    3,  5,  V, { RO_E, VR, VR, RO, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "NETWORKDAYS.INTL" ) },
    { ocWorkday_MS,         NOID,   2,  4,  V, { VR, VR, VR, RO }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "WORKDAY.INTL" ) },
    { ocWorkday_MS,         255,    3,  5,  V, { RO_E, VR, VR, VR, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "WORKDAY.INTL" ) },
    EXC_FUNCENTRY_V_VR( ocCeil_ISO,         1,  2,  0,  "ISO.CEILING" )
};
 
#define EXC_FUNCENTRY_V_VR_IMPORT( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
#define EXC_FUNCENTRY_V_RO_EXPORT( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
#define EXC_FUNCENTRY_A_VR( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     A, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
    { opcode,  255, (minparam)+1, (maxparam)+1, A, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
#define EXC_FUNCENTRY_V_RO( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { RO },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
// implicit maxparam=MX
#define EXC_FUNCENTRY_V_RX( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     MX,           V, { RX },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
    { opcode,  255, (minparam)+1, MX,           V, { RO_E, RX }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
#define EXC_FUNCENTRY_V_VA( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { VA },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
/** Functions new in Excel 2010.
 
    See http://office.microsoft.com/en-us/excel-help/what-s-new-changes-made-to-excel-functions-HA010355760.aspx
    A lot of statistical functions have been renamed (the 'old' function names still exist).
 
    @See sc/source/filter/oox/formulabase.cxx saFuncTable2010 for V,VR,RO,...
 */
const XclFunctionInfo saFuncTable_2010[] =
{
    EXC_FUNCENTRY_V_VA( ocCovarianceP,      2,  2,  0,  "COVARIANCE.P" ),
    EXC_FUNCENTRY_V_VA( ocCovarianceS,      2,  2,  0,  "COVARIANCE.S" ),
    EXC_FUNCENTRY_V_RX( ocStDevP_MS,        1, MX,  0,  "STDEV.P" ),
    EXC_FUNCENTRY_V_RX( ocStDevS,           1, MX,  0,  "STDEV.S" ),
    EXC_FUNCENTRY_V_RX( ocVarP_MS,          1, MX,  0,  "VAR.P" ),
    EXC_FUNCENTRY_V_RX( ocVarS,             1, MX,  0,  "VAR.S" ),
    EXC_FUNCENTRY_V_VR( ocBetaDist_MS,      4,  6,  0,  "BETA.DIST" ),
    EXC_FUNCENTRY_V_VR( ocBetaInv_MS,       3,  5,  0,  "BETA.INV" ),
    EXC_FUNCENTRY_V_VR( ocBinomDist_MS,     4,  4,  0,  "BINOM.DIST" ),
    EXC_FUNCENTRY_V_VR( ocBinomInv,         3,  3,  0,  "BINOM.INV" ),
    EXC_FUNCENTRY_V_VR( ocChiSqDist_MS,     3,  3,  0,  "CHISQ.DIST" ),
    EXC_FUNCENTRY_V_VR( ocChiSqInv_MS,      2,  2,  0,  "CHISQ.INV" ),
    EXC_FUNCENTRY_V_VR( ocChiDist_MS,       2,  2,  0,  "CHISQ.DIST.RT" ),
    EXC_FUNCENTRY_V_VR( ocChiInv_MS,        2,  2,  0,  "CHISQ.INV.RT" ),
    EXC_FUNCENTRY_V_VR( ocChiTest_MS,       2,  2,  0,  "CHISQ.TEST" ),
    EXC_FUNCENTRY_V_VR( ocConfidence_N,     3,  3,  0,  "CONFIDENCE.NORM" ),
    EXC_FUNCENTRY_V_VR( ocConfidence_T,     3,  3,  0,  "CONFIDENCE.T" ),
    EXC_FUNCENTRY_V_VR( ocFDist_LT,         4,  4,  0,  "F.DIST" ),
    EXC_FUNCENTRY_V_VR( ocFDist_RT,         3,  3,  0,  "F.DIST.RT" ),
    EXC_FUNCENTRY_V_VR( ocFInv_LT,          3,  3,  0,  "F.INV" ),
    EXC_FUNCENTRY_V_VR( ocFInv_RT,          3,  3,  0,  "F.INV.RT" ),
    EXC_FUNCENTRY_V_VR( ocFTest_MS,         2,  2,  0,  "F.TEST" ),
    EXC_FUNCENTRY_V_VR( ocExpDist_MS,       3,  3,  0,  "EXPON.DIST" ),
    EXC_FUNCENTRY_V_VR( ocHypGeomDist_MS,   5,  5,  0,  "HYPGEOM.DIST" ),
    EXC_FUNCENTRY_V_VR( ocPoissonDist_MS,   3,  3,  0,  "POISSON.DIST" ),
    EXC_FUNCENTRY_V_VR( ocWeibull_MS,       4,  4,  0,  "WEIBULL.DIST" ),
    EXC_FUNCENTRY_V_VR( ocGammaDist_MS,     4,  4,  0,  "GAMMA.DIST" ),
    EXC_FUNCENTRY_V_VR( ocGammaInv_MS,      3,  3,  0,  "GAMMA.INV" ),
    EXC_FUNCENTRY_V_VR( ocGammaLn_MS,       1,  1,  0,  "GAMMALN.PRECISE" ),
    EXC_FUNCENTRY_V_VR( ocLogNormDist_MS,   4,  4,  0,  "LOGNORM.DIST" ),
    EXC_FUNCENTRY_V_VR( ocLogInv_MS,        3,  3,  0,  "LOGNORM.INV" ),
    EXC_FUNCENTRY_V_VR( ocNormDist_MS,      4,  4,  0,  "NORM.DIST" ),
    EXC_FUNCENTRY_V_VR( ocNormInv_MS,       3,  3,  0,  "NORM.INV" ),
    EXC_FUNCENTRY_V_VR( ocStdNormDist_MS,   2,  2,  0,  "NORM.S.DIST" ),
    EXC_FUNCENTRY_V_VR( ocSNormInv_MS,      1,  1,  0,  "NORM.S.INV" ),
    EXC_FUNCENTRY_V_VR( ocTDist_2T,         2,  2,  0,  "T.DIST.2T" ),
    EXC_FUNCENTRY_V_VR( ocTDist_MS,         3,  3,  0,  "T.DIST" ),
    EXC_FUNCENTRY_V_VR( ocTDist_RT,         2,  2,  0,  "T.DIST.RT" ),
    EXC_FUNCENTRY_V_VR( ocTInv_2T,          2,  2,  0,  "T.INV.2T" ),
    EXC_FUNCENTRY_V_VR( ocTInv_MS,          2,  2,  0,  "T.INV" ),
    EXC_FUNCENTRY_V_VR( ocTTest_MS,         4,  4,  0,  "T.TEST" ),
    EXC_FUNCENTRY_V_VR( ocPercentile_Inc,   2,  2,  0,  "PERCENTILE.INC" ),
    EXC_FUNCENTRY_V_VR( ocPercentrank_Inc,  2,  3,  0,  "PERCENTRANK.INC" ),
    EXC_FUNCENTRY_V_VR( ocQuartile_Inc,     2,  2,  0,  "QUARTILE.INC" ),
    EXC_FUNCENTRY_V_VR( ocRank_Eq,          2,  3,  0,  "RANK.EQ" ),
    EXC_FUNCENTRY_V_VR( ocPercentile_Exc,   2,  2,  0,  "PERCENTILE.EXC" ),
    EXC_FUNCENTRY_V_VR( ocPercentrank_Exc,  2,  3,  0,  "PERCENTRANK.EXC" ),
    EXC_FUNCENTRY_V_VR( ocQuartile_Exc,     2,  2,  0,  "QUARTILE.EXC" ),
    EXC_FUNCENTRY_V_VR( ocRank_Avg,         2,  3,  0,  "RANK.AVG" ),
    EXC_FUNCENTRY_V_RX( ocModalValue_MS,    1, MX,  0,  "MODE.SNGL" ),
    EXC_FUNCENTRY_V_RX( ocModalValue_Multi, 1, MX,  0,  "MODE.MULT" ),
    EXC_FUNCENTRY_V_VR( ocNegBinomDist_MS,  4,  4,  0,  "NEGBINOM.DIST" ),
    EXC_FUNCENTRY_V_VR( ocZTest_MS,         2,  3,  0,  "Z.TEST" ),
    EXC_FUNCENTRY_V_VR( ocCeil_Precise,     1,  2,  0,  "CEILING.PRECISE" ),
    EXC_FUNCENTRY_V_VR( ocFloor_Precise,    1,  2,  0,  "FLOOR.PRECISE" ),
    EXC_FUNCENTRY_V_VR( ocErf_MS,           1,  1,  0,  "ERF.PRECISE" ),
    EXC_FUNCENTRY_V_VR( ocErfc_MS,          1,  1,  0,  "ERFC.PRECISE" ),
    EXC_FUNCENTRY_V_RX( ocAggregate,        3, MX,  0,  "AGGREGATE" ),
};
 
/** 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 EXC_FUNCENTRY_V_VR_IMPORT are rewritten in
    sc/source/filter/excel/xeformula.cxx during export for BIFF, OOXML export
    uses a different mapping but still uses this mapping here to determine the
    feature set.
 
    FIXME: either have the exporter determine the feature set from the active
    mapping, preferred, or enhance this mapping here such that for OOXML the
    rewrite can be overridden.
 
    @See sc/source/filter/oox/formulabase.cxx saFuncTable2013 for V,VR,RO,...
 */
const XclFunctionInfo saFuncTable_2013[] =
{
    EXC_FUNCENTRY_V_VR_IMPORT(  ocArcCot,        1,  1,  0,  "ACOT" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocArcCotHyp,     1,  1,  0,  "ACOTH" ),
    EXC_FUNCENTRY_V_VR(         ocArabic,        1,  1,  0,  "ARABIC" ),
    EXC_FUNCENTRY_V_VR(         ocBase,          2,  3,  0,  "BASE" ),
    EXC_FUNCENTRY_V_VR(         ocB,             3,  4,  0,  "BINOM.DIST.RANGE" ),
    EXC_FUNCENTRY_V_VR(         ocBitAnd,        2,  2,  0,  "BITAND" ),
    EXC_FUNCENTRY_V_VR(         ocBitLshift,     2,  2,  0,  "BITLSHIFT" ),
    EXC_FUNCENTRY_V_VR(         ocBitOr,         2,  2,  0,  "BITOR" ),
    EXC_FUNCENTRY_V_VR(         ocBitRshift,     2,  2,  0,  "BITRSHIFT" ),
    EXC_FUNCENTRY_V_VR(         ocBitXor,        2,  2,  0,  "BITXOR" ),
    EXC_FUNCENTRY_V_VR(         ocCeil_Math,     1,  3,  0,  "CEILING.MATH" ),
    EXC_FUNCENTRY_V_RO_EXPORT(  ocCeil,          1,  3,  0,  "CEILING.MATH" ),
    EXC_FUNCENTRY_V_VR(         ocCombinA,       2,  2,  0,  "COMBINA" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocCot,           1,  1,  0,  "COT" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocCotHyp,        1,  1,  0,  "COTH" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocCosecant,      1,  1,  0,  "CSC" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocCosecantHyp,   1,  1,  0,  "CSCH" ),
    EXC_FUNCENTRY_V_VR(         ocGetDiffDate,   2,  2,  0,  "DAYS" ),
    EXC_FUNCENTRY_V_VR(         ocDecimal,       2,  2,  0,  "DECIMAL" ),
    EXC_FUNCENTRY_V_VR(         ocEncodeURL,     1,  1,  0,  "ENCODEURL" ),
    // NOTE: this FDIST is not our LEGACY.FDIST
    EXC_FUNCENTRY_V_VR(         ocNoName,        3,  4,  0,  "FDIST" ),
    // NOTE: this FINV is not our LEGACY.FINV
    EXC_FUNCENTRY_V_VR(         ocNoName,        3,  3,  0,  "FINV" ),
    EXC_FUNCENTRY_V_VR(         ocFilterXML,     2,  2,  0,  "FILTERXML" ),
    EXC_FUNCENTRY_V_VR(         ocFloor_Math,    1,  3,  0,  "FLOOR.MATH" ),
    EXC_FUNCENTRY_V_RO_EXPORT(  ocFloor,         1,  3,  0,  "FLOOR.MATH" ),
    EXC_FUNCENTRY_V_RO(         ocFormula,       1,  1,  0,  "FORMULATEXT" ),
    EXC_FUNCENTRY_V_VR(         ocGamma,         1,  1,  0,  "GAMMA" ),
    EXC_FUNCENTRY_V_VR(         ocGauss,         1,  1,  0,  "GAUSS" ),
    {                           ocIfNA,       NOID,  2,  2,  V, { VO, RO }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "IFNA" ) },
    {                           ocIfNA,        255,  3,  3,  V, { RO_E, VO, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "IFNA" ) },
    // IMCOSH, IMCOT, IMCSC, IMCSCH, IMSEC, IMSECH, IMSINH and IMTAN are
    // implemented in the Analysis Add-In.
    EXC_FUNCENTRY_V_RO(         ocIsFormula,     1,  1,  0,  "ISFORMULA" ),
    EXC_FUNCENTRY_V_VR(         ocWeek,          1,  2,  0,  "WEEKNUM" ),
    EXC_FUNCENTRY_V_VR(         ocIsoWeeknum,    1,  1,  0,  "ISOWEEKNUM" ),
    EXC_FUNCENTRY_A_VR(         ocMatrixUnit,    1,  1,  0,  "MUNIT" ),
    EXC_FUNCENTRY_V_VR(         ocNumberValue,   1,  3,  0,  "NUMBERVALUE" ),
    EXC_FUNCENTRY_V_VR(         ocPDuration,     3,  3,  0,  "PDURATION" ),
    EXC_FUNCENTRY_V_VR(         ocPermutationA,  2,  2,  0,  "PERMUTATIONA" ),
    EXC_FUNCENTRY_V_VR(         ocPhi,           1,  1,  0,  "PHI" ),
    EXC_FUNCENTRY_V_VR(         ocRRI,           3,  3,  0,  "RRI" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocSecant,        1,  1,  0,  "SEC" ),
    EXC_FUNCENTRY_V_VR_IMPORT(  ocSecantHyp,     1,  1,  0,  "SECH" ),
    EXC_FUNCENTRY_V_RO(         ocSheet,         0,  1,  0,  "SHEET" ),
    EXC_FUNCENTRY_V_RO(         ocSheets,        0,  1,  0,  "SHEETS" ),
    EXC_FUNCENTRY_V_RX(         ocSkewp,         1,  MX, 0,  "SKEW.P" ),
    EXC_FUNCENTRY_V_VR(         ocUnichar,       1,  1,  0,  "UNICHAR" ),
    EXC_FUNCENTRY_V_VR(         ocUnicode,       1,  1,  0,  "UNICODE" ),
    EXC_FUNCENTRY_V_VR(         ocWebservice,    1,  1,  0,  "WEBSERVICE" ),
    EXC_FUNCENTRY_V_RX(         ocXor,           1,  MX, 0,  "XOR" ),
    EXC_FUNCENTRY_V_VR(         ocErrorType_ODF, 1,  1,  0,  "ERROR.TYPE" )
};
 
/** 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/oox/formulabase.cxx saFuncTable2016 for V,VR,RO,...
 */
const XclFunctionInfo saFuncTable_2016[] =
{
    EXC_FUNCENTRY_V_VR(  ocForecast_ETS_ADD,    3,  6,  0,  "FORECAST.ETS" ),
    EXC_FUNCENTRY_V_VR(  ocForecast_ETS_PIA,    3,  7,  0,  "FORECAST.ETS.CONFINT" ),
    EXC_FUNCENTRY_V_VR(  ocForecast_ETS_SEA,    2,  4,  0,  "FORECAST.ETS.SEASONALITY" ),
    EXC_FUNCENTRY_V_VR(  ocForecast_ETS_STA,    3,  6,  0,  "FORECAST.ETS.STAT" ),
    EXC_FUNCENTRY_V_VR(  ocForecast_LIN,        3,  3,  0,  "FORECAST.LINEAR" ),
    EXC_FUNCENTRY_V_VR(  ocConcat_MS,           1,  MX, 0,  "CONCAT" ),
    EXC_FUNCENTRY_V_VR(  ocTextJoin_MS,         3,  MX, 0,  "TEXTJOIN" ),
    EXC_FUNCENTRY_V_VR(  ocIfs_MS,              2,  MX, 0,  "IFS" ),
    EXC_FUNCENTRY_V_VR(  ocSwitch_MS,           3,  MX, 0,  "SWITCH" ),
    EXC_FUNCENTRY_V_VR(  ocMinIfs_MS,           3,  MX, 0,  "MINIFS" ),
    EXC_FUNCENTRY_V_VR(  ocMaxIfs_MS,           3,  MX, 0,  "MAXIFS" )
};
 
 
/** Functions new in Excel 2021.
 
 
    @See sc/source/filter/oox/formulabase.cxx saFuncTable2021 for V,VR,RO,...
 */
const XclFunctionInfo saFuncTable_2021[] =
{
    EXC_FUNCENTRY_V_VR(  ocXLookup,    3,  6,  0,  "XLOOKUP" ),
    EXC_FUNCENTRY_V_VR(  ocXMatch,     2,  4,  0,  "XMATCH" ),
    EXC_FUNCENTRY_V_VR(  ocFilter,     2,  3,  0,  "FILTER" ),
    EXC_FUNCENTRY_V_VR(  ocSort,       1,  4,  0,  "SORT" ),
    EXC_FUNCENTRY_V_VR(  ocSortBy,     2,  3,  0,  "SORTBY" ),
    EXC_FUNCENTRY_V_VR(  ocMatSequence,1,  4,  0,  "SEQUENCE" ),
    EXC_FUNCENTRY_V_VR(  ocRandArray,  0,  5,  0,  "RANDARRAY" ),
    EXC_FUNCENTRY_V_VR(  ocUnique,     1,  3,  0,  "UNIQUE" ),
    EXC_FUNCENTRY_V_VR(  ocLet,        3,  3,  0,  "SORTBY")
};
 
 
#define EXC_FUNCENTRY_ODF( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME_ODF( asciiname ) }, \
    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME_ODF( asciiname ) }
 
/** Functions defined by OpenFormula, but not supported by Calc (ocNoName) or by Excel (defined op-code). */
const XclFunctionInfo saFuncTable_Odf[] =
{
    EXC_FUNCENTRY_ODF( ocChiSqDist,     2,  3,  0,  "CHISQDIST" ),
    EXC_FUNCENTRY_ODF( ocChiSqInv,      2,  2,  0,  "CHISQINV" )
};
 
#undef EXC_FUNCENTRY_ODF
 
#define EXC_FUNCENTRY_OOO( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
// Import Broken Raw ... even without leading _xlfn.
#define EXC_FUNCENTRY_OOO_IBR( opcode, minparam, maxparam, flags, asciiname ) \
    { opcode, NOID, minparam,     maxparam,     V, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), asciiname }
 
/** Functions defined by Calc, but not in OpenFormula nor supported by Excel. */
const XclFunctionInfo saFuncTable_OOoLO[] =
{
    EXC_FUNCENTRY_OOO( ocErrorType,     1,  1,  0,  "ORG.OPENOFFICE.ERRORTYPE" ),
    EXC_FUNCENTRY_OOO_IBR( ocErrorType, 1,  1,  0,  "ERRORTYPE" ),      // was written wrongly, read it
    EXC_FUNCENTRY_OOO( ocMultiArea,     1, MX,  0,  "ORG.OPENOFFICE.MULTIRANGE" ),
    EXC_FUNCENTRY_OOO_IBR( ocMultiArea, 1, MX,  0,  "MULTIRANGE" ),     // was written wrongly, read it
    EXC_FUNCENTRY_OOO( ocBackSolver,    3,  3,  0,  "ORG.OPENOFFICE.GOALSEEK" ),
    EXC_FUNCENTRY_OOO_IBR( ocBackSolver,3,  3,  0,  "GOALSEEK" ),       // was written wrongly, read it
    EXC_FUNCENTRY_OOO( ocEasterSunday,  1,  1,  0,  "ORG.OPENOFFICE.EASTERSUNDAY" ),
    EXC_FUNCENTRY_OOO_IBR( ocEasterSunday,1,1,  0,  "EASTERSUNDAY" ),   // was written wrongly, read it
    EXC_FUNCENTRY_OOO( ocCurrent,       0,  0,  0,  "ORG.OPENOFFICE.CURRENT" ),
    EXC_FUNCENTRY_OOO_IBR( ocCurrent,   0,  0,  0,  "CURRENT" ),        // was written wrongly, read it
    EXC_FUNCENTRY_OOO( ocStyle,         1,  3,  0,  "ORG.OPENOFFICE.STYLE" ),
    EXC_FUNCENTRY_OOO_IBR( ocStyle,     1,  3,  0,  "STYLE" ),          // was written wrongly, read it
    EXC_FUNCENTRY_OOO( ocConvertOOo,    3,  3,  0,  "ORG.OPENOFFICE.CONVERT" ),
    EXC_FUNCENTRY_OOO( ocColor,         3,  4,  0,  "ORG.LIBREOFFICE.COLOR" ),
    EXC_FUNCENTRY_OOO( ocRawSubtract,   2, MX,  0,  "ORG.LIBREOFFICE.RAWSUBTRACT" ),
    EXC_FUNCENTRY_OOO( ocWeeknumOOo,    2,  2,  0,  "ORG.LIBREOFFICE.WEEKNUM_OOO" ),
    EXC_FUNCENTRY_OOO( ocForecast_ETS_MUL, 3,  6,  0,  "ORG.LIBREOFFICE.FORECAST.ETS.MULT" ),
    EXC_FUNCENTRY_OOO( ocForecast_ETS_PIM, 3,  7,  0,  "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT" ),
    EXC_FUNCENTRY_OOO( ocForecast_ETS_STM, 3,  6,  0,  "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT" ),
    EXC_FUNCENTRY_OOO( ocRoundSig,      2,  2,  0,  "ORG.LIBREOFFICE.ROUNDSIG" ),
    EXC_FUNCENTRY_OOO( ocRegex,         2,  4,  0,  "ORG.LIBREOFFICE.REGEX" ),
    EXC_FUNCENTRY_OOO( ocFourier,       2,  5,  0,  "ORG.LIBREOFFICE.FOURIER" ),
    EXC_FUNCENTRY_OOO( ocRandomNV,      0,  0,  0,  "ORG.LIBREOFFICE.RAND.NV" ),
    EXC_FUNCENTRY_OOO( ocRandbetweenNV, 2,  2,  0,  "ORG.LIBREOFFICE.RANDBETWEEN.NV" )
};
 
#undef EXC_FUNCENTRY_OOO_IBR
#undef EXC_FUNCENTRY_OOO
 
XclFunctionProvider::XclFunctionProvider( const XclRoot& rRoot )
{
    void (XclFunctionProvider::*pFillFunc)( const XclFunctionInfo*, const XclFunctionInfo* ) =
        rRoot.IsImport() ? &XclFunctionProvider::FillXclFuncMap : &XclFunctionProvider::FillScFuncMap;
 
    /*  Only read/write functions supported in the current BIFF version.
        Function tables from later BIFF versions may overwrite single functions
        from earlier tables. */
    XclBiff eBiff = rRoot.GetBiff();
    if( eBiff >= EXC_BIFF2 )
        (this->*pFillFunc)(saFuncTable_2, std::end(saFuncTable_2));
    if( eBiff >= EXC_BIFF3 )
        (this->*pFillFunc)(saFuncTable_3, std::end(saFuncTable_3));
    if( eBiff >= EXC_BIFF4 )
        (this->*pFillFunc)(saFuncTable_4, std::end(saFuncTable_4));
    if( eBiff >= EXC_BIFF5 )
        (this->*pFillFunc)(saFuncTable_5, std::end(saFuncTable_5));
    if( eBiff >= EXC_BIFF8 )
        (this->*pFillFunc)(saFuncTable_8, std::end(saFuncTable_8));
    (this->*pFillFunc)(saFuncTable_Oox, std::end(saFuncTable_Oox));
    (this->*pFillFunc)(saFuncTable_2010, std::end(saFuncTable_2010));
    (this->*pFillFunc)(saFuncTable_2013, std::end(saFuncTable_2013));
    (this->*pFillFunc)(saFuncTable_2016, std::end(saFuncTable_2016));
    (this->*pFillFunc)(saFuncTable_2021, std::end(saFuncTable_2021));
    (this->*pFillFunc)(saFuncTable_Odf, std::end(saFuncTable_Odf));
    (this->*pFillFunc)(saFuncTable_OOoLO, std::end(saFuncTable_OOoLO));
}
 
const XclFunctionInfo* XclFunctionProvider::GetFuncInfoFromXclFunc( sal_uInt16 nXclFunc ) const
{
    // only in import filter allowed
    OSL_ENSURE( !maXclFuncMap.empty(), "XclFunctionProvider::GetFuncInfoFromXclFunc - wrong filter" );
    XclFuncMap::const_iterator aIt = maXclFuncMap.find( nXclFunc );
    return (aIt == maXclFuncMap.end()) ? nullptr : aIt->second;
}
 
const XclFunctionInfo* XclFunctionProvider::GetFuncInfoFromXclMacroName( const OUString& rXclMacroName ) const
{
    // only in import filter allowed, but do not test maXclMacroNameMap, it may be empty for old BIFF versions
    OSL_ENSURE( !maXclFuncMap.empty(), "XclFunctionProvider::GetFuncInfoFromXclMacroName - wrong filter" );
    XclMacroNameMap::const_iterator aIt = maXclMacroNameMap.find( rXclMacroName );
    return (aIt == maXclMacroNameMap.end()) ? nullptr : aIt->second;
}
 
const XclFunctionInfo* XclFunctionProvider::GetFuncInfoFromOpCode( OpCode eOpCode ) const
{
    // only in export filter allowed
    OSL_ENSURE( !maScFuncMap.empty(), "XclFunctionProvider::GetFuncInfoFromOpCode - wrong filter" );
    ScFuncMap::const_iterator aIt = maScFuncMap.find( eOpCode );
    return (aIt == maScFuncMap.end()) ? nullptr : aIt->second;
}
 
void XclFunctionProvider::FillXclFuncMap( const XclFunctionInfo* pBeg, const XclFunctionInfo* pEnd )
{
    for( const XclFunctionInfo* pIt = pBeg; pIt != pEnd; ++pIt )
    {
        if( !::get_flag( pIt->mnFlags, EXC_FUNCFLAG_EXPORTONLY ) )
        {
            if( pIt->mnXclFunc != NOID )
                maXclFuncMap[ pIt->mnXclFunc ] = pIt;
            if( pIt->IsMacroFunc() )
                maXclMacroNameMap[ pIt->GetMacroFuncName() ] = pIt;
        }
    }
}
 
void XclFunctionProvider::FillScFuncMap( const XclFunctionInfo* pBeg, const XclFunctionInfo* pEnd )
{
    for( const XclFunctionInfo* pIt = pBeg; pIt != pEnd; ++pIt )
        if( !::get_flag( pIt->mnFlags, EXC_FUNCFLAG_IMPORTONLY ) )
            maScFuncMap[ pIt->meOpCode ] = pIt;
}
 
// Token array ================================================================
 
XclTokenArray::XclTokenArray( bool bVolatile ) :
    mbVolatile( bVolatile )
{
}
 
XclTokenArray::XclTokenArray( ScfUInt8Vec& rTokVec, ScfUInt8Vec& rExtDataVec, bool bVolatile ) :
    mbVolatile( bVolatile )
{
    maTokVec.swap( rTokVec );
    maExtDataVec.swap( rExtDataVec );
}
 
sal_uInt16 XclTokenArray::GetSize() const
{
    OSL_ENSURE( maTokVec.size() <= 0xFFFF, "XclTokenArray::GetSize - array too long" );
    return limit_cast< sal_uInt16 >( maTokVec.size() );
}
 
sal_uInt16 XclTokenArray::ReadSize(XclImpStream& rStrm)
{
    return rStrm.ReaduInt16();
}
 
void XclTokenArray::ReadArray(sal_uInt16 nSize, XclImpStream& rStrm)
{
    maTokVec.resize(0);
 
    const std::size_t nMaxBuffer = 4096;
    std::size_t nBytesLeft = nSize;
    std::size_t nTotalRead = 0;
 
    while (true)
    {
        if (!nBytesLeft)
            break;
        std::size_t nReadRequest = o3tl::sanitizing_min(nBytesLeft, nMaxBuffer);
        maTokVec.resize(maTokVec.size() + nReadRequest);
        auto nRead = rStrm.Read(maTokVec.data() + nTotalRead, nReadRequest);
        nTotalRead += nRead;
        if (nRead != nReadRequest)
        {
            maTokVec.resize(nTotalRead);
            break;
        }
        nBytesLeft -= nRead;
    }
}
 
void XclTokenArray::Read( XclImpStream& rStrm )
{
    ReadArray(ReadSize(rStrm), rStrm);
}
 
void XclTokenArray::WriteSize( XclExpStream& rStrm ) const
{
    rStrm << GetSize();
}
 
void XclTokenArray::WriteArray( XclExpStream& rStrm ) const
{
    if( !maTokVec.empty() )
        rStrm.Write(maTokVec.data(), GetSize());
    if( !maExtDataVec.empty() )
        rStrm.Write(maExtDataVec.data(), maExtDataVec.size());
}
 
void XclTokenArray::Write( XclExpStream& rStrm ) const
{
    WriteSize( rStrm );
    WriteArray( rStrm );
}
 
bool XclTokenArray::operator==( const XclTokenArray& rTokArr ) const
{
    return (mbVolatile == rTokArr.mbVolatile) && (maTokVec == rTokArr.maTokVec) && (maExtDataVec == rTokArr.maExtDataVec);
}
 
XclImpStream& operator>>( XclImpStream& rStrm, XclTokenArray& rTokArr )
{
    rTokArr.Read( rStrm );
    return rStrm;
}
 
XclExpStream& operator<<( XclExpStream& rStrm, const XclTokenArray& rTokArr )
{
    rTokArr.Write( rStrm );
    return rStrm;
}
 
XclExpStream& operator<<( XclExpStream& rStrm, const XclTokenArrayRef& rxTokArr )
{
    if( rxTokArr )
        rxTokArr->Write( rStrm );
    else
        rStrm << sal_uInt16( 0 );
    return rStrm;
}
 
XclTokenArrayIterator::XclTokenArrayIterator() :
    mppScTokenBeg( nullptr ),
    mppScTokenEnd( nullptr ),
    mppScToken( nullptr ),
    mbSkipSpaces( false )
{
}
 
XclTokenArrayIterator::XclTokenArrayIterator( const ScTokenArray& rScTokArr, bool bSkipSpaces )
{
    Init( rScTokArr, bSkipSpaces );
}
 
XclTokenArrayIterator::XclTokenArrayIterator( const XclTokenArrayIterator& rTokArrIt, bool bSkipSpaces ) :
    mppScTokenBeg( rTokArrIt.mppScTokenBeg ),
    mppScTokenEnd( rTokArrIt.mppScTokenEnd ),
    mppScToken( rTokArrIt.mppScToken ),
    mbSkipSpaces( bSkipSpaces )
{
    SkipSpaces();
}
 
void XclTokenArrayIterator::Init( const ScTokenArray& rScTokArr, bool bSkipSpaces )
{
    sal_uInt16 nTokArrLen = rScTokArr.GetLen();
    mppScTokenBeg = static_cast< const FormulaToken* const* >( nTokArrLen ? rScTokArr.GetArray() : nullptr );
    mppScTokenEnd = mppScTokenBeg ? (mppScTokenBeg + nTokArrLen) : nullptr;
    mppScToken = (mppScTokenBeg != mppScTokenEnd) ? mppScTokenBeg : nullptr;
    mbSkipSpaces = bSkipSpaces;
    SkipSpaces();
}
 
XclTokenArrayIterator& XclTokenArrayIterator::operator++()
{
    NextRawToken();
    SkipSpaces();
    return *this;
}
 
void XclTokenArrayIterator::NextRawToken()
{
    if( mppScToken )
        if( (++mppScToken == mppScTokenEnd) || !*mppScToken )
            mppScToken = nullptr;
}
 
void XclTokenArrayIterator::SkipSpaces()
{
    if( mbSkipSpaces )
    {
        OpCode eOp;
        while( Is() && (((eOp = (*this)->GetOpCode()) == ocSpaces) || eOp == ocWhitespace) )
            NextRawToken();
    }
}
 
// strings and string lists ---------------------------------------------------
 
bool XclTokenArrayHelper::GetTokenString( OUString& rString, const FormulaToken& rScToken )
{
    bool bIsStr = (rScToken.GetType() == svString) && (rScToken.GetOpCode() == ocPush);
    if( bIsStr ) rString = rScToken.GetString().getString();
    return bIsStr;
}
 
bool XclTokenArrayHelper::GetString( OUString& rString, const ScTokenArray& rScTokArr )
{
    XclTokenArrayIterator aIt( rScTokArr, true );
    // something is following the string token -> error
    return aIt.Is() && GetTokenString( rString, *aIt ) && !++aIt;
}
 
bool XclTokenArrayHelper::GetStringList( OUString& rStringList, const ScTokenArray& rScTokArr, sal_Unicode cSep )
{
    bool bRet = true;
    XclTokenArrayIterator aIt( rScTokArr, true );
    enum { STATE_START, STATE_STR, STATE_SEP, STATE_END } eState = STATE_START;
    while( eState != STATE_END ) switch( eState )
    {
        case STATE_START:
            eState = aIt.Is() ? STATE_STR : STATE_END;
        break;
        case STATE_STR:
        {
            OUString aString;
            bRet = GetTokenString( aString, *aIt );
            if( bRet ) rStringList += aString ;
            eState = (bRet && (++aIt).Is()) ? STATE_SEP : STATE_END;
            break;
        }
        case STATE_SEP:
            bRet = aIt->GetOpCode() == ocSep;
            if( bRet ) rStringList += OUStringChar(cSep);
            eState = (bRet && (++aIt).Is()) ? STATE_STR : STATE_END;
        break;
        default:;
    }
    return bRet;
}
 
void XclTokenArrayHelper::ConvertStringToList(
    ScTokenArray& rScTokArr, svl::SharedStringPool& rSPool, sal_Unicode cStringSep )
{
    OUString aString;
    if( !GetString( aString, rScTokArr ) )
        return;
 
    rScTokArr.Clear();
    if (aString.isEmpty())
        return;
    sal_Int32 nStringIx = 0;
    for (;;)
    {
        OUString aToken( aString.getToken( 0, cStringSep, nStringIx ) );
        rScTokArr.AddString(rSPool.intern(comphelper::string::stripStart(aToken, ' ')));
        if (nStringIx<0)
            break;
        rScTokArr.AddOpCode( ocSep );
    }
}
 
// multiple operations --------------------------------------------------------
 
namespace {
 
bool lclGetAddress( const ScDocument& rDoc, ScAddress& rAddress, const FormulaToken& rToken, const ScAddress& rPos )
{
    OpCode eOpCode = rToken.GetOpCode();
    bool bIsSingleRef = (eOpCode == ocPush) && (rToken.GetType() == svSingleRef);
    if( bIsSingleRef )
    {
        const ScSingleRefData& rRef = *rToken.GetSingleRef();
        rAddress = rRef.toAbs(rDoc, rPos);
        bIsSingleRef = !rRef.IsDeleted();
    }
    return bIsSingleRef;
}
 
} // namespace
 
bool XclTokenArrayHelper::GetMultipleOpRefs(
    const ScDocument& rDoc,
    XclMultipleOpRefs& rRefs, const ScTokenArray& rScTokArr, const ScAddress& rScPos )
{
    rRefs.mbDblRefMode = false;
    enum
    {
        stBegin, stTableOp, stOpen, stFormula, stFormulaSep,
        stColFirst, stColFirstSep, stColRel, stColRelSep,
        stRowFirst, stRowFirstSep, stRowRel, stClose, stError
    } eState = stBegin;     // last read token
    for( XclTokenArrayIterator aIt( rScTokArr, true ); aIt.Is() && (eState != stError); ++aIt )
    {
        OpCode eOpCode = aIt->GetOpCode();
        bool bIsSep = eOpCode == ocSep;
        switch( eState )
        {
            case stBegin:
                eState = (eOpCode == ocTableOp) ? stTableOp : stError;
            break;
            case stTableOp:
                eState = (eOpCode == ocOpen) ? stOpen : stError;
            break;
            case stOpen:
                eState = lclGetAddress(rDoc, rRefs.maFmlaScPos, *aIt, rScPos) ? stFormula : stError;
            break;
            case stFormula:
                eState = bIsSep ? stFormulaSep : stError;
            break;
            case stFormulaSep:
                eState = lclGetAddress(rDoc, rRefs.maColFirstScPos, *aIt, rScPos) ? stColFirst : stError;
            break;
            case stColFirst:
                eState = bIsSep ? stColFirstSep : stError;
            break;
            case stColFirstSep:
                eState = lclGetAddress(rDoc, rRefs.maColRelScPos, *aIt, rScPos) ? stColRel : stError;
            break;
            case stColRel:
                eState = bIsSep ? stColRelSep : ((eOpCode == ocClose) ? stClose : stError);
            break;
            case stColRelSep:
                eState = lclGetAddress(rDoc, rRefs.maRowFirstScPos, *aIt, rScPos) ? stRowFirst : stError;
                rRefs.mbDblRefMode = true;
            break;
            case stRowFirst:
                eState = bIsSep ? stRowFirstSep : stError;
            break;
            case stRowFirstSep:
                eState = lclGetAddress(rDoc, rRefs.maRowRelScPos, *aIt, rScPos) ? stRowRel : stError;
            break;
            case stRowRel:
                eState = (eOpCode == ocClose) ? stClose : stError;
            break;
            default:
                eState = stError;
        }
    }
    return eState == stClose;
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V707 Giving short names to global variables is considered to be bad practice. It is suggested to rename 'R' variable.

V707 Giving short names to global variables is considered to be bad practice. It is suggested to rename 'V' variable.

V707 Giving short names to global variables is considered to be bad practice. It is suggested to rename 'A' variable.

V707 Giving short names to global variables is considered to be bad practice. It is suggested to rename 'MX' variable.

V1016 Expression 'eBiff >= EXC_BIFF2' is always true.