summaryrefslogtreecommitdiffstats
path: root/basic/source/runtime/methods1.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basic/source/runtime/methods1.cxx')
-rw-r--r--basic/source/runtime/methods1.cxx3073
1 files changed, 3073 insertions, 0 deletions
diff --git a/basic/source/runtime/methods1.cxx b/basic/source/runtime/methods1.cxx
new file mode 100644
index 000000000..f0c26ae5a
--- /dev/null
+++ b/basic/source/runtime/methods1.cxx
@@ -0,0 +1,3073 @@
+/* -*- 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 <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 <officecfg/Office/Scripting.hxx>
+
+#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)
+ {
+ SbxVariable* pSbxVariable = rPar.Get(1);
+ nVal = pSbxVariable->GetDate();
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ 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)
+ {
+ SbxVariable* pSbxVariable = rPar.Get(1);
+ nVal = pSbxVariable->GetInteger();
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ rPar.Get(0)->PutInteger(nVal);
+}
+
+void SbRtl_CLng(StarBASIC *, SbxArray & rPar, bool) // JSM
+{
+ sal_Int32 nVal = 0;
+ if (rPar.Count() == 2)
+ {
+ SbxVariable* pSbxVariable = rPar.Get(1);
+ nVal = pSbxVariable->GetLong();
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ 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
+{
+ OUString aString;
+ if (rPar.Count() == 2)
+ {
+ SbxVariable* pSbxVariable = rPar.Get(1);
+ aString = pSbxVariable->GetOUString();
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ 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)
+{
+ sal_Int16 nErrCode = 0;
+ if (rPar.Count() == 2)
+ {
+ SbxVariable* pSbxVariable = rPar.Get(1);
+ nErrCode = pSbxVariable->GetInteger();
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ rPar.Get(0)->PutErr(nErrCode);
+}
+
+void SbRtl_Iif(StarBASIC *, SbxArray & rPar, bool) // JSM
+{
+ if (rPar.Count() == 4)
+ {
+ if (rPar.Get(1)->GetBool())
+ {
+ *rPar.Get(0) = *rPar.Get(2);
+ }
+ else
+ {
+ *rPar.Get(0) = *rPar.Get(3);
+ }
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+}
+
+void SbRtl_GetSystemType(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() != 1)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ // Removed for SRC595
+ rPar.Get(0)->PutInteger(-1);
+ }
+}
+
+void SbRtl_GetGUIType(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() != 1)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ // 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ 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
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ 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 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ // 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ 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& rStr = rVar.GetOUString();
+ if( !bBinary || bIsArray )
+ {
+ if( bIsVariant )
+ {
+ pStrm->WriteUInt16( SbxSTRING );
+ }
+ pStrm->WriteUniOrByteString( rStr, osl_getThreadTextEncoding() );
+ }
+ else
+ {
+ // without any length information! without end-identifier!
+ // What does that mean for Unicode?! Choosing conversion to ByteString...
+ OString aByteStr(OUStringToOString(rStr, 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ 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)) )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
+ return;
+ }
+
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ OUString aResult;
+ // should be ANSI but that's not possible under Win16 in the DLL
+ OString aByteStr(OUStringToOString(rPar.Get(1)->GetOUString(),
+ osl_getThreadTextEncoding()));
+ const char* pEnvStr = getenv(aByteStr.getStr());
+ if ( pEnvStr )
+ {
+ aResult = OUString(pEnvStr, strlen(pEnvStr), osl_getThreadTextEncoding());
+ }
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ rPar.Get(0)->PutDouble(GetDialogZoomFactor(true, rPar.Get(1)->GetLong()));
+}
+
+void SbRtl_GetDialogZoomFactorY(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() != 2)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ 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)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ rPar.Get(0)->PutLong(tools::Time::GetSystemTicks());
+}
+
+void SbRtl_GetPathSeparator(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() != 1)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ rPar.Get(0)->PutString(OUString(SAL_PATHDELIMITER));
+}
+
+void SbRtl_ResolvePath(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() == 2)
+ {
+ OUString aStr = rPar.Get(1)->GetOUString();
+ rPar.Get(0)->PutString(aStr);
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+}
+
+void SbRtl_TypeLen(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() != 2)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+ else
+ {
+ 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:
+ 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 SbxOBJECT:
+ case SbxVARIANT:
+ case SbxDATAOBJECT:
+ nLen = 0;
+ 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)
+ {
+ 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);
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+}
+
+void SbRtl_ConvertFromUrl(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() == 2)
+ {
+ OUString aStr = rPar.Get(1)->GetOUString();
+ OUString aSysPath;
+ ::osl::File::getSystemPathFromFileURL( aStr, aSysPath );
+ if( aSysPath.isEmpty() )
+ {
+ aSysPath = aStr;
+ }
+ rPar.Get(0)->PutString(aSysPath);
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ }
+}
+
+
+// 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 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ SbxBase* pParObj = rPar.Get(1)->GetObject();
+ SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
+ if( pArr )
+ {
+ if (pArr->GetDims() != 1)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_WRONG_DIMS ); // Syntax Error?!
+ return;
+ }
+ 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());
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );
+ }
+}
+
+
+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 )
+ {
+ 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;
+ }
+ default: break;
+ }
+
+ 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 );
+ 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& sFuncName, SbxVariable* pRet )
+{
+ static Reference< XFunctionAccess > xFunc;
+ try
+ {
+ if ( !xFunc.is() )
+ {
+ Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() );
+ if( xFactory.is() )
+ {
+ xFunc.set( xFactory->createInstance("com.sun.star.sheet.FunctionAccess"), 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, "SYD", 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, "SLN", 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();
+ }
+ // type
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ type = rPar.Get(5)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(rate),
+ Any(nper),
+ Any(pmt),
+ Any(fv),
+ Any(type)
+ };
+
+ CallFunctionAccessFunction(aParams, "Pmt", rPar.Get(0));
+}
+
+void SbRtl_PPmt(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 4 || nArgCount > 6 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ // retrieve non-optional params
+
+ double rate = rPar.Get(1)->GetDouble();
+ double per = rPar.Get(2)->GetDouble();
+ double nper = rPar.Get(3)->GetDouble();
+ double pv = rPar.Get(4)->GetDouble();
+
+ // set default values for Optional args
+ double fv = 0;
+ double type = 0;
+
+ // fv
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ fv = rPar.Get(5)->GetDouble();
+ }
+ // type
+ if ( nArgCount >= 6 )
+ {
+ if (rPar.Get(6)->GetType() != SbxEMPTY)
+ type = rPar.Get(6)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(rate),
+ Any(per),
+ Any(nper),
+ Any(pv),
+ Any(fv),
+ Any(type)
+ };
+
+ CallFunctionAccessFunction(aParams, "PPmt", rPar.Get(0));
+}
+
+void SbRtl_PV(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();
+ }
+ // type
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ type = rPar.Get(5)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(rate),
+ Any(nper),
+ Any(pmt),
+ Any(fv),
+ Any(type)
+ };
+
+ CallFunctionAccessFunction(aParams, "PV", rPar.Get(0));
+}
+
+void SbRtl_NPV(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 1 || nArgCount > 2 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ Any aValues = sbxToUnoValue(rPar.Get(2),
+ cppu::UnoType<Sequence<double>>::get() );
+
+ // convert for calc functions
+ Sequence< Sequence< double > > sValues(1);
+ aValues >>= sValues.getArray()[ 0 ];
+ aValues <<= sValues;
+
+ Sequence< Any > aParams
+ {
+ Any(rPar.Get(1)->GetDouble()),
+ aValues
+ };
+
+ CallFunctionAccessFunction(aParams, "NPV", rPar.Get(0));
+}
+
+void SbRtl_NPer(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 pmt = rPar.Get(2)->GetDouble();
+ double pv = 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();
+ }
+ // type
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ type = rPar.Get(5)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(rate),
+ Any(pmt),
+ Any(pv),
+ Any(fv),
+ Any(type)
+ };
+
+ CallFunctionAccessFunction(aParams, "NPer", rPar.Get(0));
+}
+
+void SbRtl_MIRR(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 3 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // retrieve non-optional params
+
+ Any aValues = sbxToUnoValue(rPar.Get(1),
+ cppu::UnoType<Sequence<double>>::get() );
+
+ // convert for calc functions
+ Sequence< Sequence< double > > sValues(1);
+ aValues >>= sValues.getArray()[ 0 ];
+ aValues <<= sValues;
+
+ Sequence< Any > aParams
+ {
+ aValues,
+ Any(rPar.Get(2)->GetDouble()),
+ Any(rPar.Get(3)->GetDouble())
+ };
+
+ CallFunctionAccessFunction(aParams, "MIRR", rPar.Get(0));
+}
+
+void SbRtl_IRR(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 1 || nArgCount > 2 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ // retrieve non-optional params
+ Any aValues = sbxToUnoValue(rPar.Get(1),
+ cppu::UnoType<Sequence<double>>::get() );
+
+ // convert for calc functions
+ Sequence< Sequence< double > > sValues(1);
+ aValues >>= sValues.getArray()[ 0 ];
+ aValues <<= sValues;
+
+ // set default values for Optional args
+ double guess = 0.1;
+ // guess
+ if ( nArgCount >= 2 )
+ {
+ if (rPar.Get(2)->GetType() != SbxEMPTY)
+ guess = rPar.Get(2)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ aValues,
+ Any(guess)
+ };
+
+ CallFunctionAccessFunction(aParams, "IRR", rPar.Get(0));
+}
+
+void SbRtl_IPmt(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 4 || nArgCount > 6 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ // retrieve non-optional params
+
+ double rate = rPar.Get(1)->GetDouble();
+ double per = rPar.Get(2)->GetInteger();
+ double nper = rPar.Get(3)->GetDouble();
+ double pv = rPar.Get(4)->GetDouble();
+
+ // set default values for Optional args
+ double fv = 0;
+ double type = 0;
+
+ // fv
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ fv = rPar.Get(5)->GetDouble();
+ }
+ // type
+ if ( nArgCount >= 6 )
+ {
+ if (rPar.Get(6)->GetType() != SbxEMPTY)
+ type = rPar.Get(6)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(rate),
+ Any(per),
+ Any(nper),
+ Any(pv),
+ Any(fv),
+ Any(type)
+ };
+
+ CallFunctionAccessFunction(aParams, "IPmt", rPar.Get(0));
+}
+
+void SbRtl_FV(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 pv = 0;
+ double type = 0;
+
+ // pv
+ if ( nArgCount >= 4 )
+ {
+ if (rPar.Get(4)->GetType() != SbxEMPTY)
+ pv = rPar.Get(4)->GetDouble();
+ }
+ // type
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ type = rPar.Get(5)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(rate),
+ Any(nper),
+ Any(pmt),
+ Any(pv),
+ Any(type)
+ };
+
+ CallFunctionAccessFunction(aParams, "FV", rPar.Get(0));
+}
+
+void SbRtl_DDB(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 4 || nArgCount > 5 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ // retrieve non-optional params
+
+ double cost = rPar.Get(1)->GetDouble();
+ double salvage = rPar.Get(2)->GetDouble();
+ double life = rPar.Get(3)->GetDouble();
+ double period = rPar.Get(4)->GetDouble();
+
+ // set default values for Optional args
+ double factor = 2;
+
+ // factor
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ factor = rPar.Get(5)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(cost),
+ Any(salvage),
+ Any(life),
+ Any(period),
+ Any(factor)
+ };
+
+ CallFunctionAccessFunction(aParams, "DDB", rPar.Get(0));
+}
+
+void SbRtl_Rate(StarBASIC *, SbxArray & rPar, bool)
+{
+ sal_uInt32 nArgCount = rPar.Count() - 1;
+
+ if ( nArgCount < 3 || nArgCount > 6 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+ // retrieve non-optional params
+
+ double nper = 0;
+ double pmt = 0;
+ double pv = 0;
+
+ nper = rPar.Get(1)->GetDouble();
+ pmt = rPar.Get(2)->GetDouble();
+ pv = rPar.Get(3)->GetDouble();
+
+ // set default values for Optional args
+ double fv = 0;
+ double type = 0;
+ double guess = 0.1;
+
+ // fv
+ if ( nArgCount >= 4 )
+ {
+ if (rPar.Get(4)->GetType() != SbxEMPTY)
+ fv = rPar.Get(4)->GetDouble();
+ }
+
+ // type
+ if ( nArgCount >= 5 )
+ {
+ if (rPar.Get(5)->GetType() != SbxEMPTY)
+ type = rPar.Get(5)->GetDouble();
+ }
+
+ // guess
+ if ( nArgCount >= 6 )
+ {
+ if (rPar.Get(6)->GetType() != SbxEMPTY)
+ guess = rPar.Get(6)->GetDouble();
+ }
+
+ Sequence< Any > aParams
+ {
+ Any(nper),
+ Any(pmt),
+ Any(pv),
+ Any(fv),
+ Any(type),
+ Any(guess)
+ };
+
+ CallFunctionAccessFunction(aParams, "Rate", rPar.Get(0));
+}
+
+void SbRtl_StrReverse(StarBASIC *, SbxArray & rPar, bool)
+{
+ if (rPar.Count() != 2)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ SbxVariable* pSbxVariable = rPar.Get(1);
+ if( pSbxVariable->IsNull() )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ OUString aStr = comphelper::string::reverseString(pSbxVariable->GetOUString());
+ rPar.Get(0)->PutString(aStr);
+}
+
+void SbRtl_CompatibilityMode(StarBASIC *, SbxArray & rPar, bool)
+{
+ bool bEnabled = false;
+ sal_uInt32 nCount = rPar.Count();
+ if ( nCount != 1 && nCount != 2 )
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst )
+ {
+ if ( nCount == 2 )
+ {
+ pInst->EnableCompatibility(rPar.Get(1)->GetBool());
+ }
+ bEnabled = pInst->IsCompatibility();
+ }
+ rPar.Get(0)->PutBool(bEnabled);
+}
+
+void SbRtl_Input(StarBASIC *, SbxArray & rPar, bool)
+{
+ // 2 parameters needed
+ if (rPar.Count() < 3)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ sal_uInt16 nByteCount = rPar.Get(1)->GetUShort();
+ sal_Int16 nFileNumber = rPar.Get(2)->GetInteger();
+
+ SbiIoSystem* pIosys = GetSbData()->pInst->GetIoSystem();
+ SbiStream* pSbStrm = pIosys->GetStream( nFileNumber );
+ if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Input)) )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
+ return;
+ }
+
+ OString aByteBuffer;
+ ErrCode err = pSbStrm->Read( aByteBuffer, nByteCount, true );
+ if( !err )
+ err = pIosys->GetError();
+
+ if( err )
+ {
+ StarBASIC::Error( err );
+ return;
+ }
+ rPar.Get(0)->PutString(OStringToOUString(aByteBuffer, osl_getThreadTextEncoding()));
+}
+
+void SbRtl_Me(StarBASIC *, SbxArray & rPar, bool)
+{
+ SbModule* pActiveModule = GetSbData()->pInst->GetActiveModule();
+ SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pActiveModule );
+ SbxVariableRef refVar = rPar.Get(0);
+ if( pClassModuleObject == nullptr )
+ {
+ SbObjModule* pMod = dynamic_cast<SbObjModule*>( pActiveModule );
+ if ( pMod )
+ refVar->PutObject( pMod );
+ else
+ StarBASIC::Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
+ }
+ else
+ refVar->PutObject( pClassModuleObject );
+}
+
+#endif
+
+bool LibreOffice6FloatingPointMode()
+{
+ static bool bMode = std::getenv("LIBREOFFICE6FLOATINGPOINTMODE") != nullptr;
+
+ return bMode || officecfg::Office::Scripting::Basic::Compatibility::UseLibreOffice6FloatingPointConversion::get();
+}
+
+sal_Int16 implGetWeekDay( double aDate, bool bFirstDayParam, sal_Int16 nFirstDay )
+{
+ Date aRefDate(1899'12'30);
+ sal_Int32 nDays = static_cast<sal_Int32>(aDate);
+ aRefDate.AddDays( nDays);
+ DayOfWeek aDay = aRefDate.GetDayOfWeek();
+ sal_Int16 nDay;
+ if ( aDay != SUNDAY )
+ nDay = static_cast<sal_Int16>(aDay) + 2;
+ else
+ nDay = 1; // 1 == Sunday
+
+ // #117253 optional 2nd parameter "firstdayofweek"
+ if( bFirstDayParam )
+ {
+ if( nFirstDay < 0 || nFirstDay > 7 )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+#endif
+ return 0;
+ }
+ if( nFirstDay == 0 )
+ {
+ const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
+ if( !xCalendar.is() )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
+#endif
+ return 0;
+ }
+ nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
+ }
+ nDay = 1 + (nDay + 7 - nFirstDay) % 7;
+ }
+ return nDay;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */