/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dllmgr.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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( pObjVar ); if( !pObj ) if (auto pSbxVar = dynamic_cast( pObjVar)) pObj = dynamic_cast( 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( 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(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(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(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(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( 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(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(nArraySize)); } else { pArray->AddDim(0, sal::static_int_cast(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(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( 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( pObjVar ); } if( !pObj ) if (auto pSbxVar = dynamic_cast( pObjVar)) pObj = dynamic_cast( pSbxVar->GetObject() ); OUString aNameStr = rPar.Get(2)->GetOUString(); SbxObject* pFindObj = nullptr; if( pObj ) { SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::Object ); pFindObj = dynamic_cast( 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(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(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(nBlockLen * nRecordNo) : static_cast(nRecordNo); pStrm->Seek( nFilePos ); } SbxDimArray* pArr = nullptr; SbxVariable* pVar = rPar.Get(3); if( pVar->GetType() & SbxARRAY ) { SbxBase* pParObj = pVar->GetObject(); pArr = dynamic_cast( pParObj ); } bool bRet; if( pArr ) { sal_uInt64 const nFPos = pStrm->Tell(); sal_Int32 nDims = pArr->GetDims(); std::unique_ptr 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; // 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) 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(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 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( 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(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(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( 3 * (lNumber % 4) ); } else { nYearsAdd = lNumber / 12; nMonthAdd = static_cast( lNumber % 12 ); } sal_Int32 nTargetYear; if( bNeg ) { nTargetMonth = nMonth - nMonthAdd; if( nTargetMonth <= 0 ) { nTargetMonth += 12; nYearsAdd++; } nTargetYear = static_cast(nYear) - nYearsAdd; } else { nTargetMonth = nMonth + nMonthAdd; if( nTargetMonth > 12 ) { nTargetMonth -= 12; nYearsAdd++; } nTargetYear = static_cast(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 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(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(); } // 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, u"Pmt"_ustr, 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, u"PPmt"_ustr, 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, u"PV"_ustr, 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>::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, u"NPV"_ustr, 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, u"NPer"_ustr, 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>::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, u"MIRR"_ustr, 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>::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, u"IRR"_ustr, 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, u"IPmt"_ustr, 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, u"FV"_ustr, 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, u"DDB"_ustr, 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, u"Rate"_ustr, 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( pActiveModule ); SbxVariableRef refVar = rPar.Get(0); if( pClassModuleObject == nullptr ) { SbObjModule* pMod = dynamic_cast( pActiveModule ); if ( pMod ) refVar->PutObject( pMod ); else StarBASIC::Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); } else refVar->PutObject( pClassModuleObject ); } #endif sal_Int16 implGetWeekDay( double aDate, bool bFirstDayParam, sal_Int16 nFirstDay ) { Date aRefDate(1899'12'30); sal_Int32 nDays = static_cast(aDate); aRefDate.AddDays( nDays); DayOfWeek aDay = aRefDate.GetDayOfWeek(); sal_Int16 nDay; if ( aDay != SUNDAY ) nDay = static_cast(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: */