Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/basic/source/runtime/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 76 kB image not shown  

Quelle  methods1.cxx   Sprache: C

 
/* -*- 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 <config_features.h>

#include <sal/config.h>
#include <config_version.h>

#include <cstddef>

#include <rtl/math.hxx>
#include <vcl/svapp.hxx>
#include <vcl/mapmod.hxx>
#include <vcl/outdev.hxx>
#include <vcl/timer.hxx>
#include <vcl/settings.hxx>
#include <basic/sbxvar.hxx>
#include <basic/sbx.hxx>
#include <svl/zforlist.hxx>
#include <tools/urlobj.hxx>
#include <tools/fract.hxx>
#include <o3tl/temporary.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <sbobjmod.hxx>
#include <basic/sbuno.hxx>

#include <date.hxx>
#include <sbintern.hxx>
#include <runtime.hxx>
#include <rtlproto.hxx>
#include "dllmgr.hxx"
#include <iosys.hxx>
#include <sbunoobj.hxx>
#include <propacc.hxx>
#include <sal/log.hxx>
#include <eventatt.hxx>
#include <rtl/math.h>
#include <svl/numformat.hxx>

#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>

#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/i18n/LocaleCalendar2.hpp>
#include <com/sun/star/sheet/XFunctionAccess.hpp>

#include <memory>

using namespace comphelper;
using namespace com::sun::star::i18n;
using namespace com::sun::star::lang;
using namespace com::sun::star::sheet;
using namespace com::sun::star::uno;

static Reference< XCalendar4 > const & getLocaleCalendar()
{
    static Reference< XCalendar4 > xCalendar = LocaleCalendar2::create(getProcessComponentContext());
    static css::lang::Locale aLastLocale;
    static bool bNeedsReload = true;

    css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale();
    bNeedsReload = bNeedsReload ||
           ( aLocale.Language != aLastLocale.Language ||
             aLocale.Country  != aLastLocale.Country ||
             aLocale.Variant  != aLastLocale.Variant );
    if( bNeedsReload )
    {
        bNeedsReload = false;
        aLastLocale = aLocale;
        xCalendar->loadDefaultCalendar( aLocale );
    }
    return xCalendar;
}

#if HAVE_FEATURE_SCRIPTING

void SbRtl_CallByName(StarBASIC *, SbxArray & rPar, bool)
{
    const sal_Int16 vbGet       = 2;
    const sal_Int16 vbLet       = 4;
    const sal_Int16 vbMethod    = 1;
    const sal_Int16 vbSet       = 8;

    // At least 3 parameter needed plus function itself -> 4
    sal_uInt32 nParCount = rPar.Count();
    if ( nParCount < 4 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    // 1. parameter is object
    SbxBase* pObjVar = rPar.Get(1)->GetObject();
    SbxObject* pObj = nullptr;
    if( pObjVar )
        pObj = dynamic_cast<SbxObject*>( pObjVar );
    if( !pObj )
        if (auto pSbxVar = dynamic_cast<const SbxVariable*>( pObjVar))
            pObj = dynamic_cast<SbxObject*>( pSbxVar->GetObject() );
    if( !pObj )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
        return;
    }

    // 2. parameter is ProcName
    OUString aNameStr = rPar.Get(2)->GetOUString();

    // 3. parameter is CallType
    sal_Int16 nCallType = rPar.Get(3)->GetInteger();

    //SbxObject* pFindObj = NULL;
    SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::DontCare );
    if( pFindVar == nullptr )
    {
        StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
        return;
    }

    switch( nCallType )
    {
    case vbGet:
        {
            SbxValues aVals;
            aVals.eType = SbxVARIANT;
            pFindVar->Get( aVals );

            SbxVariableRef refVar = rPar.Get(0);
            refVar->Put( aVals );
        }
        break;
    case vbLet:
    case vbSet:
        {
            if ( nParCount != 5 )
            {
                StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
                return;
            }
            SbxVariableRef pValVar = rPar.Get(4);
            if( nCallType == vbLet )
            {
                SbxValues aVals;
                aVals.eType = SbxVARIANT;
                pValVar->Get( aVals );
                pFindVar->Put( aVals );
            }
            else
            {
                SbxVariableRef rFindVar = pFindVar;
                SbiInstance* pInst = GetSbData()->pInst;
                SbiRuntime* pRT = pInst ? pInst->pRun : nullptr;
                if( pRT != nullptr )
                {
                    pRT->StepSET_Impl( pValVar, rFindVar );
                }
            }
        }
        break;
    case vbMethod:
        {
            SbMethod* pMeth = dynamic_cast<SbMethod*>( pFindVar );
            if( pMeth == nullptr )
            {
                StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
                return;
            }

            // Setup parameters
            SbxArrayRef xArray;
            sal_uInt32 nMethParamCount = nParCount - 4;
            if( nMethParamCount > 0 )
            {
                xArray = new SbxArray;
                for( sal_uInt32 i = 0 ; i < nMethParamCount ; i++ )
                {
                    SbxVariable* pPar = rPar.Get(i + 4);
                    xArray->Put(pPar, i + 1);
                }
            }

            // Call method
            SbxVariableRef refVar = rPar.Get(0);
            if( xArray.is() )
                pMeth->SetParameters( xArray.get() );
            pMeth->Call( refVar.get() );
            pMeth->SetParameters( nullptr );
        }
        break;
    default:
        StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
    }
}

void SbRtl_CBool(StarBASIC *, SbxArray & rPar, bool// JSM
{
    bool bVal = false;
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        bVal = pSbxVariable->GetBool();
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    rPar.Get(0)->PutBool(bVal);
}

void SbRtl_CByte(StarBASIC *, SbxArray & rPar, bool// JSM
{
    sal_uInt8 nByte = 0;
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        nByte = pSbxVariable->GetByte();
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    rPar.Get(0)->PutByte(nByte);
}

void SbRtl_CCur(StarBASIC *, SbxArray & rPar, bool)
{
    sal_Int64 nCur = 0;
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        nCur = pSbxVariable->GetCurrency();
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    rPar.Get(0)->PutCurrency(nCur);
}

void SbRtl_CDec(StarBASIC *, SbxArray & rPar, bool)
{
#ifdef _WIN32
    SbxDecimal* pDec = nullptr;
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        pDec = pSbxVariable->GetDecimal();
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    rPar.Get(0)->PutDecimal(pDec);
#else
    rPar.Get(0)->PutEmpty();
    StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTED);
#endif
}

void SbRtl_CDate(StarBASIC *, SbxArray & rPar, bool// JSM
{
    double nVal = 0.0;
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxVariable* pSbxVariable = rPar.Get(1);
    nVal = pSbxVariable->GetDate();
    rPar.Get(0)->PutDate(nVal);
}

void SbRtl_CDbl(StarBASIC *, SbxArray & rPar, bool)  // JSM
{
    double nVal = 0.0;
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        if( pSbxVariable->GetType() == SbxSTRING )
        {
            // #41690
            OUString aScanStr = pSbxVariable->GetOUString();
            ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, nVal );
            if( Error != ERRCODE_NONE )
            {
                StarBASIC::Error( Error );
            }
        }
        else
        {
            nVal = pSbxVariable->GetDouble();
        }
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }

    rPar.Get(0)->PutDouble(nVal);
}

void SbRtl_CInt(StarBASIC *, SbxArray & rPar, bool)  // JSM
{
    sal_Int16 nVal = 0;
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxVariable* pSbxVariable = rPar.Get(1);
    nVal = pSbxVariable->GetInteger();
    rPar.Get(0)->PutInteger(nVal);
}

void SbRtl_CLng(StarBASIC *, SbxArray & rPar, bool)  // JSM
{
    sal_Int32 nVal = 0;
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxVariable* pSbxVariable = rPar.Get(1);
    nVal = pSbxVariable->GetLong();
    rPar.Get(0)->PutLong(nVal);
}

void SbRtl_CSng(StarBASIC *, SbxArray & rPar, bool)  // JSM
{
    float nVal = float(0.0);
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        if( pSbxVariable->GetType() == SbxSTRING )
        {
            // #41690
            double dVal = 0.0;
            OUString aScanStr = pSbxVariable->GetOUString();
            ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, dVal, /*bSingle=*/true );
            if( SbxBase::GetError() == ERRCODE_NONE && Error != ERRCODE_NONE )
            {
                StarBASIC::Error( Error );
            }
            nVal = static_cast<float>(dVal);
        }
        else
        {
            nVal = pSbxVariable->GetSingle();
        }
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    rPar.Get(0)->PutSingle(nVal);
}

void SbRtl_CStr(StarBASIC *, SbxArray & rPar, bool)  // JSM
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxVariable* pSbxVariable = rPar.Get(1);
    OUString aString = pSbxVariable->GetOUString();
    rPar.Get(0)->PutString(aString);
}

void SbRtl_CVar(StarBASIC *, SbxArray & rPar, bool)  // JSM
{
    SbxValues aVals( SbxVARIANT );
    if (rPar.Count() == 2)
    {
        SbxVariable* pSbxVariable = rPar.Get(1);
        pSbxVariable->Get( aVals );
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    rPar.Get(0)->Put(aVals);
}

void SbRtl_CVErr(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxVariable* pSbxVariable = rPar.Get(1);
    sal_Int16 nErrCode = pSbxVariable->GetInteger();
    rPar.Get(0)->PutErr(nErrCode);
}

void SbRtl_Iif(StarBASIC *, SbxArray & rPar, bool// JSM
{
    if (rPar.Count() != 4)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    if (rPar.Get(1)->GetBool())
    {
        *rPar.Get(0) = *rPar.Get(2);
    }
    else
    {
        *rPar.Get(0) = *rPar.Get(3);
    }

}

void SbRtl_GetSystemType(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 1)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

        // Removed for SRC595
    rPar.Get(0)->PutInteger(-1);
}

void SbRtl_GetGUIType(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 1)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

        // 17.7.2000 Make simple solution for testtool / fat office
#if   defined(_WIN32)
    rPar.Get(0)->PutInteger(1);
#elif defined(UNX)
    rPar.Get(0)->PutInteger(4);
#else
    rPar.Get(0)->PutInteger(-1);
#endif
}

void SbRtl_Red(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    sal_Int32 nRGB = rPar.Get(1)->GetLong();
    nRGB &= 0x00FF0000;
    nRGB >>= 16;
    rPar.Get(0)->PutInteger(static_cast<sal_Int16>(nRGB));

}

void SbRtl_Green(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)

        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    sal_Int32 nRGB = rPar.Get(1)->GetLong();
    nRGB &= 0x0000FF00;
    nRGB >>= 8;
    rPar.Get(0)->PutInteger(static_cast<sal_Int16>(nRGB));
}

void SbRtl_Blue(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    sal_Int32 nRGB = rPar.Get(1)->GetLong();
    nRGB &= 0x000000FF;
    rPar.Get(0)->PutInteger(static_cast<sal_Int16>(nRGB));
}


void SbRtl_Switch(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nCount = rPar.Count();
    if( !(nCount & 0x0001 ))
    {
        // number of arguments must be odd
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    sal_uInt32 nCurExpr = 1;
    while( nCurExpr < (nCount-1) )
    {
        if (rPar.Get(nCurExpr)->GetBool())
        {
            (*rPar.Get(0)) = *(rPar.Get(nCurExpr + 1));
            return;
        }
        nCurExpr += 2;
    }
    rPar.Get(0)->PutNull();
}

//i#64882# Common wait impl for existing Wait and new WaitUntil
// rtl functions
void Wait_Impl( bool bDurationBased, SbxArray& rPar )
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    tools::Long nWait = 0;
    if ( bDurationBased )
    {
        double dWait = rPar.Get(1)->GetDouble();
        double dNow = Now_Impl();
        double dSecs = ( dWait - dNow ) * 24.0 * 3600.0;
        nWait = static_cast<tools::Long>( dSecs * 1000 ); // wait in thousands of sec
    }
    else
    {
        nWait = rPar.Get(1)->GetLong();
    }

    if( nWait < 0 )
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    Timer aTimer("basic Wait_Impl");
    aTimer.SetTimeout( nWait );
    aTimer.Start();
    while ( aTimer.IsActive() && !Application::IsQuit())
    {
        Application::Yield();
    }
}

//i#64882#
void SbRtl_Wait(StarBASIC *, SbxArray & rPar, bool)
{
    Wait_Impl( false, rPar );
}

//i#64882# add new WaitUntil ( for application.wait )
// share wait_impl with 'normal' oobasic wait
void SbRtl_WaitUntil(StarBASIC *, SbxArray & rPar, bool)
{
    Wait_Impl( true, rPar );
}

void SbRtl_DoEvents(StarBASIC *, SbxArray & rPar, bool)
{
// don't understand what upstream are up to
// we already process application events etc. in between
// basic runtime pcode ( on a timed basis )
    // always return 0
    rPar.Get(0)->PutInteger(0);
    Application::Reschedule( true );
}

void SbRtl_GetGUIVersion(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 1)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    // Removed for SRC595
    rPar.Get(0)->PutLong(-1);
}

void SbRtl_Choose(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() < 2)
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    sal_Int16 nIndex = rPar.Get(1)->GetInteger();
    sal_uInt32 nCount = rPar.Count();
    nCount--;
    if( nCount == 1 || nIndex > sal::static_int_cast<sal_Int16>(nCount-1) || nIndex < 1 )
    {
        rPar.Get(0)->PutNull();
        return;
    }
    (*rPar.Get(0)) = *(rPar.Get(nIndex + 1));
}


void SbRtl_Trim(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() < 2)
    {
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    OUString aStr(comphelper::string::strip(rPar.Get(1)->GetOUString(), ' '));
    rPar.Get(0)->PutString(aStr);
}

void SbRtl_GetSolarVersion(StarBASIC *, SbxArray & rPar, bool)
{
    rPar.Get(0)->PutLong(LIBO_VERSION_MAJOR * 10000 + LIBO_VERSION_MINOR * 100
                         + LIBO_VERSION_MICRO * 1);
}

void SbRtl_TwipsPerPixelX(StarBASIC *, SbxArray & rPar, bool)
{
    sal_Int32 nResult = 0;
    Size aSize( 100,0 );
    MapMode aMap( MapUnit::MapTwip );
    OutputDevice* pDevice = Application::GetDefaultDevice();
    if( pDevice )
    {
        aSize = pDevice->PixelToLogic( aSize, aMap );
        nResult = aSize.Width() / 100;
    }
    rPar.Get(0)->PutLong(nResult);
}

void SbRtl_TwipsPerPixelY(StarBASIC *, SbxArray & rPar, bool)
{
    sal_Int32 nResult = 0;
    Size aSize( 0,100 );
    MapMode aMap( MapUnit::MapTwip );
    OutputDevice* pDevice = Application::GetDefaultDevice();
    if( pDevice )
    {
        aSize = pDevice->PixelToLogic( aSize, aMap );
        nResult = aSize.Height() / 100;
    }
    rPar.Get(0)->PutLong(nResult);
}


void SbRtl_FreeLibrary(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    GetSbData()->pInst->GetDllMgr()->FreeDll(rPar.Get(1)->GetOUString());
}
bool IsBaseIndexOne()
{
    bool bResult = false;
    if ( GetSbData()->pInst && GetSbData()->pInst->pRun )
    {
        sal_uInt16 res = GetSbData()->pInst->pRun->GetBase();
        if ( res )
        {
            bResult = true;
        }
    }
    return bResult;
}

void SbRtl_Array(StarBASIC *, SbxArray & rPar, bool)
{
    SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
    sal_uInt32 nArraySize = rPar.Count() - 1;
    bool bIncIndex = IsBaseIndexOne();
    if( nArraySize )
    {
        if ( bIncIndex )
        {
            pArray->AddDim(1, sal::static_int_cast<sal_Int32>(nArraySize));
        }
        else
        {
            pArray->AddDim(0, sal::static_int_cast<sal_Int32>(nArraySize) - 1);
        }
    }
    else
    {
        pArray->unoAddDim(0, -1);
    }

    // insert parameters into the array
    for( sal_uInt32 i = 0 ; i < nArraySize ; i++ )
    {
        SbxVariable* pVar = rPar.Get(i + 1);
        SbxVariable* pNew = new SbxEnsureParentVariable(*pVar);
        pNew->SetFlag( SbxFlagBits::Write );
        sal_Int32 aIdx[1];
        aIdx[0] = static_cast<sal_Int32>(i);
        if ( bIncIndex )
        {
            ++aIdx[0];
        }
        pArray->Put(pNew, aIdx);
    }

    // return array
    SbxVariableRef refVar = rPar.Get(0);
    SbxFlagBits nFlags = refVar->GetFlags();
    refVar->ResetFlag( SbxFlagBits::Fixed );
    refVar->PutObject( pArray );
    refVar->SetFlags( nFlags );
    refVar->SetParameters( nullptr );
}


// Featurewish #57868
// The function returns a variant-array; if there are no parameters passed,
// an empty array is created (according to dim a(); equal to a sequence of
// the length 0 in Uno).
// If there are parameters passed, there's a dimension created for each of
// them; DimArray( 2, 2, 4 ) is equal to DIM a( 2, 2, 4 )
// the array is always of the type variant
void SbRtl_DimArray(StarBASIC *, SbxArray & rPar, bool)
{
    SbxDimArray * pArray = new SbxDimArray( SbxVARIANT );
    sal_uInt32 nArrayDims = rPar.Count() - 1;
    if( nArrayDims > 0 )
    {
        for( sal_uInt32 i = 0; i < nArrayDims ; i++ )
        {
            sal_Int32 ub = rPar.Get(i + 1)->GetLong();
            if( ub < 0 )
            {
                StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
                ub = 0;
            }
            pArray->AddDim(0, ub);
        }
    }
    else
    {
        pArray->unoAddDim(0, -1);
    }
    SbxVariableRef refVar = rPar.Get(0);
    SbxFlagBits nFlags = refVar->GetFlags();
    refVar->ResetFlag( SbxFlagBits::Fixed );
    refVar->PutObject( pArray );
    refVar->SetFlags( nFlags );
    refVar->SetParameters( nullptr );
}

/*
 * FindObject and FindPropertyObject make it possible to
 * address objects and properties of the type Object with
 * their name as string-parameters at the runtime.
 *
 * Example:
 * MyObj.Prop1.Bla = 5
 *
 * is equal to:
 * dim ObjVar as Object
 * dim ObjProp as Object
 * ObjName$ = "MyObj"
 * ObjVar = FindObject( ObjName$ )
 * PropName$ = "Prop1"
 * ObjProp = FindPropertyObject( ObjVar, PropName$ )
 * ObjProp.Bla = 5
 *
 * The names can be created dynamically at the runtime
 * so that e. g. via controls "TextEdit1" to "TextEdit5"
 * can be iterated in a dialog in a loop.
 */



// 1st parameter = the object's name as string
void SbRtl_FindObject(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );


    OUString aNameStr = rPar.Get(1)->GetOUString();

    SbxBase* pFind =  StarBASIC::FindSBXInCurrentScope( aNameStr );
    SbxObject* pFindObj = nullptr;
    if( pFind )
    {
        pFindObj = dynamic_cast<SbxObject*>( pFind );
    }
    SbxVariableRef refVar = rPar.Get(0);
    refVar->PutObject( pFindObj );
}

// address object-property in an object
// 1st parameter = object
// 2nd parameter = the property's name as string
void SbRtl_FindPropertyObject(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 3)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );


    SbxBase* pObjVar = rPar.Get(1)->GetObject();
    SbxObject* pObj = nullptr;
    if( pObjVar )
    {
        pObj = dynamic_cast<SbxObject*>( pObjVar );
    }
    if( !pObj )
        if (auto pSbxVar = dynamic_cast<const SbxVariable*>( pObjVar))
            pObj = dynamic_cast<SbxObject*>( pSbxVar->GetObject() );

    OUString aNameStr = rPar.Get(2)->GetOUString();

    SbxObject* pFindObj = nullptr;
    if( pObj )
    {
        SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::Object );
        pFindObj = dynamic_cast<SbxObject*>( pFindVar );
    }
    else
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
    }

    SbxVariableRef refVar = rPar.Get(0);
    refVar->PutObject( pFindObj );
}


static bool lcl_WriteSbxVariable( const SbxVariable& rVar, SvStream* pStrm,
                                      bool bBinary, short nBlockLen, bool bIsArray )
{
    sal_uInt64 const nFPos = pStrm->Tell();

    bool bIsVariant = !rVar.IsFixed();
    SbxDataType eType = rVar.GetType();

    switch( eType )
    {
    case SbxBOOL:
    case SbxCHAR:
    case SbxBYTE:
        if( bIsVariant )
        {
            pStrm->WriteUInt16( SbxBYTE ); // VarType Id
        }
        pStrm->WriteUChar( rVar.GetByte() );
        break;

    case SbxEMPTY:
    case SbxNULL:
    case SbxVOID:
    case SbxINTEGER:
    case SbxUSHORT:
    case SbxINT:
    case SbxUINT:
        if( bIsVariant )
        {
            pStrm->WriteUInt16( SbxINTEGER ); // VarType Id
        }
        pStrm->WriteInt16( rVar.GetInteger() );
        break;

    case SbxLONG:
    case SbxULONG:
        if( bIsVariant )
        {
            pStrm->WriteUInt16( SbxLONG ); // VarType Id
        }
        pStrm->WriteInt32( rVar.GetLong() );
        break;
    case SbxSALINT64:
    case SbxSALUINT64:
        if( bIsVariant )
        {
            pStrm->WriteUInt16( SbxSALINT64 ); // VarType Id
        }
        pStrm->WriteUInt64( rVar.GetInt64() );
        break;
    case SbxSINGLE:
        if( bIsVariant )
        {
            pStrm->WriteUInt16( eType ); // VarType Id
        }
        pStrm->WriteFloat( rVar.GetSingle() );
        break;

    case SbxDOUBLE:
    case SbxCURRENCY:
    case SbxDATE:
        if( bIsVariant )
        {
            pStrm->WriteUInt16( eType ); // VarType Id
        }
        pStrm->WriteDouble( rVar.GetDouble() );
        break;

    case SbxSTRING:
    case SbxLPSTR:
        {
            const OUString aStr = rVar.GetOUString();
            if( !bBinary || bIsArray )
            {
                if( bIsVariant )
                {
                    pStrm->WriteUInt16( SbxSTRING );
                }
                pStrm->WriteUniOrByteString( aStr, osl_getThreadTextEncoding() );
            }
            else
            {
                // without any length information! without end-identifier!
                // What does that mean for Unicode?! Choosing conversion to ByteString...
                OString aByteStr(OUStringToOString(aStr, osl_getThreadTextEncoding()));
                pStrm->WriteOString( aByteStr );
            }
        }
        break;

    default:
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return false;
    }

    if( nBlockLen )
    {
        pStrm->Seek( nFPos + nBlockLen );
    }
    return pStrm->GetErrorCode() == ERRCODE_NONE;
}

static bool lcl_ReadSbxVariable( SbxVariable& rVar, SvStream* pStrm,
                                     bool bBinary, short nBlockLen )
{
    double aDouble;

    sal_uInt64 const nFPos = pStrm->Tell();

    bool bIsVariant = !rVar.IsFixed();
    SbxDataType eVarType = rVar.GetType();

    SbxDataType eSrcType = eVarType;
    if( bIsVariant )
    {
        sal_uInt16 nTemp;
        pStrm->ReadUInt16( nTemp );
        eSrcType = static_cast<SbxDataType>(nTemp);
    }

    switch( eSrcType )
    {
    case SbxBOOL:
    case SbxCHAR:
    case SbxBYTE:
        {
            sal_uInt8 aByte;
            pStrm->ReadUChar( aByte );

            if( bBinary && SbiRuntime::isVBAEnabled() && aByte == 1 && pStrm->eof() )
            {
                aByte = 0;
            }
            rVar.PutByte( aByte );
        }
        break;

    case SbxEMPTY:
    case SbxNULL:
    case SbxVOID:
    case SbxINTEGER:
    case SbxUSHORT:
    case SbxINT:
    case SbxUINT:
        {
            sal_Int16 aInt;
            pStrm->ReadInt16( aInt );
            rVar.PutInteger( aInt );
        }
        break;

    case SbxLONG:
    case SbxULONG:
        {
            sal_Int32 aInt;
            pStrm->ReadInt32( aInt );
            rVar.PutLong( aInt );
        }
        break;
    case SbxSALINT64:
    case SbxSALUINT64:
        {
            sal_uInt32 aInt;
            pStrm->ReadUInt32( aInt );
            rVar.PutInt64( static_cast<sal_Int64>(aInt) );
        }
        break;
    case SbxSINGLE:
        {
            float nS;
            pStrm->ReadFloat( nS );
            rVar.PutSingle( nS );
        }
        break;

    case SbxDOUBLE:
    case SbxCURRENCY:
        {
            pStrm->ReadDouble( aDouble );
            rVar.PutDouble( aDouble );
        }
        break;

    case SbxDATE:
        {
            pStrm->ReadDouble( aDouble );
            rVar.PutDate( aDouble );
        }
        break;

    case SbxSTRING:
    case SbxLPSTR:
        {
            OUString aStr = pStrm->ReadUniOrByteString(osl_getThreadTextEncoding());
            rVar.PutString( aStr );
        }
        break;

    default:
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return false;
    }

    if( nBlockLen )
    {
        pStrm->Seek( nFPos + nBlockLen );
    }
    return pStrm->GetErrorCode() == ERRCODE_NONE;
}


// nCurDim = 1...n
static bool lcl_WriteReadSbxArray( SbxDimArray& rArr, SvStream* pStrm,
    bool bBinary, sal_Int32 nCurDim, sal_Int32* pOtherDims, bool bWrite )
{
    SAL_WARN_IF( nCurDim <= 0,"basic""Bad Dim");
    sal_Int32 nLower, nUpper;
    if (!rArr.GetDim(nCurDim, nLower, nUpper))
        return false;
    for(sal_Int32 nCur = nLower; nCur <= nUpper; nCur++ )
    {
        pOtherDims[ nCurDim-1 ] = nCur;
        if( nCurDim != 1 )
            lcl_WriteReadSbxArray(rArr, pStrm, bBinary, nCurDim-1, pOtherDims, bWrite);
        else
        {
            SbxVariable* pVar = rArr.Get(pOtherDims);
            bool bRet;
            if( bWrite )
                bRet = lcl_WriteSbxVariable(*pVar, pStrm, bBinary, 0, true );
            else
                bRet = lcl_ReadSbxVariable(*pVar, pStrm, bBinary, 0 );
            if( !bRet )
                return false;
        }
    }
    return true;
}

static void PutGet( SbxArray& rPar, bool bPut )
{
    if (rPar.Count() != 4)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    sal_Int16 nFileNo = rPar.Get(1)->GetInteger();
    SbxVariable* pVar2 = rPar.Get(2);
    SbxDataType eType2 = pVar2->GetType();
    bool bHasRecordNo = (eType2 != SbxEMPTY && eType2 != SbxERROR);
    tools::Long nRecordNo = pVar2->GetLong();
    if ( nFileNo < 1 || ( bHasRecordNo && nRecordNo < 1 ) )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }
    nRecordNo--;
    SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
    SbiStream* pSbStrm = pIO->GetStream( nFileNo );

    if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Random)) )
        return StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );

    SvStream* pStrm = pSbStrm->GetStrm();
    bool bRandom = pSbStrm->IsRandom();
    short nBlockLen = bRandom ? pSbStrm->GetBlockLen() : 0;

    if( bPut )
    {
        pSbStrm->ExpandFile();
    }

    if( bHasRecordNo )
    {
        sal_uInt64 const nFilePos = bRandom
            ? static_cast<sal_uInt64>(nBlockLen * nRecordNo)
            : static_cast<sal_uInt64>(nRecordNo);
        pStrm->Seek( nFilePos );
    }

    SbxDimArray* pArr = nullptr;
    SbxVariable* pVar = rPar.Get(3);
    if( pVar->GetType() & SbxARRAY )
    {
        SbxBase* pParObj = pVar->GetObject();
        pArr = dynamic_cast<SbxDimArray*>( pParObj );
    }

    bool bRet;

    if( pArr )
    {
        sal_uInt64 const nFPos = pStrm->Tell();
        sal_Int32 nDims = pArr->GetDims();
        std::unique_ptr<sal_Int32[]> pDims(new sal_Int32[ nDims ]);
        bRet = lcl_WriteReadSbxArray(*pArr,pStrm,!bRandom,nDims,pDims.get(),bPut);
        pDims.reset();
        if( nBlockLen )
            pStrm->Seek( nFPos + nBlockLen );
    }
    else
    {
        if( bPut )
            bRet = lcl_WriteSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, false);
        else
            bRet = lcl_ReadSbxVariable(*pVar, pStrm, !bRandom, nBlockLen);
    }
    if( !bRet || pStrm->GetErrorCode() )
        StarBASIC::Error( ERRCODE_BASIC_IO_ERROR );
}

void SbRtl_Put(StarBASIC *, SbxArray & rPar, bool)
{
    PutGet( rPar, true );
}

void SbRtl_Get(StarBASIC *, SbxArray & rPar, bool)
{
    PutGet( rPar, false );
}

void SbRtl_Environ(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    OUString aResult;
    osl_getEnvironment(rPar.Get(1)->GetOUString().pData, &aResult.pData);
    rPar.Get(0)->PutString(aResult);
}

static double GetDialogZoomFactor( bool bX, tools::Long nValue )
{
    OutputDevice* pDevice = Application::GetDefaultDevice();
    double nResult = 0;
    if( pDevice )
    {
        Size aRefSize( nValue, nValue );
        Fraction aFracX( 1, 26 );
        Fraction aFracY( 1, 24 );
        MapMode aMap( MapUnit::MapAppFont, Point(), aFracX, aFracY );
        Size aScaledSize = pDevice->LogicToPixel( aRefSize, aMap );
        aRefSize = pDevice->LogicToPixel( aRefSize, MapMode(MapUnit::MapTwip) );

        double nRef, nScaled;
        if( bX )
        {
            nRef = aRefSize.Width();
            nScaled = aScaledSize.Width();
        }
        else
        {
            nRef = aRefSize.Height();
            nScaled = aScaledSize.Height();
        }
        nResult = nScaled / nRef;
    }
    return nResult;
}


void SbRtl_GetDialogZoomFactorX(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    rPar.Get(0)->PutDouble(GetDialogZoomFactor(true, rPar.Get(1)->GetLong()));
}

void SbRtl_GetDialogZoomFactorY(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    rPar.Get(0)->PutDouble(GetDialogZoomFactor(false, rPar.Get(1)->GetLong()));
}


void SbRtl_EnableReschedule(StarBASIC *, SbxArray & rPar, bool)
{
    rPar.Get(0)->PutEmpty();
    if (rPar.Count() != 2)
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    if( GetSbData()->pInst )
        GetSbData()->pInst->EnableReschedule(rPar.Get(1)->GetBool());
}

void SbRtl_GetSystemTicks(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 1)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    rPar.Get(0)->PutLong(tools::Time::GetSystemTicks());
}

void SbRtl_GetPathSeparator(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 1)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    rPar.Get(0)->PutString(OUString(SAL_PATHDELIMITER));
}

void SbRtl_ResolvePath(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    OUString aStr = rPar.Get(1)->GetOUString();
    rPar.Get(0)->PutString(aStr);
}

void SbRtl_TypeLen(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxDataType eType = rPar.Get(1)->GetType();
    sal_Int16 nLen = 0;
    switch( eType )
    {
    case SbxEMPTY:
    case SbxNULL:
    case SbxVECTOR:
    case SbxARRAY:
    case SbxBYREF:
    case SbxVOID:
    case SbxHRESULT:
    case SbxPOINTER:
    case SbxDIMARRAY:
    case SbxCARRAY:
    case SbxUSERDEF:
    case SbxOBJECT:
    case SbxVARIANT:
    case SbxDATAOBJECT:
        nLen = 0;
        break;

    case SbxINTEGER:
    case SbxERROR:
    case SbxUSHORT:
    case SbxINT:
    case SbxUINT:
        nLen = 2;
        break;

    case SbxLONG:
    case SbxSINGLE:
    case SbxULONG:
        nLen = 4;
        break;

    case SbxDOUBLE:
    case SbxCURRENCY:
    case SbxDATE:
    case SbxSALINT64:
    case SbxSALUINT64:
        nLen = 8;
        break;

    case SbxCHAR:
    case SbxBYTE:
    case SbxBOOL:
        nLen = 1;
            break;

    case SbxLPSTR:
    case SbxLPWSTR:
    case SbxCoreSTRING:
    case SbxSTRING:
        nLen = static_cast<sal_Int16>(rPar.Get(1)->GetOUString().getLength());
        break;

    default:
        nLen = 0;
        break;
    }
    rPar.Get(0)->PutInteger(nLen);
}


// 1st parameter == class name, other parameters for initialisation
void SbRtl_CreateUnoStruct(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_CreateUnoStruct( rPar );
}


// 1st parameter == service-name
void SbRtl_CreateUnoService(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_CreateUnoService( rPar );
}

void SbRtl_CreateUnoServiceWithArguments(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_CreateUnoServiceWithArguments( rPar );
}


void SbRtl_CreateUnoValue(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_CreateUnoValue( rPar );
}


// no parameters
void SbRtl_GetProcessServiceManager(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_GetProcessServiceManager( rPar );
}


// 1st parameter == Sequence<PropertyValue>
void SbRtl_CreatePropertySet(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_CreatePropertySet( rPar );
}


// multiple interface-names as parameters
void SbRtl_HasUnoInterfaces(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_HasInterfaces( rPar );
}


void SbRtl_IsUnoStruct(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_IsUnoStruct( rPar );
}


void SbRtl_EqualUnoObjects(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_EqualUnoObjects( rPar );
}

void SbRtl_CreateUnoDialog(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_CreateUnoDialog( rPar );
}

// Return the application standard lib as root scope
void SbRtl_GlobalScope(StarBASIC * pBasic, SbxArray & rPar, bool)
{
    SbxObject* p = pBasic;
    while( p->GetParent() )
    {
        p = p->GetParent();
    }
    SbxVariableRef refVar = rPar.Get(0);
    refVar->PutObject( p );
}

// Helper functions to convert Url from/to system paths
void SbRtl_ConvertToUrl(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    OUString aStr = rPar.Get(1)->GetOUString();
    INetURLObject aURLObj( aStr, INetProtocol::File );
    OUString aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
    if( aFileURL.isEmpty() )
    {
        osl::File::getFileURLFromSystemPath(aStr, aFileURL);
    }
    if( aFileURL.isEmpty() )
    {
        aFileURL = aStr;
    }
    rPar.Get(0)->PutString(aFileURL);

}

void SbRtl_ConvertFromUrl(StarBASIC *, SbxArray & rPar, bool)
{
    if (rPar.Count() != 2)
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    OUString aStr = rPar.Get(1)->GetOUString();
    OUString aSysPath;
    ::osl::File::getSystemPathFromFileURL( aStr, aSysPath );
    if( aSysPath.isEmpty() )
    {
        aSysPath = aStr;
    }
    rPar.Get(0)->PutString(aSysPath);
}


// Provide DefaultContext
void SbRtl_GetDefaultContext(StarBASIC *, SbxArray & rPar, bool)
{
    RTL_Impl_GetDefaultContext( rPar );
}

void SbRtl_Join(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if ( nParCount != 3 && nParCount != 2 )
        return StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );

    SbxBase* pParObj = rPar.Get(1)->GetObject();
    SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
    if( !pArr )
        return StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );

    if (pArr->GetDims() != 1)
        return StarBASIC::Error( ERRCODE_BASIC_WRONG_DIMS );   // Syntax Error?!

    OUString aDelim;
    if( nParCount == 3 )
    {
        aDelim = rPar.Get(2)->GetOUString();
    }
    else
    {
        aDelim = " ";
    }
    OUStringBuffer aRetStr(32);
    sal_Int32 nLower, nUpper;
    pArr->GetDim(1, nLower, nUpper);
    sal_Int32 aIdx[1];
    for (aIdx[0] = nLower; aIdx[0] <= nUpper; ++aIdx[0])
    {
        OUString aStr = pArr->Get(aIdx)->GetOUString();
        aRetStr.append(aStr);
        if (aIdx[0] != nUpper)
        {
            aRetStr.append(aDelim);
        }
    }
    rPar.Get(0)->PutString(aRetStr.makeStringAndClear());

}


void SbRtl_Split(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if ( nParCount < 2 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    OUString aExpression = rPar.Get(1)->GetOUString();
    sal_Int32 nArraySize = 0;
    std::vector< OUString > vRet;
    if( !aExpression.isEmpty() )
    {
        OUString aDelim;
        if( nParCount >= 3 )
        {
            aDelim = rPar.Get(2)->GetOUString();
        }
        else
        {
            aDelim = " ";
        }

        sal_Int32 nCount = -1;
        if( nParCount == 4 )
        {
            nCount = rPar.Get(3)->GetLong();
        }
        sal_Int32 nDelimLen = aDelim.getLength();
        if( nDelimLen )
        {
            sal_Int32 iSearch = -1;
            sal_Int32 iStart = 0;
            do
            {
                bool bBreak = false;
                if( nCount >= 0 && nArraySize == nCount - 1 )
                {
                    bBreak = true;
                }
                iSearch = aExpression.indexOf( aDelim, iStart );
                OUString aSubStr;
                if( iSearch >= 0 && !bBreak )
                {
                    aSubStr = aExpression.copy( iStart, iSearch - iStart );
                    iStart = iSearch + nDelimLen;
                }
                else
                {
                    aSubStr = aExpression.copy( iStart );
                }
                vRet.push_back( aSubStr );
                nArraySize++;

                if( bBreak )
                {
                    break;
                }
            }
            while( iSearch >= 0 );
        }
        else
        {
            vRet.push_back( aExpression );
            nArraySize = 1;
        }
    }

    // tdf#123025 - split returns an array of substrings
    SbxDimArray* pArray = new SbxDimArray( SbxSTRING );
    pArray->unoAddDim(0, nArraySize - 1);

    // insert parameter(s) into the array
    const bool bIsVBAInterOp = SbiRuntime::isVBAEnabled();
    for(sal_Int32 i = 0 ; i < nArraySize ; i++ )
    {
        // tdf#123025 - split returns an array of substrings
        SbxVariableRef xVar = new SbxVariable( SbxSTRING );
        xVar->PutString( vRet[i] );
        // tdf#144924 - allow the assignment of different data types to the individual elements
        if (!bIsVBAInterOp)
        {
            xVar->ResetFlag(SbxFlagBits::Fixed);
        }
        pArray->Put(xVar.get(), &i);
    }

    // return array
    SbxVariableRef refVar = rPar.Get(0);
    SbxFlagBits nFlags = refVar->GetFlags();
    refVar->ResetFlag( SbxFlagBits::Fixed );
    refVar->PutObject( pArray );
    refVar->SetFlags( nFlags );
    refVar->SetParameters( nullptr );
}

// MonthName(month[, abbreviate])
void SbRtl_MonthName(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if( nParCount != 2 && nParCount != 3 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
    if( !xCalendar.is() )
    {
        StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
        return;
    }
    Sequence< CalendarItem2 > aMonthSeq = xCalendar->getMonths2();
    sal_Int32 nMonthCount = aMonthSeq.getLength();

    sal_Int16 nVal = rPar.Get(1)->GetInteger();
    if( nVal < 1 || nVal > nMonthCount )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    bool bAbbreviate = false;
    if( nParCount == 3 )
        bAbbreviate = rPar.Get(2)->GetBool();

    const CalendarItem2* pCalendarItems = aMonthSeq.getConstArray();
    const CalendarItem2& rItem = pCalendarItems[nVal - 1];

    OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
    rPar.Get(0)->PutString(aRetStr);
}

// WeekdayName(weekday, abbreviate, firstdayofweek)
void SbRtl_WeekdayName(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if( nParCount < 2 || nParCount > 4 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
    if( !xCalendar.is() )
    {
        StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
        return;
    }

    Sequence< CalendarItem2 > aDaySeq = xCalendar->getDays2();
    sal_Int16 nDayCount = static_cast<sal_Int16>(aDaySeq.getLength());
    sal_Int16 nDay = rPar.Get(1)->GetInteger();
    sal_Int16 nFirstDay = 0;
    if( nParCount == 4 )
    {
        nFirstDay = rPar.Get(3)->GetInteger();
        if( nFirstDay < 0 || nFirstDay > 7 )
        {
            StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
            return;
        }
    }
    if( nFirstDay == 0 )
    {
        nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
    }
    nDay = 1 + (nDay + nDayCount + nFirstDay - 2) % nDayCount;
    if( nDay < 1 || nDay > nDayCount )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    bool bAbbreviate = false;
    if( nParCount >= 3 )
    {
        SbxVariable* pPar2 = rPar.Get(2);
        if( !pPar2->IsErr() )
        {
            bAbbreviate = pPar2->GetBool();
        }
    }

    const CalendarItem2* pCalendarItems = aDaySeq.getConstArray();
    const CalendarItem2& rItem = pCalendarItems[nDay - 1];

    OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
    rPar.Get(0)->PutString(aRetStr);
}

void SbRtl_Weekday(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if ( nParCount < 2 || nParCount > 3 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
    else
    {
        double aDate = rPar.Get(1)->GetDate();

        bool bFirstDay = false;
        sal_Int16 nFirstDay = 0;
        if ( nParCount > 2 )
        {
            nFirstDay = rPar.Get(2)->GetInteger();
            bFirstDay = true;
        }
        sal_Int16 nDay = implGetWeekDay( aDate, bFirstDay, nFirstDay );
        rPar.Get(0)->PutInteger(nDay);
    }
}

namespace {

enum Interval
{
    INTERVAL_YYYY,
    INTERVAL_Q,
    INTERVAL_M,
    INTERVAL_Y,
    INTERVAL_D,
    INTERVAL_W,
    INTERVAL_WW,
    INTERVAL_H,
    INTERVAL_N,
    INTERVAL_S
};

struct IntervalInfo
{
    Interval    meInterval;
    char const * mStringCode;
    double      mdValue;
    bool        mbSimple;
};

}

static IntervalInfo const * getIntervalInfo( const OUString& rStringCode )
{
    static IntervalInfo const aIntervalTable[] =
    {
        { INTERVAL_YYYY, "yyyy", 0.0,           false }, // Year
        { INTERVAL_Q,    "q",    0.0,           false }, // Quarter
        { INTERVAL_M,    "m",    0.0,           false }, // Month
        { INTERVAL_Y,    "y",    1.0,           true  }, // Day of year
        { INTERVAL_D,    "d",    1.0,           true  }, // Day
        { INTERVAL_W,    "w",    1.0,           true  }, // Weekday
        { INTERVAL_WW,   "ww",   7.0,           true  }, // Week
        { INTERVAL_H,    "h",    1.0 /    24.0, true  }, // Hour
        { INTERVAL_N,    "n",    1.0 /  1440.0, true  }, // Minute
        { INTERVAL_S,    "s",    1.0 / 86400.0, true  }  // Second
    };
    auto const pred = [&rStringCode](const IntervalInfo &aInterval) {
            return rStringCode.equalsIgnoreAsciiCaseAscii(aInterval.mStringCode);
    };

    auto intervalIter = std::find_if(std::begin(aIntervalTable), std::end(aIntervalTable), pred);
    if(intervalIter != std::end(aIntervalTable)) {
            return intervalIter;
    }
    return nullptr;
}

static void implGetDayMonthYear( sal_Int16& rnYear, sal_Int16& rnMonth, sal_Int16& rnDay, double dDate )
{
    rnDay   = implGetDateDay( dDate );
    rnMonth = implGetDateMonth( dDate );
    rnYear  = implGetDateYear( dDate );
}

/** Limits a date to valid dates within tools' class Date capabilities.

    @return the year number, truncated if necessary and in that case also
            rMonth and rDay adjusted.
 */

static sal_Int16 limitDate( sal_Int32 n32Year, sal_Int16& rMonth, sal_Int16& rDay )
{
    if( n32Year > SAL_MAX_INT16 )
    {
        n32Year = SAL_MAX_INT16;
        rMonth = 12;
        rDay = 31;
    }
    else if( n32Year < SAL_MIN_INT16 )
    {
        n32Year = SAL_MIN_INT16;
        rMonth = 1;
        rDay = 1;
    }
    return static_cast<sal_Int16>(n32Year);
}

void SbRtl_DateAdd(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if( nParCount != 4 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    OUString aStringCode = rPar.Get(1)->GetOUString();
    IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
    if( !pInfo )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    sal_Int32 lNumber = rPar.Get(2)->GetLong();
    double dDate = rPar.Get(3)->GetDate();
    double dNewDate = 0;
    if( pInfo->mbSimple )
    {
        double dAdd = pInfo->mdValue * lNumber;
        dNewDate = dDate + dAdd;
    }
    else
    {
        // Keep hours, minutes, seconds
        double dHoursMinutesSeconds = dDate - floor( dDate );

        bool bOk = true;
        sal_Int16 nYear, nMonth, nDay;
        sal_Int16 nTargetYear16 = 0, nTargetMonth = 0;
        implGetDayMonthYear( nYear, nMonth, nDay, dDate );
        switch( pInfo->meInterval )
        {
            case INTERVAL_YYYY:
            {
                sal_Int32 nTargetYear = lNumber + nYear;
                nTargetYear16 = limitDate( nTargetYear, nMonth, nDay );
                /* TODO: should the result be error if the date was limited? It never was. */
                nTargetMonth = nMonth;
                bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
                break;
            }
            case INTERVAL_Q:
            case INTERVAL_M:
            {
                bool bNeg = (lNumber < 0);
                if( bNeg )
                    lNumber = -lNumber;
                sal_Int32 nYearsAdd;
                sal_Int16 nMonthAdd;
                if( pInfo->meInterval == INTERVAL_Q )
                {
                    nYearsAdd = lNumber / 4;
                    nMonthAdd = static_cast<sal_Int16>( 3 * (lNumber % 4) );
                }
                else
                {
                    nYearsAdd = lNumber / 12;
                    nMonthAdd = static_cast<sal_Int16>( lNumber % 12 );
                }

                sal_Int32 nTargetYear;
                if( bNeg )
                {
                    nTargetMonth = nMonth - nMonthAdd;
                    if( nTargetMonth <= 0 )
                    {
                        nTargetMonth += 12;
                        nYearsAdd++;
                    }
                    nTargetYear = static_cast<sal_Int32>(nYear) - nYearsAdd;
                }
                else
                {
                    nTargetMonth = nMonth + nMonthAdd;
                    if( nTargetMonth > 12 )
                    {
                        nTargetMonth -= 12;
                        nYearsAdd++;
                    }
                    nTargetYear = static_cast<sal_Int32>(nYear) + nYearsAdd;
                }
                nTargetYear16 = limitDate( nTargetYear, nTargetMonth, nDay );
                /* TODO: should the result be error if the date was limited? It never was. */
                bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
                break;
            }
            defaultbreak;
        }

        if( bOk )
            dNewDate += dHoursMinutesSeconds;
    }

    rPar.Get(0)->PutDate(dNewDate);
}

static double RoundImpl( double d )
{
    return ( d >= 0 ) ? floor( d + 0.5 ) : -floor( -d + 0.5 );
}

void SbRtl_DateDiff(StarBASIC *, SbxArray & rPar, bool)
{
    // DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])

    sal_uInt32 nParCount = rPar.Count();
    if( nParCount < 4 || nParCount > 6 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    OUString aStringCode = rPar.Get(1)->GetOUString();
    IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
    if( !pInfo )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    double dDate1 = rPar.Get(2)->GetDate();
    double dDate2 = rPar.Get(3)->GetDate();

    double dRet = 0.0;
    switch( pInfo->meInterval )
    {
        case INTERVAL_YYYY:
        {
            sal_Int16 nYear1 = implGetDateYear( dDate1 );
            sal_Int16 nYear2 = implGetDateYear( dDate2 );
            dRet = nYear2 - nYear1;
            break;
        }
        case INTERVAL_Q:
        {
            sal_Int16 nYear1 = implGetDateYear( dDate1 );
            sal_Int16 nYear2 = implGetDateYear( dDate2 );
            sal_Int16 nQ1 = 1 + (implGetDateMonth( dDate1 ) - 1) / 3;
            sal_Int16 nQ2 = 1 + (implGetDateMonth( dDate2 ) - 1) / 3;
            sal_Int16 nQGes1 = 4 * nYear1 + nQ1;
            sal_Int16 nQGes2 = 4 * nYear2 + nQ2;
            dRet = nQGes2 - nQGes1;
            break;
        }
        case INTERVAL_M:
        {
            sal_Int16 nYear1 = implGetDateYear( dDate1 );
            sal_Int16 nYear2 = implGetDateYear( dDate2 );
            sal_Int16 nMonth1 = implGetDateMonth( dDate1 );
            sal_Int16 nMonth2 = implGetDateMonth( dDate2 );
            sal_Int16 nMonthGes1 = 12 * nYear1 + nMonth1;
            sal_Int16 nMonthGes2 = 12 * nYear2 + nMonth2;
            dRet = nMonthGes2 - nMonthGes1;
            break;
        }
        case INTERVAL_Y:
        case INTERVAL_D:
        {
            double dDays1 = floor( dDate1 );
            double dDays2 = floor( dDate2 );
            dRet = dDays2 - dDays1;
            break;
        }
        case INTERVAL_W:
        case INTERVAL_WW:
        {
            double dDays1 = floor( dDate1 );
            double dDays2 = floor( dDate2 );
            if( pInfo->meInterval == INTERVAL_WW )
            {
                sal_Int16 nFirstDay = 1;    // Default
                if( nParCount >= 5 )
                {
                    nFirstDay = rPar.Get(4)->GetInteger();
                    if( nFirstDay < 0 || nFirstDay > 7 )
                    {
                        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
                        return;
                    }
                    if( nFirstDay == 0 )
                    {
                        const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
                        if( !xCalendar.is() )
                        {
                            StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
                            return;
                        }
                        nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
                    }
                }
                sal_Int16 nDay1 = implGetWeekDay( dDate1 );
                sal_Int16 nDay1_Diff = nDay1 - nFirstDay;
                if( nDay1_Diff < 0 )
                    nDay1_Diff += 7;
                dDays1 -= nDay1_Diff;

                sal_Int16 nDay2 = implGetWeekDay( dDate2 );
                sal_Int16 nDay2_Diff = nDay2 - nFirstDay;
                if( nDay2_Diff < 0 )
                    nDay2_Diff += 7;
                dDays2 -= nDay2_Diff;
            }

            double dDiff = dDays2 - dDays1;
            dRet = ( dDiff >= 0 ) ? floor( dDiff / 7.0 ) : -floor( -dDiff / 7.0 );
            break;
        }
        case INTERVAL_H:
        {
            dRet = RoundImpl( 24.0 * (dDate2 - dDate1) );
            break;
        }
        case INTERVAL_N:
        {
            dRet = RoundImpl( 1440.0 * (dDate2 - dDate1) );
            break;
        }
        case INTERVAL_S:
        {
            dRet = RoundImpl( 86400.0 * (dDate2 - dDate1) );
            break;
        }
    }
    rPar.Get(0)->PutDouble(dRet);
}

static double implGetDateOfFirstDayInFirstWeek
    ( sal_Int16 nYear, sal_Int16& nFirstDay, sal_Int16& nFirstWeek, bool* pbError = nullptr )
{
    ErrCode nError = ERRCODE_NONE;
    if( nFirstDay < 0 || nFirstDay > 7 )
        nError = ERRCODE_BASIC_BAD_ARGUMENT;

    if( nFirstWeek < 0 || nFirstWeek > 3 )
        nError = ERRCODE_BASIC_BAD_ARGUMENT;

    Reference< XCalendar4 > xCalendar;
    if( nFirstDay == 0 || nFirstWeek == 0 )
    {
        xCalendar = getLocaleCalendar();
        if( !xCalendar.is() )
            nError = ERRCODE_BASIC_BAD_ARGUMENT;
    }

    if( nError != ERRCODE_NONE )
    {
        StarBASIC::Error( nError );
        if( pbError )
            *pbError = true;
        return 0.0;
    }

    if( nFirstDay == 0 )
        nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );

    sal_Int16 nFirstWeekMinDays = 0;    // Not used for vbFirstJan1 = default
    if( nFirstWeek == 0 )
    {
        nFirstWeekMinDays = xCalendar->getMinimumNumberOfDaysForFirstWeek();
        if( nFirstWeekMinDays == 1 )
        {
            nFirstWeekMinDays = 0;
            nFirstWeek = 1;
        }
        else if( nFirstWeekMinDays == 4 )
            nFirstWeek = 2;
        else if( nFirstWeekMinDays == 7 )
            nFirstWeek = 3;
    }
    else if( nFirstWeek == 2 )
        nFirstWeekMinDays = 4;      // vbFirstFourDays
    else if( nFirstWeek == 3 )
        nFirstWeekMinDays = 7;      // vbFirstFourDays

    double dBaseDate;
    implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );

    sal_Int16 nWeekDay0101 = implGetWeekDay( dBaseDate );
    sal_Int16 nDayDiff = nWeekDay0101 - nFirstDay;
    if( nDayDiff < 0 )
        nDayDiff += 7;

    if( nFirstWeekMinDays )
    {
        sal_Int16 nThisWeeksDaysInYearCount = 7 - nDayDiff;
        if( nThisWeeksDaysInYearCount < nFirstWeekMinDays )
            nDayDiff -= 7;
    }
    double dRetDate = dBaseDate - nDayDiff;
    return dRetDate;
}

void SbRtl_DatePart(StarBASIC *, SbxArray & rPar, bool)
{
    // DatePart(interval, date[,firstdayofweek[, firstweekofyear]])

    sal_uInt32 nParCount = rPar.Count();
    if( nParCount < 3 || nParCount > 5 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    OUString aStringCode = rPar.Get(1)->GetOUString();
    IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
    if( !pInfo )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    double dDate = rPar.Get(2)->GetDate();

    sal_Int32 nRet = 0;
    switch( pInfo->meInterval )
    {
        case INTERVAL_YYYY:
        {
            nRet = implGetDateYear( dDate );
            break;
        }
        case INTERVAL_Q:
        {
            nRet = 1 + (implGetDateMonth( dDate ) - 1) / 3;
            break;
        }
        case INTERVAL_M:
        {
            nRet = implGetDateMonth( dDate );
            break;
        }
        case INTERVAL_Y:
        {
            sal_Int16 nYear = implGetDateYear( dDate );
            double dBaseDate;
            implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
            nRet = 1 + sal_Int32( dDate - dBaseDate );
            break;
        }
        case INTERVAL_D:
        {
            nRet = implGetDateDay( dDate );
            break;
        }
        case INTERVAL_W:
        {
            bool bFirstDay = false;
            sal_Int16 nFirstDay = 1;    // Default
            if( nParCount >= 4 )
            {
                nFirstDay = rPar.Get(3)->GetInteger();
                bFirstDay = true;
            }
            nRet = implGetWeekDay( dDate, bFirstDay, nFirstDay );
            break;
        }
        case INTERVAL_WW:
        {
            sal_Int16 nFirstDay = 1;    // Default
            if( nParCount >= 4 )
                nFirstDay = rPar.Get(3)->GetInteger();

            sal_Int16 nFirstWeek = 1;   // Default
            if( nParCount == 5 )
                nFirstWeek = rPar.Get(4)->GetInteger();

            sal_Int16 nYear = implGetDateYear( dDate );
            bool bError = false;
            double dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear, nFirstDay, nFirstWeek, &bError&nbsp;);
            if( !bError )
            {
                if( dYearFirstDay > dDate )
                {
                    // Date belongs to last year's week
                    dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear - 1, nFirstDay, nFirstWeek );
                }
                else if( nFirstWeek != 1 )
                {
                    // Check if date belongs to next year
                    double dNextYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear + 1, nFirstDay, nFirstWeek );
                    if( dDate >= dNextYearFirstDay )
                        dYearFirstDay = dNextYearFirstDay;
                }

                // Calculate week
                double dDiff = dDate - dYearFirstDay;
                nRet = 1 + sal_Int32( dDiff / 7 );
            }
            break;
        }
        case INTERVAL_H:
        {
            nRet = implGetHour( dDate );
            break;
        }
        case INTERVAL_N:
        {
            nRet = implGetMinute( dDate );
            break;
        }
        case INTERVAL_S:
        {
            nRet = implGetSecond( dDate );
            break;
        }
    }
    rPar.Get(0)->PutLong(nRet);
}

// FormatDateTime(Date[,NamedFormat])
void SbRtl_FormatDateTime(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if( nParCount < 2 || nParCount > 3 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    double dDate = rPar.Get(1)->GetDate();
    sal_Int16 nNamedFormat = 0;
    if( nParCount > 2 )
    {
        nNamedFormat = rPar.Get(2)->GetInteger();
        if( nNamedFormat < 0 || nNamedFormat > 4 )
        {
            StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
            return;
        }
    }

    const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
    if( !xCalendar.is() )
    {
        StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
        return;
    }

    OUString aRetStr;
    SbxVariableRef pSbxVar = new SbxVariable( SbxSTRING );
    switch( nNamedFormat )
    {
        // GeneralDate:
        // Display a date and/or time. If there is a date part,
        // display it as a short date. If there is a time part,
        // display it as a long time. If present, both parts are displayed.

        // 12/21/2004 11:24:50 AM
        // 21.12.2004 12:13:51
    case 0:
        pSbxVar->PutDate( dDate );
        aRetStr = pSbxVar->GetOUString();
        break;

        // LongDate: Display a date using the long date format specified
        // in your computer's regional settings.
        // Tuesday, December 21, 2004
        // Dienstag, 21. December 2004
    case 1:
        {
            std::shared_ptr<SvNumberFormatter> pFormatter;
            if( GetSbData()->pInst )
            {
                pFormatter = GetSbData()->pInst->GetNumberFormatter();
            }
            else
            {
                sal_uInt32 n;   // Dummy
                pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
            }

            LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
            const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, eLangType );
            const Color* pCol;
            pFormatter->GetOutputString( dDate, nIndex, aRetStr, &pCol );
            break;
        }

        // ShortDate: Display a date using the short date format specified
        // in your computer's regional settings.
        // 21.12.2004
    case 2:
        pSbxVar->PutDate( floor(dDate) );
        aRetStr = pSbxVar->GetOUString();
        break;

        // LongTime: Display a time using the time format specified
        // in your computer's regional settings.
        // 11:24:50 AM
        // 12:13:51
    case 3:
        // ShortTime: Display a time using the 24-hour format (hh:mm).
        // 11:24
    case 4:
        double dTime = modf( dDate, &o3tl::temporary(double()) );
        pSbxVar->PutDate( dTime );
        if( nNamedFormat == 3 )
        {
            aRetStr = pSbxVar->GetOUString();
        }
        else
        {
            aRetStr = pSbxVar->GetOUString().copy( 0, 5 );
        }
        break;
    }

    rPar.Get(0)->PutString(aRetStr);
}

void SbRtl_Frac(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if( nParCount != 2)
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    SbxVariable* pSbxVariable = rPar.Get(1);
    double dVal = pSbxVariable->GetDouble();
    if(dVal >= 0)
        rPar.Get(0)->PutDouble(dVal - ::rtl::math::approxFloor(dVal));
    else
        rPar.Get(0)->PutDouble(dVal - ::rtl::math::approxCeil(dVal));
}

void SbRtl_Round(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nParCount = rPar.Count();
    if( nParCount != 2 && nParCount != 3 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    SbxVariable* pSbxVariable = rPar.Get(1);
    double dVal = pSbxVariable->GetDouble();
    double dRes = 0.0;
    if( dVal != 0.0 )
    {
        sal_Int16 numdecimalplaces = 0;
        if( nParCount == 3 )
        {
            numdecimalplaces = rPar.Get(2)->GetInteger();
            if( numdecimalplaces < 0 || numdecimalplaces > 22 )
            {
                StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
                return;
            }
        }

        dRes = rtl_math_round(dVal, numdecimalplaces, rtl_math_RoundingMode_HalfEven);
    }
    rPar.Get(0)->PutDouble(dRes);
}

static void CallFunctionAccessFunction( const Sequence< Any >& aArgs, const OUString&&nbsp;sFuncName, SbxVariable* pRet )
{
    static Reference< XFunctionAccess > xFunc;
    try
    {
        if ( !xFunc.is() )
        {
            Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() );
            if( xFactory.is() )
            {
                xFunc.set( xFactory->createInstance(u"com.sun.star.sheet.FunctionAccess"_ustr), UNO_QUERY_THROW);
            }
        }
        Any aRet = xFunc->callFunction( sFuncName, aArgs );

        unoToSbxValue( pRet, aRet );

    }
    catch(const Exception& )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
    }
}

void SbRtl_SYD(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nArgCount = rPar.Count() - 1;

    if ( nArgCount < 4 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    // retrieve non-optional params

    Sequence< Any > aParams
    {
        Any(rPar.Get(1)->GetDouble()),
        Any(rPar.Get(2)->GetDouble()),
        Any(rPar.Get(3)->GetDouble()),
        Any(rPar.Get(4)->GetDouble())
    };

    CallFunctionAccessFunction(aParams, u"SYD"_ustr, rPar.Get(0));
}

void SbRtl_SLN(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nArgCount = rPar.Count() - 1;

    if ( nArgCount < 3 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }

    // retrieve non-optional params

    Sequence< Any > aParams
    {
        Any(rPar.Get(1)->GetDouble()),
        Any(rPar.Get(2)->GetDouble()),
        Any(rPar.Get(3)->GetDouble())
    };

    CallFunctionAccessFunction(aParams, u"SLN"_ustr, rPar.Get(0));
}

void SbRtl_Pmt(StarBASIC *, SbxArray & rPar, bool)
{
    sal_uInt32 nArgCount = rPar.Count() - 1;

    if ( nArgCount < 3 || nArgCount > 5 )
    {
        StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
        return;
    }
    // retrieve non-optional params

    double rate = rPar.Get(1)->GetDouble();
    double nper = rPar.Get(2)->GetDouble();
    double pmt = rPar.Get(3)->GetDouble();

    // set default values for Optional args
    double fv = 0;
    double type = 0;

    // fv
    if ( nArgCount >= 4 )
    {
        if (rPar.Get(4)->GetType() != SbxEMPTY)
            fv = rPar.Get(4)->GetDouble();
    }
--> --------------------

--> maximum size reached

--> --------------------

96%


¤ Dauer der Verarbeitung: 0.36 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.