nss: upgrade to release 3.73
[LibreOffice.git] / basic / source / runtime / methods1.cxx
blobc847df8d26e6096515f3ba77f239657b6ed3fedb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <sal/config.h>
23 #include <config_version.h>
25 #include <cstddef>
27 #include <stdlib.h>
28 #include <rtl/math.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/mapmod.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/timer.hxx>
33 #include <vcl/settings.hxx>
34 #include <basic/sbxvar.hxx>
35 #include <basic/sbx.hxx>
36 #include <svl/zforlist.hxx>
37 #include <tools/urlobj.hxx>
38 #include <tools/fract.hxx>
39 #include <o3tl/temporary.hxx>
40 #include <osl/file.hxx>
41 #include <sbobjmod.hxx>
42 #include <basic/sbuno.hxx>
44 #include <date.hxx>
45 #include <sbintern.hxx>
46 #include <runtime.hxx>
47 #include <rtlproto.hxx>
48 #include "dllmgr.hxx"
49 #include <iosys.hxx>
50 #include <sbunoobj.hxx>
51 #include <propacc.hxx>
52 #include <sal/log.hxx>
53 #include <eventatt.hxx>
55 #include <comphelper/processfactory.hxx>
56 #include <comphelper/string.hxx>
58 #include <com/sun/star/uno/Sequence.hxx>
59 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
60 #include <com/sun/star/i18n/LocaleCalendar2.hpp>
61 #include <com/sun/star/sheet/XFunctionAccess.hpp>
62 #include <memory>
64 using namespace comphelper;
65 using namespace com::sun::star::i18n;
66 using namespace com::sun::star::lang;
67 using namespace com::sun::star::sheet;
68 using namespace com::sun::star::uno;
70 static Reference< XCalendar4 > const & getLocaleCalendar()
72 static Reference< XCalendar4 > xCalendar = LocaleCalendar2::create(getProcessComponentContext());
73 static css::lang::Locale aLastLocale;
74 static bool bNeedsInit = true;
76 css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale();
77 bool bNeedsReload = false;
78 if( bNeedsInit )
80 bNeedsInit = false;
81 bNeedsReload = true;
83 else if( aLocale.Language != aLastLocale.Language ||
84 aLocale.Country != aLastLocale.Country ||
85 aLocale.Variant != aLastLocale.Variant )
87 bNeedsReload = true;
89 if( bNeedsReload )
91 aLastLocale = aLocale;
92 xCalendar->loadDefaultCalendar( aLocale );
94 return xCalendar;
97 #if HAVE_FEATURE_SCRIPTING
99 void SbRtl_CallByName(StarBASIC *, SbxArray & rPar, bool)
101 const sal_Int16 vbGet = 2;
102 const sal_Int16 vbLet = 4;
103 const sal_Int16 vbMethod = 1;
104 const sal_Int16 vbSet = 8;
106 // At least 3 parameter needed plus function itself -> 4
107 sal_uInt32 nParCount = rPar.Count32();
108 if ( nParCount < 4 )
110 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
111 return;
114 // 1. parameter is object
115 SbxBase* pObjVar = rPar.Get32(1)->GetObject();
116 SbxObject* pObj = nullptr;
117 if( pObjVar )
118 pObj = dynamic_cast<SbxObject*>( pObjVar );
119 if( !pObj )
120 if (auto pSbxVar = dynamic_cast<const SbxVariable*>( pObjVar))
121 pObj = dynamic_cast<SbxObject*>( pSbxVar->GetObject() );
122 if( !pObj )
124 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
125 return;
128 // 2. parameter is ProcedureName
129 OUString aNameStr = rPar.Get32(2)->GetOUString();
131 // 3. parameter is CallType
132 sal_Int16 nCallType = rPar.Get32(3)->GetInteger();
134 //SbxObject* pFindObj = NULL;
135 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::DontCare );
136 if( pFindVar == nullptr )
138 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
139 return;
142 switch( nCallType )
144 case vbGet:
146 SbxValues aVals;
147 aVals.eType = SbxVARIANT;
148 pFindVar->Get( aVals );
150 SbxVariableRef refVar = rPar.Get32(0);
151 refVar->Put( aVals );
153 break;
154 case vbLet:
155 case vbSet:
157 if ( nParCount != 5 )
159 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
160 return;
162 SbxVariableRef pValVar = rPar.Get32(4);
163 if( nCallType == vbLet )
165 SbxValues aVals;
166 aVals.eType = SbxVARIANT;
167 pValVar->Get( aVals );
168 pFindVar->Put( aVals );
170 else
172 SbxVariableRef rFindVar = pFindVar;
173 SbiInstance* pInst = GetSbData()->pInst;
174 SbiRuntime* pRT = pInst ? pInst->pRun : nullptr;
175 if( pRT != nullptr )
177 pRT->StepSET_Impl( pValVar, rFindVar );
181 break;
182 case vbMethod:
184 SbMethod* pMeth = dynamic_cast<SbMethod*>( pFindVar );
185 if( pMeth == nullptr )
187 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
188 return;
191 // Setup parameters
192 SbxArrayRef xArray;
193 sal_uInt32 nMethParamCount = nParCount - 4;
194 if( nMethParamCount > 0 )
196 xArray = new SbxArray;
197 for( sal_uInt32 i = 0 ; i < nMethParamCount ; i++ )
199 SbxVariable* pPar = rPar.Get32( i + 4 );
200 xArray->Put32( pPar, i + 1 );
204 // Call method
205 SbxVariableRef refVar = rPar.Get32(0);
206 if( xArray.is() )
207 pMeth->SetParameters( xArray.get() );
208 pMeth->Call( refVar.get() );
209 pMeth->SetParameters( nullptr );
211 break;
212 default:
213 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
217 void SbRtl_CBool(StarBASIC *, SbxArray & rPar, bool) // JSM
219 bool bVal = false;
220 if ( rPar.Count32() == 2 )
222 SbxVariable *pSbxVariable = rPar.Get32(1);
223 bVal = pSbxVariable->GetBool();
225 else
227 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
229 rPar.Get32(0)->PutBool(bVal);
232 void SbRtl_CByte(StarBASIC *, SbxArray & rPar, bool) // JSM
234 sal_uInt8 nByte = 0;
235 if ( rPar.Count32() == 2 )
237 SbxVariable *pSbxVariable = rPar.Get32(1);
238 nByte = pSbxVariable->GetByte();
240 else
242 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
244 rPar.Get32(0)->PutByte(nByte);
247 void SbRtl_CCur(StarBASIC *, SbxArray & rPar, bool)
249 sal_Int64 nCur = 0;
250 if ( rPar.Count32() == 2 )
252 SbxVariable *pSbxVariable = rPar.Get32(1);
253 nCur = pSbxVariable->GetCurrency();
255 else
257 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
259 rPar.Get32(0)->PutCurrency( nCur );
262 void SbRtl_CDec(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
264 (void)pBasic;
265 (void)bWrite;
267 #ifdef _WIN32
268 SbxDecimal* pDec = nullptr;
269 if ( rPar.Count32() == 2 )
271 SbxVariable *pSbxVariable = rPar.Get32(1);
272 pDec = pSbxVariable->GetDecimal();
274 else
276 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
278 rPar.Get32(0)->PutDecimal( pDec );
279 #else
280 rPar.Get32(0)->PutEmpty();
281 StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTED);
282 #endif
285 void SbRtl_CDate(StarBASIC *, SbxArray & rPar, bool) // JSM
287 double nVal = 0.0;
288 if ( rPar.Count32() == 2 )
290 SbxVariable *pSbxVariable = rPar.Get32(1);
291 nVal = pSbxVariable->GetDate();
293 else
295 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
297 rPar.Get32(0)->PutDate(nVal);
300 void SbRtl_CDbl(StarBASIC *, SbxArray & rPar, bool) // JSM
302 double nVal = 0.0;
303 if ( rPar.Count32() == 2 )
305 SbxVariable *pSbxVariable = rPar.Get32(1);
306 if( pSbxVariable->GetType() == SbxSTRING )
308 // #41690
309 OUString aScanStr = pSbxVariable->GetOUString();
310 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, nVal );
311 if( Error != ERRCODE_NONE )
313 StarBASIC::Error( Error );
316 else
318 nVal = pSbxVariable->GetDouble();
321 else
323 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
326 rPar.Get32(0)->PutDouble(nVal);
329 void SbRtl_CInt(StarBASIC *, SbxArray & rPar, bool) // JSM
331 sal_Int16 nVal = 0;
332 if ( rPar.Count32() == 2 )
334 SbxVariable *pSbxVariable = rPar.Get32(1);
335 nVal = pSbxVariable->GetInteger();
337 else
339 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
341 rPar.Get32(0)->PutInteger(nVal);
344 void SbRtl_CLng(StarBASIC *, SbxArray & rPar, bool) // JSM
346 sal_Int32 nVal = 0;
347 if ( rPar.Count32() == 2 )
349 SbxVariable *pSbxVariable = rPar.Get32(1);
350 nVal = pSbxVariable->GetLong();
352 else
354 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
356 rPar.Get32(0)->PutLong(nVal);
359 void SbRtl_CSng(StarBASIC *, SbxArray & rPar, bool) // JSM
361 float nVal = float(0.0);
362 if ( rPar.Count32() == 2 )
364 SbxVariable *pSbxVariable = rPar.Get32(1);
365 if( pSbxVariable->GetType() == SbxSTRING )
367 // #41690
368 double dVal = 0.0;
369 OUString aScanStr = pSbxVariable->GetOUString();
370 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, dVal, /*bSingle=*/true );
371 if( SbxBase::GetError() == ERRCODE_NONE && Error != ERRCODE_NONE )
373 StarBASIC::Error( Error );
375 nVal = static_cast<float>(dVal);
377 else
379 nVal = pSbxVariable->GetSingle();
382 else
384 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
386 rPar.Get32(0)->PutSingle(nVal);
389 void SbRtl_CStr(StarBASIC *, SbxArray & rPar, bool) // JSM
391 OUString aString;
392 if ( rPar.Count32() == 2 )
394 SbxVariable *pSbxVariable = rPar.Get32(1);
395 aString = pSbxVariable->GetOUString();
397 else
399 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
401 rPar.Get32(0)->PutString(aString);
404 void SbRtl_CVar(StarBASIC *, SbxArray & rPar, bool) // JSM
406 SbxValues aVals( SbxVARIANT );
407 if ( rPar.Count32() == 2 )
409 SbxVariable *pSbxVariable = rPar.Get32(1);
410 pSbxVariable->Get( aVals );
412 else
414 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
416 rPar.Get32(0)->Put( aVals );
419 void SbRtl_CVErr(StarBASIC *, SbxArray & rPar, bool)
421 sal_Int16 nErrCode = 0;
422 if ( rPar.Count32() == 2 )
424 SbxVariable *pSbxVariable = rPar.Get32(1);
425 nErrCode = pSbxVariable->GetInteger();
427 else
429 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
431 rPar.Get32(0)->PutErr( nErrCode );
434 void SbRtl_Iif(StarBASIC *, SbxArray & rPar, bool) // JSM
436 if ( rPar.Count32() == 4 )
438 if (rPar.Get32(1)->GetBool())
440 *rPar.Get32(0) = *rPar.Get32(2);
442 else
444 *rPar.Get32(0) = *rPar.Get32(3);
447 else
449 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
453 void SbRtl_GetSystemType(StarBASIC *, SbxArray & rPar, bool)
455 if ( rPar.Count32() != 1 )
457 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
459 else
461 // Removed for SRC595
462 rPar.Get32(0)->PutInteger( -1 );
466 void SbRtl_GetGUIType(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
468 (void)pBasic;
469 (void)bWrite;
471 if ( rPar.Count32() != 1 )
473 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
475 else
477 // 17.7.2000 Make simple solution for testtool / fat office
478 #if defined(_WIN32)
479 rPar.Get32(0)->PutInteger( 1 );
480 #elif defined(UNX)
481 rPar.Get32(0)->PutInteger( 4 );
482 #else
483 rPar.Get32(0)->PutInteger( -1 );
484 #endif
488 void SbRtl_Red(StarBASIC *, SbxArray & rPar, bool)
490 if ( rPar.Count32() != 2 )
492 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
494 else
496 sal_Int32 nRGB = rPar.Get32(1)->GetLong();
497 nRGB &= 0x00FF0000;
498 nRGB >>= 16;
499 rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
503 void SbRtl_Green(StarBASIC *, SbxArray & rPar, bool)
505 if ( rPar.Count32() != 2 )
507 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
509 else
511 sal_Int32 nRGB = rPar.Get32(1)->GetLong();
512 nRGB &= 0x0000FF00;
513 nRGB >>= 8;
514 rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
518 void SbRtl_Blue(StarBASIC *, SbxArray & rPar, bool)
520 if ( rPar.Count32() != 2 )
522 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
524 else
526 sal_Int32 nRGB = rPar.Get32(1)->GetLong();
527 nRGB &= 0x000000FF;
528 rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
533 void SbRtl_Switch(StarBASIC *, SbxArray & rPar, bool)
535 sal_uInt32 nCount = rPar.Count32();
536 if( !(nCount & 0x0001 ))
538 // number of arguments must be odd
539 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
541 sal_uInt32 nCurExpr = 1;
542 while( nCurExpr < (nCount-1) )
544 if( rPar.Get32( nCurExpr )->GetBool())
546 (*rPar.Get32(0)) = *(rPar.Get32(nCurExpr+1));
547 return;
549 nCurExpr += 2;
551 rPar.Get32(0)->PutNull();
554 //i#64882# Common wait impl for existing Wait and new WaitUntil
555 // rtl functions
556 void Wait_Impl( bool bDurationBased, SbxArray& rPar )
558 if( rPar.Count32() != 2 )
560 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
561 return;
563 tools::Long nWait = 0;
564 if ( bDurationBased )
566 double dWait = rPar.Get32(1)->GetDouble();
567 double dNow = Now_Impl();
568 double dSecs = ( dWait - dNow ) * 24.0 * 3600.0;
569 nWait = static_cast<tools::Long>( dSecs * 1000 ); // wait in thousands of sec
571 else
573 nWait = rPar.Get32(1)->GetLong();
575 if( nWait < 0 )
577 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
578 return;
581 Timer aTimer;
582 aTimer.SetTimeout( nWait );
583 aTimer.Start();
584 while ( aTimer.IsActive() )
586 Application::Yield();
590 //i#64882#
591 void SbRtl_Wait(StarBASIC *, SbxArray & rPar, bool)
593 Wait_Impl( false, rPar );
596 //i#64882# add new WaitUntil ( for application.wait )
597 // share wait_impl with 'normal' oobasic wait
598 void SbRtl_WaitUntil(StarBASIC *, SbxArray & rPar, bool)
600 Wait_Impl( true, rPar );
603 void SbRtl_DoEvents(StarBASIC *, SbxArray & rPar, bool)
605 // don't understand what upstream are up to
606 // we already process application events etc. in between
607 // basic runtime pcode ( on a timed basis )
608 // always return 0
609 rPar.Get32(0)->PutInteger( 0 );
610 Application::Reschedule( true );
613 void SbRtl_GetGUIVersion(StarBASIC *, SbxArray & rPar, bool)
615 if ( rPar.Count32() != 1 )
617 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
619 else
621 // Removed for SRC595
622 rPar.Get32(0)->PutLong( -1 );
626 void SbRtl_Choose(StarBASIC *, SbxArray & rPar, bool)
628 if ( rPar.Count32() < 2 )
630 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
632 sal_Int16 nIndex = rPar.Get32(1)->GetInteger();
633 sal_uInt32 nCount = rPar.Count32();
634 nCount--;
635 if( nCount == 1 || nIndex > sal::static_int_cast<sal_Int16>(nCount-1) || nIndex < 1 )
637 rPar.Get32(0)->PutNull();
638 return;
640 (*rPar.Get32(0)) = *(rPar.Get32(nIndex+1));
644 void SbRtl_Trim(StarBASIC *, SbxArray & rPar, bool)
646 if ( rPar.Count32() < 2 )
648 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
650 else
652 OUString aStr(comphelper::string::strip(rPar.Get32(1)->GetOUString(), ' '));
653 rPar.Get32(0)->PutString(aStr);
657 void SbRtl_GetSolarVersion(StarBASIC *, SbxArray & rPar, bool)
659 rPar.Get32(0)->PutLong( LIBO_VERSION_MAJOR * 10000 + LIBO_VERSION_MINOR * 100 + LIBO_VERSION_MICRO * 1);
662 void SbRtl_TwipsPerPixelX(StarBASIC *, SbxArray & rPar, bool)
664 sal_Int32 nResult = 0;
665 Size aSize( 100,0 );
666 MapMode aMap( MapUnit::MapTwip );
667 OutputDevice* pDevice = Application::GetDefaultDevice();
668 if( pDevice )
670 aSize = pDevice->PixelToLogic( aSize, aMap );
671 nResult = aSize.Width() / 100;
673 rPar.Get32(0)->PutLong( nResult );
676 void SbRtl_TwipsPerPixelY(StarBASIC *, SbxArray & rPar, bool)
678 sal_Int32 nResult = 0;
679 Size aSize( 0,100 );
680 MapMode aMap( MapUnit::MapTwip );
681 OutputDevice* pDevice = Application::GetDefaultDevice();
682 if( pDevice )
684 aSize = pDevice->PixelToLogic( aSize, aMap );
685 nResult = aSize.Height() / 100;
687 rPar.Get32(0)->PutLong( nResult );
691 void SbRtl_FreeLibrary(StarBASIC *, SbxArray & rPar, bool)
693 if ( rPar.Count32() != 2 )
695 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
697 GetSbData()->pInst->GetDllMgr()->FreeDll( rPar.Get32(1)->GetOUString() );
699 bool IsBaseIndexOne()
701 bool bResult = false;
702 if ( GetSbData()->pInst && GetSbData()->pInst->pRun )
704 sal_uInt16 res = GetSbData()->pInst->pRun->GetBase();
705 if ( res )
707 bResult = true;
710 return bResult;
713 void SbRtl_Array(StarBASIC *, SbxArray & rPar, bool)
715 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
716 sal_uInt32 nArraySize = rPar.Count32() - 1;
717 bool bIncIndex = IsBaseIndexOne();
718 if( nArraySize )
720 if ( bIncIndex )
722 pArray->AddDim32( 1, sal::static_int_cast<sal_Int32>(nArraySize) );
724 else
726 pArray->AddDim32( 0, sal::static_int_cast<sal_Int32>(nArraySize) - 1 );
729 else
731 pArray->unoAddDim32( 0, -1 );
734 // insert parameters into the array
735 for( sal_uInt32 i = 0 ; i < nArraySize ; i++ )
737 SbxVariable* pVar = rPar.Get32(i+1);
738 SbxVariable* pNew = new SbxEnsureParentVariable(*pVar);
739 pNew->SetFlag( SbxFlagBits::Write );
740 sal_Int32 aIdx[1];
741 aIdx[0] = static_cast<sal_Int32>(i);
742 if ( bIncIndex )
744 ++aIdx[0];
746 pArray->Put32(pNew, aIdx);
749 // return array
750 SbxVariableRef refVar = rPar.Get32(0);
751 SbxFlagBits nFlags = refVar->GetFlags();
752 refVar->ResetFlag( SbxFlagBits::Fixed );
753 refVar->PutObject( pArray );
754 refVar->SetFlags( nFlags );
755 refVar->SetParameters( nullptr );
759 // Featurewish #57868
760 // The function returns a variant-array; if there are no parameters passed,
761 // an empty array is created (according to dim a(); equal to a sequence of
762 // the length 0 in Uno).
763 // If there are parameters passed, there's a dimension created for each of
764 // them; DimArray( 2, 2, 4 ) is equal to DIM a( 2, 2, 4 )
765 // the array is always of the type variant
766 void SbRtl_DimArray(StarBASIC *, SbxArray & rPar, bool)
768 SbxDimArray * pArray = new SbxDimArray( SbxVARIANT );
769 sal_uInt32 nArrayDims = rPar.Count32() - 1;
770 if( nArrayDims > 0 )
772 for( sal_uInt32 i = 0; i < nArrayDims ; i++ )
774 sal_Int32 ub = rPar.Get32(i+1)->GetLong();
775 if( ub < 0 )
777 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
778 ub = 0;
780 pArray->AddDim32( 0, ub );
783 else
785 pArray->unoAddDim32( 0, -1 );
787 SbxVariableRef refVar = rPar.Get32(0);
788 SbxFlagBits nFlags = refVar->GetFlags();
789 refVar->ResetFlag( SbxFlagBits::Fixed );
790 refVar->PutObject( pArray );
791 refVar->SetFlags( nFlags );
792 refVar->SetParameters( nullptr );
796 * FindObject and FindPropertyObject make it possible to
797 * address objects and properties of the type Object with
798 * their name as string-parameters at the runtime.
800 * Example:
801 * MyObj.Prop1.Bla = 5
803 * is equal to:
804 * dim ObjVar as Object
805 * dim ObjProp as Object
806 * ObjName$ = "MyObj"
807 * ObjVar = FindObject( ObjName$ )
808 * PropName$ = "Prop1"
809 * ObjProp = FindPropertyObject( ObjVar, PropName$ )
810 * ObjProp.Bla = 5
812 * The names can be created dynamically at the runtime
813 * so that e. g. via controls "TextEdit1" to "TextEdit5"
814 * can be iterated in a dialog in a loop.
818 // 1st parameter = the object's name as string
819 void SbRtl_FindObject(StarBASIC *, SbxArray & rPar, bool)
821 if ( rPar.Count32() < 2 )
823 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
824 return;
827 OUString aNameStr = rPar.Get32(1)->GetOUString();
829 SbxBase* pFind = StarBASIC::FindSBXInCurrentScope( aNameStr );
830 SbxObject* pFindObj = nullptr;
831 if( pFind )
833 pFindObj = dynamic_cast<SbxObject*>( pFind );
835 SbxVariableRef refVar = rPar.Get32(0);
836 refVar->PutObject( pFindObj );
839 // address object-property in an object
840 // 1st parameter = object
841 // 2nd parameter = the property's name as string
842 void SbRtl_FindPropertyObject(StarBASIC *, SbxArray & rPar, bool)
844 if ( rPar.Count32() < 3 )
846 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
847 return;
850 SbxBase* pObjVar = rPar.Get32(1)->GetObject();
851 SbxObject* pObj = nullptr;
852 if( pObjVar )
854 pObj = dynamic_cast<SbxObject*>( pObjVar );
856 if( !pObj )
857 if (auto pSbxVar = dynamic_cast<const SbxVariable*>( pObjVar))
858 pObj = dynamic_cast<SbxObject*>( pSbxVar->GetObject() );
860 OUString aNameStr = rPar.Get32(2)->GetOUString();
862 SbxObject* pFindObj = nullptr;
863 if( pObj )
865 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::Object );
866 pFindObj = dynamic_cast<SbxObject*>( pFindVar );
868 else
870 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
873 SbxVariableRef refVar = rPar.Get32(0);
874 refVar->PutObject( pFindObj );
878 static bool lcl_WriteSbxVariable( const SbxVariable& rVar, SvStream* pStrm,
879 bool bBinary, short nBlockLen, bool bIsArray )
881 sal_uInt64 const nFPos = pStrm->Tell();
883 bool bIsVariant = !rVar.IsFixed();
884 SbxDataType eType = rVar.GetType();
886 switch( eType )
888 case SbxBOOL:
889 case SbxCHAR:
890 case SbxBYTE:
891 if( bIsVariant )
893 pStrm->WriteUInt16( SbxBYTE ); // VarType Id
895 pStrm->WriteUChar( rVar.GetByte() );
896 break;
898 case SbxEMPTY:
899 case SbxNULL:
900 case SbxVOID:
901 case SbxINTEGER:
902 case SbxUSHORT:
903 case SbxINT:
904 case SbxUINT:
905 if( bIsVariant )
907 pStrm->WriteUInt16( SbxINTEGER ); // VarType Id
909 pStrm->WriteInt16( rVar.GetInteger() );
910 break;
912 case SbxLONG:
913 case SbxULONG:
914 if( bIsVariant )
916 pStrm->WriteUInt16( SbxLONG ); // VarType Id
918 pStrm->WriteInt32( rVar.GetLong() );
919 break;
920 case SbxSALINT64:
921 case SbxSALUINT64:
922 if( bIsVariant )
924 pStrm->WriteUInt16( SbxSALINT64 ); // VarType Id
926 pStrm->WriteUInt64( rVar.GetInt64() );
927 break;
928 case SbxSINGLE:
929 if( bIsVariant )
931 pStrm->WriteUInt16( eType ); // VarType Id
933 pStrm->WriteFloat( rVar.GetSingle() );
934 break;
936 case SbxDOUBLE:
937 case SbxCURRENCY:
938 case SbxDATE:
939 if( bIsVariant )
941 pStrm->WriteUInt16( eType ); // VarType Id
943 pStrm->WriteDouble( rVar.GetDouble() );
944 break;
946 case SbxSTRING:
947 case SbxLPSTR:
949 const OUString& rStr = rVar.GetOUString();
950 if( !bBinary || bIsArray )
952 if( bIsVariant )
954 pStrm->WriteUInt16( SbxSTRING );
956 pStrm->WriteUniOrByteString( rStr, osl_getThreadTextEncoding() );
958 else
960 // without any length information! without end-identifier!
961 // What does that mean for Unicode?! Choosing conversion to ByteString...
962 OString aByteStr(OUStringToOString(rStr, osl_getThreadTextEncoding()));
963 pStrm->WriteOString( aByteStr );
966 break;
968 default:
969 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
970 return false;
973 if( nBlockLen )
975 pStrm->Seek( nFPos + nBlockLen );
977 return pStrm->GetErrorCode() == ERRCODE_NONE;
980 static bool lcl_ReadSbxVariable( SbxVariable& rVar, SvStream* pStrm,
981 bool bBinary, short nBlockLen )
983 double aDouble;
985 sal_uInt64 const nFPos = pStrm->Tell();
987 bool bIsVariant = !rVar.IsFixed();
988 SbxDataType eVarType = rVar.GetType();
990 SbxDataType eSrcType = eVarType;
991 if( bIsVariant )
993 sal_uInt16 nTemp;
994 pStrm->ReadUInt16( nTemp );
995 eSrcType = static_cast<SbxDataType>(nTemp);
998 switch( eSrcType )
1000 case SbxBOOL:
1001 case SbxCHAR:
1002 case SbxBYTE:
1004 sal_uInt8 aByte;
1005 pStrm->ReadUChar( aByte );
1007 if( bBinary && SbiRuntime::isVBAEnabled() && aByte == 1 && pStrm->eof() )
1009 aByte = 0;
1011 rVar.PutByte( aByte );
1013 break;
1015 case SbxEMPTY:
1016 case SbxNULL:
1017 case SbxVOID:
1018 case SbxINTEGER:
1019 case SbxUSHORT:
1020 case SbxINT:
1021 case SbxUINT:
1023 sal_Int16 aInt;
1024 pStrm->ReadInt16( aInt );
1025 rVar.PutInteger( aInt );
1027 break;
1029 case SbxLONG:
1030 case SbxULONG:
1032 sal_Int32 aInt;
1033 pStrm->ReadInt32( aInt );
1034 rVar.PutLong( aInt );
1036 break;
1037 case SbxSALINT64:
1038 case SbxSALUINT64:
1040 sal_uInt32 aInt;
1041 pStrm->ReadUInt32( aInt );
1042 rVar.PutInt64( static_cast<sal_Int64>(aInt) );
1044 break;
1045 case SbxSINGLE:
1047 float nS;
1048 pStrm->ReadFloat( nS );
1049 rVar.PutSingle( nS );
1051 break;
1053 case SbxDOUBLE:
1054 case SbxCURRENCY:
1056 pStrm->ReadDouble( aDouble );
1057 rVar.PutDouble( aDouble );
1059 break;
1061 case SbxDATE:
1063 pStrm->ReadDouble( aDouble );
1064 rVar.PutDate( aDouble );
1066 break;
1068 case SbxSTRING:
1069 case SbxLPSTR:
1071 OUString aStr = pStrm->ReadUniOrByteString(osl_getThreadTextEncoding());
1072 rVar.PutString( aStr );
1074 break;
1076 default:
1077 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1078 return false;
1081 if( nBlockLen )
1083 pStrm->Seek( nFPos + nBlockLen );
1085 return pStrm->GetErrorCode() == ERRCODE_NONE;
1089 // nCurDim = 1...n
1090 static bool lcl_WriteReadSbxArray( SbxDimArray& rArr, SvStream* pStrm,
1091 bool bBinary, sal_Int32 nCurDim, sal_Int32* pOtherDims, bool bWrite )
1093 SAL_WARN_IF( nCurDim <= 0,"basic", "Bad Dim");
1094 sal_Int32 nLower, nUpper;
1095 if( !rArr.GetDim32( nCurDim, nLower, nUpper ) )
1096 return false;
1097 for(sal_Int32 nCur = nLower; nCur <= nUpper; nCur++ )
1099 pOtherDims[ nCurDim-1 ] = nCur;
1100 if( nCurDim != 1 )
1101 lcl_WriteReadSbxArray(rArr, pStrm, bBinary, nCurDim-1, pOtherDims, bWrite);
1102 else
1104 SbxVariable* pVar = rArr.Get32( pOtherDims );
1105 bool bRet;
1106 if( bWrite )
1107 bRet = lcl_WriteSbxVariable(*pVar, pStrm, bBinary, 0, true );
1108 else
1109 bRet = lcl_ReadSbxVariable(*pVar, pStrm, bBinary, 0 );
1110 if( !bRet )
1111 return false;
1114 return true;
1117 static void PutGet( SbxArray& rPar, bool bPut )
1119 if ( rPar.Count32() != 4 )
1121 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1122 return;
1124 sal_Int16 nFileNo = rPar.Get32(1)->GetInteger();
1125 SbxVariable* pVar2 = rPar.Get32(2);
1126 SbxDataType eType2 = pVar2->GetType();
1127 bool bHasRecordNo = (eType2 != SbxEMPTY && eType2 != SbxERROR);
1128 tools::Long nRecordNo = pVar2->GetLong();
1129 if ( nFileNo < 1 || ( bHasRecordNo && nRecordNo < 1 ) )
1131 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1132 return;
1134 nRecordNo--;
1135 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
1136 SbiStream* pSbStrm = pIO->GetStream( nFileNo );
1138 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Random)) )
1140 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
1141 return;
1144 SvStream* pStrm = pSbStrm->GetStrm();
1145 bool bRandom = pSbStrm->IsRandom();
1146 short nBlockLen = bRandom ? pSbStrm->GetBlockLen() : 0;
1148 if( bPut )
1150 pSbStrm->ExpandFile();
1153 if( bHasRecordNo )
1155 sal_uInt64 const nFilePos = bRandom
1156 ? static_cast<sal_uInt64>(nBlockLen * nRecordNo)
1157 : static_cast<sal_uInt64>(nRecordNo);
1158 pStrm->Seek( nFilePos );
1161 SbxDimArray* pArr = nullptr;
1162 SbxVariable* pVar = rPar.Get32(3);
1163 if( pVar->GetType() & SbxARRAY )
1165 SbxBase* pParObj = pVar->GetObject();
1166 pArr = dynamic_cast<SbxDimArray*>( pParObj );
1169 bool bRet;
1171 if( pArr )
1173 sal_uInt64 const nFPos = pStrm->Tell();
1174 sal_Int32 nDims = pArr->GetDims32();
1175 std::unique_ptr<sal_Int32[]> pDims(new sal_Int32[ nDims ]);
1176 bRet = lcl_WriteReadSbxArray(*pArr,pStrm,!bRandom,nDims,pDims.get(),bPut);
1177 pDims.reset();
1178 if( nBlockLen )
1179 pStrm->Seek( nFPos + nBlockLen );
1181 else
1183 if( bPut )
1184 bRet = lcl_WriteSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, false);
1185 else
1186 bRet = lcl_ReadSbxVariable(*pVar, pStrm, !bRandom, nBlockLen);
1188 if( !bRet || pStrm->GetErrorCode() )
1189 StarBASIC::Error( ERRCODE_BASIC_IO_ERROR );
1192 void SbRtl_Put(StarBASIC *, SbxArray & rPar, bool)
1194 PutGet( rPar, true );
1197 void SbRtl_Get(StarBASIC *, SbxArray & rPar, bool)
1199 PutGet( rPar, false );
1202 void SbRtl_Environ(StarBASIC *, SbxArray & rPar, bool)
1204 if ( rPar.Count32() != 2 )
1206 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1207 return;
1209 OUString aResult;
1210 // should be ANSI but that's not possible under Win16 in the DLL
1211 OString aByteStr(OUStringToOString(rPar.Get32(1)->GetOUString(),
1212 osl_getThreadTextEncoding()));
1213 const char* pEnvStr = getenv(aByteStr.getStr());
1214 if ( pEnvStr )
1216 aResult = OUString(pEnvStr, strlen(pEnvStr), osl_getThreadTextEncoding());
1218 rPar.Get32(0)->PutString( aResult );
1221 static double GetDialogZoomFactor( bool bX, tools::Long nValue )
1223 OutputDevice* pDevice = Application::GetDefaultDevice();
1224 double nResult = 0;
1225 if( pDevice )
1227 Size aRefSize( nValue, nValue );
1228 Fraction aFracX( 1, 26 );
1229 Fraction aFracY( 1, 24 );
1230 MapMode aMap( MapUnit::MapAppFont, Point(), aFracX, aFracY );
1231 Size aScaledSize = pDevice->LogicToPixel( aRefSize, aMap );
1232 aRefSize = pDevice->LogicToPixel( aRefSize, MapMode(MapUnit::MapTwip) );
1234 double nRef, nScaled;
1235 if( bX )
1237 nRef = aRefSize.Width();
1238 nScaled = aScaledSize.Width();
1240 else
1242 nRef = aRefSize.Height();
1243 nScaled = aScaledSize.Height();
1245 nResult = nScaled / nRef;
1247 return nResult;
1251 void SbRtl_GetDialogZoomFactorX(StarBASIC *, SbxArray & rPar, bool)
1253 if ( rPar.Count32() != 2 )
1255 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1256 return;
1258 rPar.Get32(0)->PutDouble( GetDialogZoomFactor( true, rPar.Get32(1)->GetLong() ));
1261 void SbRtl_GetDialogZoomFactorY(StarBASIC *, SbxArray & rPar, bool)
1263 if ( rPar.Count32() != 2 )
1265 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1266 return;
1268 rPar.Get32(0)->PutDouble( GetDialogZoomFactor( false, rPar.Get32(1)->GetLong()));
1272 void SbRtl_EnableReschedule(StarBASIC *, SbxArray & rPar, bool)
1274 rPar.Get32(0)->PutEmpty();
1275 if ( rPar.Count32() != 2 )
1276 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1277 if( GetSbData()->pInst )
1278 GetSbData()->pInst->EnableReschedule( rPar.Get32(1)->GetBool() );
1281 void SbRtl_GetSystemTicks(StarBASIC *, SbxArray & rPar, bool)
1283 if ( rPar.Count32() != 1 )
1285 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1286 return;
1288 rPar.Get32(0)->PutLong( tools::Time::GetSystemTicks() );
1291 void SbRtl_GetPathSeparator(StarBASIC *, SbxArray & rPar, bool)
1293 if ( rPar.Count32() != 1 )
1295 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1296 return;
1298 rPar.Get32(0)->PutString( OUString( SAL_PATHDELIMITER ) );
1301 void SbRtl_ResolvePath(StarBASIC *, SbxArray & rPar, bool)
1303 if ( rPar.Count32() == 2 )
1305 OUString aStr = rPar.Get32(1)->GetOUString();
1306 rPar.Get32(0)->PutString( aStr );
1308 else
1310 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1314 void SbRtl_TypeLen(StarBASIC *, SbxArray & rPar, bool)
1316 if ( rPar.Count32() != 2 )
1318 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1320 else
1322 SbxDataType eType = rPar.Get32(1)->GetType();
1323 sal_Int16 nLen = 0;
1324 switch( eType )
1326 case SbxEMPTY:
1327 case SbxNULL:
1328 case SbxVECTOR:
1329 case SbxARRAY:
1330 case SbxBYREF:
1331 case SbxVOID:
1332 case SbxHRESULT:
1333 case SbxPOINTER:
1334 case SbxDIMARRAY:
1335 case SbxCARRAY:
1336 case SbxUSERDEF:
1337 nLen = 0;
1338 break;
1340 case SbxINTEGER:
1341 case SbxERROR:
1342 case SbxUSHORT:
1343 case SbxINT:
1344 case SbxUINT:
1345 nLen = 2;
1346 break;
1348 case SbxLONG:
1349 case SbxSINGLE:
1350 case SbxULONG:
1351 nLen = 4;
1352 break;
1354 case SbxDOUBLE:
1355 case SbxCURRENCY:
1356 case SbxDATE:
1357 case SbxSALINT64:
1358 case SbxSALUINT64:
1359 nLen = 8;
1360 break;
1362 case SbxOBJECT:
1363 case SbxVARIANT:
1364 case SbxDATAOBJECT:
1365 nLen = 0;
1366 break;
1368 case SbxCHAR:
1369 case SbxBYTE:
1370 case SbxBOOL:
1371 nLen = 1;
1372 break;
1374 case SbxLPSTR:
1375 case SbxLPWSTR:
1376 case SbxCoreSTRING:
1377 case SbxSTRING:
1378 nLen = static_cast<sal_Int16>(rPar.Get32(1)->GetOUString().getLength());
1379 break;
1381 default:
1382 nLen = 0;
1383 break;
1385 rPar.Get32(0)->PutInteger( nLen );
1390 // 1st parameter == class name, other parameters for initialisation
1391 void SbRtl_CreateUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1393 RTL_Impl_CreateUnoStruct( rPar );
1397 // 1st parameter == service-name
1398 void SbRtl_CreateUnoService(StarBASIC *, SbxArray & rPar, bool)
1400 RTL_Impl_CreateUnoService( rPar );
1403 void SbRtl_CreateUnoServiceWithArguments(StarBASIC *, SbxArray & rPar, bool)
1405 RTL_Impl_CreateUnoServiceWithArguments( rPar );
1409 void SbRtl_CreateUnoValue(StarBASIC *, SbxArray & rPar, bool)
1411 RTL_Impl_CreateUnoValue( rPar );
1415 // no parameters
1416 void SbRtl_GetProcessServiceManager(StarBASIC *, SbxArray & rPar, bool)
1418 RTL_Impl_GetProcessServiceManager( rPar );
1422 // 1st parameter == Sequence<PropertyValue>
1423 void SbRtl_CreatePropertySet(StarBASIC *, SbxArray & rPar, bool)
1425 RTL_Impl_CreatePropertySet( rPar );
1429 // multiple interface-names as parameters
1430 void SbRtl_HasUnoInterfaces(StarBASIC *, SbxArray & rPar, bool)
1432 RTL_Impl_HasInterfaces( rPar );
1436 void SbRtl_IsUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1438 RTL_Impl_IsUnoStruct( rPar );
1442 void SbRtl_EqualUnoObjects(StarBASIC *, SbxArray & rPar, bool)
1444 RTL_Impl_EqualUnoObjects( rPar );
1447 void SbRtl_CreateUnoDialog(StarBASIC *, SbxArray & rPar, bool)
1449 RTL_Impl_CreateUnoDialog( rPar );
1452 // Return the application standard lib as root scope
1453 void SbRtl_GlobalScope(StarBASIC * pBasic, SbxArray & rPar, bool)
1455 SbxObject* p = pBasic;
1456 while( p->GetParent() )
1458 p = p->GetParent();
1460 SbxVariableRef refVar = rPar.Get32(0);
1461 refVar->PutObject( p );
1464 // Helper functions to convert Url from/to system paths
1465 void SbRtl_ConvertToUrl(StarBASIC *, SbxArray & rPar, bool)
1467 if ( rPar.Count32() == 2 )
1469 OUString aStr = rPar.Get32(1)->GetOUString();
1470 INetURLObject aURLObj( aStr, INetProtocol::File );
1471 OUString aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1472 if( aFileURL.isEmpty() )
1474 osl::File::getFileURLFromSystemPath(aStr, aFileURL);
1476 if( aFileURL.isEmpty() )
1478 aFileURL = aStr;
1480 rPar.Get32(0)->PutString(aFileURL);
1482 else
1484 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1488 void SbRtl_ConvertFromUrl(StarBASIC *, SbxArray & rPar, bool)
1490 if ( rPar.Count32() == 2 )
1492 OUString aStr = rPar.Get32(1)->GetOUString();
1493 OUString aSysPath;
1494 ::osl::File::getSystemPathFromFileURL( aStr, aSysPath );
1495 if( aSysPath.isEmpty() )
1497 aSysPath = aStr;
1499 rPar.Get32(0)->PutString(aSysPath);
1501 else
1503 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1508 // Provide DefaultContext
1509 void SbRtl_GetDefaultContext(StarBASIC *, SbxArray & rPar, bool)
1511 RTL_Impl_GetDefaultContext( rPar );
1514 void SbRtl_Join(StarBASIC *, SbxArray & rPar, bool)
1516 sal_uInt32 nParCount = rPar.Count32();
1517 if ( nParCount != 3 && nParCount != 2 )
1519 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1520 return;
1522 SbxBase* pParObj = rPar.Get32(1)->GetObject();
1523 SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
1524 if( pArr )
1526 if( pArr->GetDims32() != 1 )
1528 StarBASIC::Error( ERRCODE_BASIC_WRONG_DIMS ); // Syntax Error?!
1529 return;
1531 OUString aDelim;
1532 if( nParCount == 3 )
1534 aDelim = rPar.Get32(2)->GetOUString();
1536 else
1538 aDelim = " ";
1540 OUStringBuffer aRetStr(32);
1541 sal_Int32 nLower, nUpper;
1542 pArr->GetDim32( 1, nLower, nUpper );
1543 sal_Int32 aIdx[1];
1544 for (aIdx[0] = nLower; aIdx[0] <= nUpper; ++aIdx[0])
1546 OUString aStr = pArr->Get32(aIdx)->GetOUString();
1547 aRetStr.append(aStr);
1548 if (aIdx[0] != nUpper)
1550 aRetStr.append(aDelim);
1553 rPar.Get32(0)->PutString( aRetStr.makeStringAndClear() );
1555 else
1557 StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );
1562 void SbRtl_Split(StarBASIC *, SbxArray & rPar, bool)
1564 sal_uInt32 nParCount = rPar.Count32();
1565 if ( nParCount < 2 )
1567 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1568 return;
1571 OUString aExpression = rPar.Get32(1)->GetOUString();
1572 sal_Int32 nArraySize = 0;
1573 std::vector< OUString > vRet;
1574 if( !aExpression.isEmpty() )
1576 OUString aDelim;
1577 if( nParCount >= 3 )
1579 aDelim = rPar.Get32(2)->GetOUString();
1581 else
1583 aDelim = " ";
1586 sal_Int32 nCount = -1;
1587 if( nParCount == 4 )
1589 nCount = rPar.Get32(3)->GetLong();
1591 sal_Int32 nDelimLen = aDelim.getLength();
1592 if( nDelimLen )
1594 sal_Int32 iSearch = -1;
1595 sal_Int32 iStart = 0;
1598 bool bBreak = false;
1599 if( nCount >= 0 && nArraySize == nCount - 1 )
1601 bBreak = true;
1603 iSearch = aExpression.indexOf( aDelim, iStart );
1604 OUString aSubStr;
1605 if( iSearch >= 0 && !bBreak )
1607 aSubStr = aExpression.copy( iStart, iSearch - iStart );
1608 iStart = iSearch + nDelimLen;
1610 else
1612 aSubStr = aExpression.copy( iStart );
1614 vRet.push_back( aSubStr );
1615 nArraySize++;
1617 if( bBreak )
1619 break;
1622 while( iSearch >= 0 );
1624 else
1626 vRet.push_back( aExpression );
1627 nArraySize = 1;
1631 // tdf#123025 - split returns an array of substrings
1632 SbxDimArray* pArray = new SbxDimArray( SbxSTRING );
1633 pArray->unoAddDim32( 0, nArraySize-1 );
1635 // insert parameter(s) into the array
1636 for(sal_Int32 i = 0 ; i < nArraySize ; i++ )
1638 // tdf#123025 - split returns an array of substrings
1639 SbxVariableRef xVar = new SbxVariable( SbxSTRING );
1640 xVar->PutString( vRet[i] );
1641 pArray->Put32( xVar.get(), &i );
1644 // return array
1645 SbxVariableRef refVar = rPar.Get32(0);
1646 SbxFlagBits nFlags = refVar->GetFlags();
1647 refVar->ResetFlag( SbxFlagBits::Fixed );
1648 refVar->PutObject( pArray );
1649 refVar->SetFlags( nFlags );
1650 refVar->SetParameters( nullptr );
1653 // MonthName(month[, abbreviate])
1654 void SbRtl_MonthName(StarBASIC *, SbxArray & rPar, bool)
1656 sal_uInt32 nParCount = rPar.Count32();
1657 if( nParCount != 2 && nParCount != 3 )
1659 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1660 return;
1663 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1664 if( !xCalendar.is() )
1666 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
1667 return;
1669 Sequence< CalendarItem2 > aMonthSeq = xCalendar->getMonths2();
1670 sal_Int32 nMonthCount = aMonthSeq.getLength();
1672 sal_Int16 nVal = rPar.Get32(1)->GetInteger();
1673 if( nVal < 1 || nVal > nMonthCount )
1675 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1676 return;
1679 bool bAbbreviate = false;
1680 if( nParCount == 3 )
1681 bAbbreviate = rPar.Get32(2)->GetBool();
1683 const CalendarItem2* pCalendarItems = aMonthSeq.getConstArray();
1684 const CalendarItem2& rItem = pCalendarItems[nVal - 1];
1686 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1687 rPar.Get32(0)->PutString(aRetStr);
1690 // WeekdayName(weekday, abbreviate, firstdayofweek)
1691 void SbRtl_WeekdayName(StarBASIC *, SbxArray & rPar, bool)
1693 sal_uInt32 nParCount = rPar.Count32();
1694 if( nParCount < 2 || nParCount > 4 )
1696 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1697 return;
1700 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1701 if( !xCalendar.is() )
1703 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
1704 return;
1707 Sequence< CalendarItem2 > aDaySeq = xCalendar->getDays2();
1708 sal_Int16 nDayCount = static_cast<sal_Int16>(aDaySeq.getLength());
1709 sal_Int16 nDay = rPar.Get32(1)->GetInteger();
1710 sal_Int16 nFirstDay = 0;
1711 if( nParCount == 4 )
1713 nFirstDay = rPar.Get32(3)->GetInteger();
1714 if( nFirstDay < 0 || nFirstDay > 7 )
1716 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1717 return;
1720 if( nFirstDay == 0 )
1722 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
1724 nDay = 1 + (nDay + nDayCount + nFirstDay - 2) % nDayCount;
1725 if( nDay < 1 || nDay > nDayCount )
1727 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1728 return;
1731 bool bAbbreviate = false;
1732 if( nParCount >= 3 )
1734 SbxVariable* pPar2 = rPar.Get32(2);
1735 if( !pPar2->IsErr() )
1737 bAbbreviate = pPar2->GetBool();
1741 const CalendarItem2* pCalendarItems = aDaySeq.getConstArray();
1742 const CalendarItem2& rItem = pCalendarItems[nDay - 1];
1744 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1745 rPar.Get32(0)->PutString( aRetStr );
1748 void SbRtl_Weekday(StarBASIC *, SbxArray & rPar, bool)
1750 sal_uInt32 nParCount = rPar.Count32();
1751 if ( nParCount < 2 )
1753 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1755 else
1757 double aDate = rPar.Get32(1)->GetDate();
1759 bool bFirstDay = false;
1760 sal_Int16 nFirstDay = 0;
1761 if ( nParCount > 2 )
1763 nFirstDay = rPar.Get32(2)->GetInteger();
1764 bFirstDay = true;
1766 sal_Int16 nDay = implGetWeekDay( aDate, bFirstDay, nFirstDay );
1767 rPar.Get32(0)->PutInteger( nDay );
1771 namespace {
1773 enum Interval
1775 INTERVAL_YYYY,
1776 INTERVAL_Q,
1777 INTERVAL_M,
1778 INTERVAL_Y,
1779 INTERVAL_D,
1780 INTERVAL_W,
1781 INTERVAL_WW,
1782 INTERVAL_H,
1783 INTERVAL_N,
1784 INTERVAL_S
1787 struct IntervalInfo
1789 Interval meInterval;
1790 char const * mStringCode;
1791 double mdValue;
1792 bool mbSimple;
1797 static IntervalInfo const * getIntervalInfo( const OUString& rStringCode )
1799 static IntervalInfo const aIntervalTable[] =
1801 { INTERVAL_YYYY, "yyyy", 0.0, false }, // Year
1802 { INTERVAL_Q, "q", 0.0, false }, // Quarter
1803 { INTERVAL_M, "m", 0.0, false }, // Month
1804 { INTERVAL_Y, "y", 1.0, true }, // Day of year
1805 { INTERVAL_D, "d", 1.0, true }, // Day
1806 { INTERVAL_W, "w", 1.0, true }, // Weekday
1807 { INTERVAL_WW, "ww", 7.0, true }, // Week
1808 { INTERVAL_H, "h", 1.0 / 24.0, true }, // Hour
1809 { INTERVAL_N, "n", 1.0 / 1440.0, true }, // Minute
1810 { INTERVAL_S, "s", 1.0 / 86400.0, true } // Second
1812 for( std::size_t i = 0; i != SAL_N_ELEMENTS(aIntervalTable); ++i )
1814 if( rStringCode.equalsIgnoreAsciiCaseAscii(
1815 aIntervalTable[i].mStringCode ) )
1817 return &aIntervalTable[i];
1820 return nullptr;
1823 static void implGetDayMonthYear( sal_Int16& rnYear, sal_Int16& rnMonth, sal_Int16& rnDay, double dDate )
1825 rnDay = implGetDateDay( dDate );
1826 rnMonth = implGetDateMonth( dDate );
1827 rnYear = implGetDateYear( dDate );
1830 /** Limits a date to valid dates within tools' class Date capabilities.
1832 @return the year number, truncated if necessary and in that case also
1833 rMonth and rDay adjusted.
1835 static sal_Int16 limitDate( sal_Int32 n32Year, sal_Int16& rMonth, sal_Int16& rDay )
1837 if( n32Year > SAL_MAX_INT16 )
1839 n32Year = SAL_MAX_INT16;
1840 rMonth = 12;
1841 rDay = 31;
1843 else if( n32Year < SAL_MIN_INT16 )
1845 n32Year = SAL_MIN_INT16;
1846 rMonth = 1;
1847 rDay = 1;
1849 return static_cast<sal_Int16>(n32Year);
1852 void SbRtl_DateAdd(StarBASIC *, SbxArray & rPar, bool)
1854 sal_uInt32 nParCount = rPar.Count32();
1855 if( nParCount != 4 )
1857 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1858 return;
1861 OUString aStringCode = rPar.Get32(1)->GetOUString();
1862 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1863 if( !pInfo )
1865 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1866 return;
1869 sal_Int32 lNumber = rPar.Get32(2)->GetLong();
1870 double dDate = rPar.Get32(3)->GetDate();
1871 double dNewDate = 0;
1872 if( pInfo->mbSimple )
1874 double dAdd = pInfo->mdValue * lNumber;
1875 dNewDate = dDate + dAdd;
1877 else
1879 // Keep hours, minutes, seconds
1880 double dHoursMinutesSeconds = dDate - floor( dDate );
1882 bool bOk = true;
1883 sal_Int16 nYear, nMonth, nDay;
1884 sal_Int16 nTargetYear16 = 0, nTargetMonth = 0;
1885 implGetDayMonthYear( nYear, nMonth, nDay, dDate );
1886 switch( pInfo->meInterval )
1888 case INTERVAL_YYYY:
1890 sal_Int32 nTargetYear = lNumber + nYear;
1891 nTargetYear16 = limitDate( nTargetYear, nMonth, nDay );
1892 /* TODO: should the result be error if the date was limited? It never was. */
1893 nTargetMonth = nMonth;
1894 bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
1895 break;
1897 case INTERVAL_Q:
1898 case INTERVAL_M:
1900 bool bNeg = (lNumber < 0);
1901 if( bNeg )
1902 lNumber = -lNumber;
1903 sal_Int32 nYearsAdd;
1904 sal_Int16 nMonthAdd;
1905 if( pInfo->meInterval == INTERVAL_Q )
1907 nYearsAdd = lNumber / 4;
1908 nMonthAdd = static_cast<sal_Int16>( 3 * (lNumber % 4) );
1910 else
1912 nYearsAdd = lNumber / 12;
1913 nMonthAdd = static_cast<sal_Int16>( lNumber % 12 );
1916 sal_Int32 nTargetYear;
1917 if( bNeg )
1919 nTargetMonth = nMonth - nMonthAdd;
1920 if( nTargetMonth <= 0 )
1922 nTargetMonth += 12;
1923 nYearsAdd++;
1925 nTargetYear = static_cast<sal_Int32>(nYear) - nYearsAdd;
1927 else
1929 nTargetMonth = nMonth + nMonthAdd;
1930 if( nTargetMonth > 12 )
1932 nTargetMonth -= 12;
1933 nYearsAdd++;
1935 nTargetYear = static_cast<sal_Int32>(nYear) + nYearsAdd;
1937 nTargetYear16 = limitDate( nTargetYear, nTargetMonth, nDay );
1938 /* TODO: should the result be error if the date was limited? It never was. */
1939 bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
1940 break;
1942 default: break;
1945 if( bOk )
1946 dNewDate += dHoursMinutesSeconds;
1949 rPar.Get32(0)->PutDate( dNewDate );
1952 static double RoundImpl( double d )
1954 return ( d >= 0 ) ? floor( d + 0.5 ) : -floor( -d + 0.5 );
1957 void SbRtl_DateDiff(StarBASIC *, SbxArray & rPar, bool)
1959 // DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])
1961 sal_uInt32 nParCount = rPar.Count32();
1962 if( nParCount < 4 || nParCount > 6 )
1964 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1965 return;
1968 OUString aStringCode = rPar.Get32(1)->GetOUString();
1969 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1970 if( !pInfo )
1972 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1973 return;
1976 double dDate1 = rPar.Get32(2)->GetDate();
1977 double dDate2 = rPar.Get32(3)->GetDate();
1979 double dRet = 0.0;
1980 switch( pInfo->meInterval )
1982 case INTERVAL_YYYY:
1984 sal_Int16 nYear1 = implGetDateYear( dDate1 );
1985 sal_Int16 nYear2 = implGetDateYear( dDate2 );
1986 dRet = nYear2 - nYear1;
1987 break;
1989 case INTERVAL_Q:
1991 sal_Int16 nYear1 = implGetDateYear( dDate1 );
1992 sal_Int16 nYear2 = implGetDateYear( dDate2 );
1993 sal_Int16 nQ1 = 1 + (implGetDateMonth( dDate1 ) - 1) / 3;
1994 sal_Int16 nQ2 = 1 + (implGetDateMonth( dDate2 ) - 1) / 3;
1995 sal_Int16 nQGes1 = 4 * nYear1 + nQ1;
1996 sal_Int16 nQGes2 = 4 * nYear2 + nQ2;
1997 dRet = nQGes2 - nQGes1;
1998 break;
2000 case INTERVAL_M:
2002 sal_Int16 nYear1 = implGetDateYear( dDate1 );
2003 sal_Int16 nYear2 = implGetDateYear( dDate2 );
2004 sal_Int16 nMonth1 = implGetDateMonth( dDate1 );
2005 sal_Int16 nMonth2 = implGetDateMonth( dDate2 );
2006 sal_Int16 nMonthGes1 = 12 * nYear1 + nMonth1;
2007 sal_Int16 nMonthGes2 = 12 * nYear2 + nMonth2;
2008 dRet = nMonthGes2 - nMonthGes1;
2009 break;
2011 case INTERVAL_Y:
2012 case INTERVAL_D:
2014 double dDays1 = floor( dDate1 );
2015 double dDays2 = floor( dDate2 );
2016 dRet = dDays2 - dDays1;
2017 break;
2019 case INTERVAL_W:
2020 case INTERVAL_WW:
2022 double dDays1 = floor( dDate1 );
2023 double dDays2 = floor( dDate2 );
2024 if( pInfo->meInterval == INTERVAL_WW )
2026 sal_Int16 nFirstDay = 1; // Default
2027 if( nParCount >= 5 )
2029 nFirstDay = rPar.Get32(4)->GetInteger();
2030 if( nFirstDay < 0 || nFirstDay > 7 )
2032 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2033 return;
2035 if( nFirstDay == 0 )
2037 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
2038 if( !xCalendar.is() )
2040 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
2041 return;
2043 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
2046 sal_Int16 nDay1 = implGetWeekDay( dDate1 );
2047 sal_Int16 nDay1_Diff = nDay1 - nFirstDay;
2048 if( nDay1_Diff < 0 )
2049 nDay1_Diff += 7;
2050 dDays1 -= nDay1_Diff;
2052 sal_Int16 nDay2 = implGetWeekDay( dDate2 );
2053 sal_Int16 nDay2_Diff = nDay2 - nFirstDay;
2054 if( nDay2_Diff < 0 )
2055 nDay2_Diff += 7;
2056 dDays2 -= nDay2_Diff;
2059 double dDiff = dDays2 - dDays1;
2060 dRet = ( dDiff >= 0 ) ? floor( dDiff / 7.0 ) : -floor( -dDiff / 7.0 );
2061 break;
2063 case INTERVAL_H:
2065 dRet = RoundImpl( 24.0 * (dDate2 - dDate1) );
2066 break;
2068 case INTERVAL_N:
2070 dRet = RoundImpl( 1440.0 * (dDate2 - dDate1) );
2071 break;
2073 case INTERVAL_S:
2075 dRet = RoundImpl( 86400.0 * (dDate2 - dDate1) );
2076 break;
2079 rPar.Get32(0)->PutDouble( dRet );
2082 static double implGetDateOfFirstDayInFirstWeek
2083 ( sal_Int16 nYear, sal_Int16& nFirstDay, sal_Int16& nFirstWeek, bool* pbError = nullptr )
2085 ErrCode nError = ERRCODE_NONE;
2086 if( nFirstDay < 0 || nFirstDay > 7 )
2087 nError = ERRCODE_BASIC_BAD_ARGUMENT;
2089 if( nFirstWeek < 0 || nFirstWeek > 3 )
2090 nError = ERRCODE_BASIC_BAD_ARGUMENT;
2092 Reference< XCalendar4 > xCalendar;
2093 if( nFirstDay == 0 || nFirstWeek == 0 )
2095 xCalendar = getLocaleCalendar();
2096 if( !xCalendar.is() )
2097 nError = ERRCODE_BASIC_BAD_ARGUMENT;
2100 if( nError != ERRCODE_NONE )
2102 StarBASIC::Error( nError );
2103 if( pbError )
2104 *pbError = true;
2105 return 0.0;
2108 if( nFirstDay == 0 )
2109 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
2111 sal_Int16 nFirstWeekMinDays = 0; // Not used for vbFirstJan1 = default
2112 if( nFirstWeek == 0 )
2114 nFirstWeekMinDays = xCalendar->getMinimumNumberOfDaysForFirstWeek();
2115 if( nFirstWeekMinDays == 1 )
2117 nFirstWeekMinDays = 0;
2118 nFirstWeek = 1;
2120 else if( nFirstWeekMinDays == 4 )
2121 nFirstWeek = 2;
2122 else if( nFirstWeekMinDays == 7 )
2123 nFirstWeek = 3;
2125 else if( nFirstWeek == 2 )
2126 nFirstWeekMinDays = 4; // vbFirstFourDays
2127 else if( nFirstWeek == 3 )
2128 nFirstWeekMinDays = 7; // vbFirstFourDays
2130 double dBaseDate;
2131 implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
2133 sal_Int16 nWeekDay0101 = implGetWeekDay( dBaseDate );
2134 sal_Int16 nDayDiff = nWeekDay0101 - nFirstDay;
2135 if( nDayDiff < 0 )
2136 nDayDiff += 7;
2138 if( nFirstWeekMinDays )
2140 sal_Int16 nThisWeeksDaysInYearCount = 7 - nDayDiff;
2141 if( nThisWeeksDaysInYearCount < nFirstWeekMinDays )
2142 nDayDiff -= 7;
2144 double dRetDate = dBaseDate - nDayDiff;
2145 return dRetDate;
2148 void SbRtl_DatePart(StarBASIC *, SbxArray & rPar, bool)
2150 // DatePart(interval, date[,firstdayofweek[, firstweekofyear]])
2152 sal_uInt32 nParCount = rPar.Count32();
2153 if( nParCount < 3 || nParCount > 5 )
2155 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2156 return;
2159 OUString aStringCode = rPar.Get32(1)->GetOUString();
2160 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
2161 if( !pInfo )
2163 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2164 return;
2167 double dDate = rPar.Get32(2)->GetDate();
2169 sal_Int32 nRet = 0;
2170 switch( pInfo->meInterval )
2172 case INTERVAL_YYYY:
2174 nRet = implGetDateYear( dDate );
2175 break;
2177 case INTERVAL_Q:
2179 nRet = 1 + (implGetDateMonth( dDate ) - 1) / 3;
2180 break;
2182 case INTERVAL_M:
2184 nRet = implGetDateMonth( dDate );
2185 break;
2187 case INTERVAL_Y:
2189 sal_Int16 nYear = implGetDateYear( dDate );
2190 double dBaseDate;
2191 implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
2192 nRet = 1 + sal_Int32( dDate - dBaseDate );
2193 break;
2195 case INTERVAL_D:
2197 nRet = implGetDateDay( dDate );
2198 break;
2200 case INTERVAL_W:
2202 bool bFirstDay = false;
2203 sal_Int16 nFirstDay = 1; // Default
2204 if( nParCount >= 4 )
2206 nFirstDay = rPar.Get32(3)->GetInteger();
2207 bFirstDay = true;
2209 nRet = implGetWeekDay( dDate, bFirstDay, nFirstDay );
2210 break;
2212 case INTERVAL_WW:
2214 sal_Int16 nFirstDay = 1; // Default
2215 if( nParCount >= 4 )
2216 nFirstDay = rPar.Get32(3)->GetInteger();
2218 sal_Int16 nFirstWeek = 1; // Default
2219 if( nParCount == 5 )
2220 nFirstWeek = rPar.Get32(4)->GetInteger();
2222 sal_Int16 nYear = implGetDateYear( dDate );
2223 bool bError = false;
2224 double dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear, nFirstDay, nFirstWeek, &bError );
2225 if( !bError )
2227 if( dYearFirstDay > dDate )
2229 // Date belongs to last year's week
2230 dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear - 1, nFirstDay, nFirstWeek );
2232 else if( nFirstWeek != 1 )
2234 // Check if date belongs to next year
2235 double dNextYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear + 1, nFirstDay, nFirstWeek );
2236 if( dDate >= dNextYearFirstDay )
2237 dYearFirstDay = dNextYearFirstDay;
2240 // Calculate week
2241 double dDiff = dDate - dYearFirstDay;
2242 nRet = 1 + sal_Int32( dDiff / 7 );
2244 break;
2246 case INTERVAL_H:
2248 nRet = implGetHour( dDate );
2249 break;
2251 case INTERVAL_N:
2253 nRet = implGetMinute( dDate );
2254 break;
2256 case INTERVAL_S:
2258 nRet = implGetSecond( dDate );
2259 break;
2262 rPar.Get32(0)->PutLong( nRet );
2265 // FormatDateTime(Date[,NamedFormat])
2266 void SbRtl_FormatDateTime(StarBASIC *, SbxArray & rPar, bool)
2268 sal_uInt32 nParCount = rPar.Count32();
2269 if( nParCount < 2 || nParCount > 3 )
2271 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2272 return;
2275 double dDate = rPar.Get32(1)->GetDate();
2276 sal_Int16 nNamedFormat = 0;
2277 if( nParCount > 2 )
2279 nNamedFormat = rPar.Get32(2)->GetInteger();
2280 if( nNamedFormat < 0 || nNamedFormat > 4 )
2282 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2283 return;
2287 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
2288 if( !xCalendar.is() )
2290 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
2291 return;
2294 OUString aRetStr;
2295 SbxVariableRef pSbxVar = new SbxVariable( SbxSTRING );
2296 switch( nNamedFormat )
2298 // GeneralDate:
2299 // Display a date and/or time. If there is a date part,
2300 // display it as a short date. If there is a time part,
2301 // display it as a long time. If present, both parts are displayed.
2303 // 12/21/2004 11:24:50 AM
2304 // 21.12.2004 12:13:51
2305 case 0:
2306 pSbxVar->PutDate( dDate );
2307 aRetStr = pSbxVar->GetOUString();
2308 break;
2310 // LongDate: Display a date using the long date format specified
2311 // in your computer's regional settings.
2312 // Tuesday, December 21, 2004
2313 // Dienstag, 21. December 2004
2314 case 1:
2316 std::shared_ptr<SvNumberFormatter> pFormatter;
2317 if( GetSbData()->pInst )
2319 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2321 else
2323 sal_uInt32 n; // Dummy
2324 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
2327 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
2328 const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, eLangType );
2329 const Color* pCol;
2330 pFormatter->GetOutputString( dDate, nIndex, aRetStr, &pCol );
2331 break;
2334 // ShortDate: Display a date using the short date format specified
2335 // in your computer's regional settings.
2336 // 21.12.2004
2337 case 2:
2338 pSbxVar->PutDate( floor(dDate) );
2339 aRetStr = pSbxVar->GetOUString();
2340 break;
2342 // LongTime: Display a time using the time format specified
2343 // in your computer's regional settings.
2344 // 11:24:50 AM
2345 // 12:13:51
2346 case 3:
2347 // ShortTime: Display a time using the 24-hour format (hh:mm).
2348 // 11:24
2349 case 4:
2350 double dTime = modf( dDate, &o3tl::temporary(double()) );
2351 pSbxVar->PutDate( dTime );
2352 if( nNamedFormat == 3 )
2354 aRetStr = pSbxVar->GetOUString();
2356 else
2358 aRetStr = pSbxVar->GetOUString().copy( 0, 5 );
2360 break;
2363 rPar.Get32(0)->PutString( aRetStr );
2366 void SbRtl_Frac(StarBASIC *, SbxArray & rPar, bool)
2368 sal_uInt32 nParCount = rPar.Count32();
2369 if( nParCount != 2)
2371 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2372 return;
2375 SbxVariable *pSbxVariable = rPar.Get32(1);
2376 double dVal = pSbxVariable->GetDouble();
2377 if(dVal >= 0)
2378 rPar.Get32(0)->PutDouble(dVal - ::rtl::math::approxFloor(dVal));
2379 else
2380 rPar.Get32(0)->PutDouble(dVal - ::rtl::math::approxCeil(dVal));
2383 void SbRtl_Round(StarBASIC *, SbxArray & rPar, bool)
2385 sal_uInt32 nParCount = rPar.Count32();
2386 if( nParCount != 2 && nParCount != 3 )
2388 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2389 return;
2392 SbxVariable *pSbxVariable = rPar.Get32(1);
2393 double dVal = pSbxVariable->GetDouble();
2394 double dRes = 0.0;
2395 if( dVal != 0.0 )
2397 bool bNeg = false;
2398 if( dVal < 0.0 )
2400 bNeg = true;
2401 dVal = -dVal;
2404 sal_Int16 numdecimalplaces = 0;
2405 if( nParCount == 3 )
2407 numdecimalplaces = rPar.Get32(2)->GetInteger();
2408 if( numdecimalplaces < 0 || numdecimalplaces > 22 )
2410 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2411 return;
2415 if( numdecimalplaces == 0 )
2417 dRes = floor( dVal + 0.5 );
2419 else
2421 double dFactor = pow( 10.0, numdecimalplaces );
2422 dVal *= dFactor;
2423 dRes = floor( dVal + 0.5 );
2424 dRes /= dFactor;
2427 if( bNeg )
2428 dRes = -dRes;
2430 rPar.Get32(0)->PutDouble( dRes );
2433 static void CallFunctionAccessFunction( const Sequence< Any >& aArgs, const OUString& sFuncName, SbxVariable* pRet )
2435 static Reference< XFunctionAccess > xFunc;
2438 if ( !xFunc.is() )
2440 Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() );
2441 if( xFactory.is() )
2443 xFunc.set( xFactory->createInstance("com.sun.star.sheet.FunctionAccess"), UNO_QUERY_THROW);
2446 Any aRet = xFunc->callFunction( sFuncName, aArgs );
2448 unoToSbxValue( pRet, aRet );
2451 catch(const Exception& )
2453 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2457 void SbRtl_SYD(StarBASIC *, SbxArray & rPar, bool)
2459 sal_uInt32 nArgCount = rPar.Count32()-1;
2461 if ( nArgCount < 4 )
2463 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2464 return;
2467 // retrieve non-optional params
2469 Sequence< Any > aParams( 4 );
2470 aParams[ 0 ] <<= rPar.Get32(1)->GetDouble();
2471 aParams[ 1 ] <<= rPar.Get32(2)->GetDouble();
2472 aParams[ 2 ] <<= rPar.Get32(3)->GetDouble();
2473 aParams[ 3 ] <<= rPar.Get32(4)->GetDouble();
2475 CallFunctionAccessFunction( aParams, "SYD", rPar.Get32( 0 ) );
2478 void SbRtl_SLN(StarBASIC *, SbxArray & rPar, bool)
2480 sal_uInt32 nArgCount = rPar.Count32()-1;
2482 if ( nArgCount < 3 )
2484 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2485 return;
2488 // retrieve non-optional params
2490 Sequence< Any > aParams( 3 );
2491 aParams[ 0 ] <<= rPar.Get32(1)->GetDouble();
2492 aParams[ 1 ] <<= rPar.Get32(2)->GetDouble();
2493 aParams[ 2 ] <<= rPar.Get32(3)->GetDouble();
2495 CallFunctionAccessFunction( aParams, "SLN", rPar.Get32( 0 ) );
2498 void SbRtl_Pmt(StarBASIC *, SbxArray & rPar, bool)
2500 sal_uInt32 nArgCount = rPar.Count32()-1;
2502 if ( nArgCount < 3 || nArgCount > 5 )
2504 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2505 return;
2507 // retrieve non-optional params
2509 double rate = rPar.Get32(1)->GetDouble();
2510 double nper = rPar.Get32(2)->GetDouble();
2511 double pmt = rPar.Get32(3)->GetDouble();
2513 // set default values for Optional args
2514 double fv = 0;
2515 double type = 0;
2517 // fv
2518 if ( nArgCount >= 4 )
2520 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2521 fv = rPar.Get32(4)->GetDouble();
2523 // type
2524 if ( nArgCount >= 5 )
2526 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2527 type = rPar.Get32(5)->GetDouble();
2530 Sequence< Any > aParams( 5 );
2531 aParams[ 0 ] <<= rate;
2532 aParams[ 1 ] <<= nper;
2533 aParams[ 2 ] <<= pmt;
2534 aParams[ 3 ] <<= fv;
2535 aParams[ 4 ] <<= type;
2537 CallFunctionAccessFunction( aParams, "Pmt", rPar.Get32( 0 ) );
2540 void SbRtl_PPmt(StarBASIC *, SbxArray & rPar, bool)
2542 sal_uInt32 nArgCount = rPar.Count32()-1;
2544 if ( nArgCount < 4 || nArgCount > 6 )
2546 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2547 return;
2549 // retrieve non-optional params
2551 double rate = rPar.Get32(1)->GetDouble();
2552 double per = rPar.Get32(2)->GetDouble();
2553 double nper = rPar.Get32(3)->GetDouble();
2554 double pv = rPar.Get32(4)->GetDouble();
2556 // set default values for Optional args
2557 double fv = 0;
2558 double type = 0;
2560 // fv
2561 if ( nArgCount >= 5 )
2563 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2564 fv = rPar.Get32(5)->GetDouble();
2566 // type
2567 if ( nArgCount >= 6 )
2569 if( rPar.Get32(6)->GetType() != SbxEMPTY )
2570 type = rPar.Get32(6)->GetDouble();
2573 Sequence< Any > aParams( 6 );
2574 aParams[ 0 ] <<= rate;
2575 aParams[ 1 ] <<= per;
2576 aParams[ 2 ] <<= nper;
2577 aParams[ 3 ] <<= pv;
2578 aParams[ 4 ] <<= fv;
2579 aParams[ 5 ] <<= type;
2581 CallFunctionAccessFunction( aParams, "PPmt", rPar.Get32( 0 ) );
2584 void SbRtl_PV(StarBASIC *, SbxArray & rPar, bool)
2586 sal_uInt32 nArgCount = rPar.Count32()-1;
2588 if ( nArgCount < 3 || nArgCount > 5 )
2590 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2591 return;
2593 // retrieve non-optional params
2595 double rate = rPar.Get32(1)->GetDouble();
2596 double nper = rPar.Get32(2)->GetDouble();
2597 double pmt = rPar.Get32(3)->GetDouble();
2599 // set default values for Optional args
2600 double fv = 0;
2601 double type = 0;
2603 // fv
2604 if ( nArgCount >= 4 )
2606 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2607 fv = rPar.Get32(4)->GetDouble();
2609 // type
2610 if ( nArgCount >= 5 )
2612 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2613 type = rPar.Get32(5)->GetDouble();
2616 Sequence< Any > aParams( 5 );
2617 aParams[ 0 ] <<= rate;
2618 aParams[ 1 ] <<= nper;
2619 aParams[ 2 ] <<= pmt;
2620 aParams[ 3 ] <<= fv;
2621 aParams[ 4 ] <<= type;
2623 CallFunctionAccessFunction( aParams, "PV", rPar.Get32( 0 ) );
2626 void SbRtl_NPV(StarBASIC *, SbxArray & rPar, bool)
2628 sal_uInt32 nArgCount = rPar.Count32()-1;
2630 if ( nArgCount < 1 || nArgCount > 2 )
2632 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2633 return;
2636 Sequence< Any > aParams( 2 );
2637 aParams[ 0 ] <<= rPar.Get32(1)->GetDouble();
2638 Any aValues = sbxToUnoValue( rPar.Get32(2),
2639 cppu::UnoType<Sequence<double>>::get() );
2641 // convert for calc functions
2642 Sequence< Sequence< double > > sValues(1);
2643 aValues >>= sValues[ 0 ];
2644 aValues <<= sValues;
2646 aParams[ 1 ] = aValues;
2648 CallFunctionAccessFunction( aParams, "NPV", rPar.Get32( 0 ) );
2651 void SbRtl_NPer(StarBASIC *, SbxArray & rPar, bool)
2653 sal_uInt32 nArgCount = rPar.Count32()-1;
2655 if ( nArgCount < 3 || nArgCount > 5 )
2657 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2658 return;
2660 // retrieve non-optional params
2662 double rate = rPar.Get32(1)->GetDouble();
2663 double pmt = rPar.Get32(2)->GetDouble();
2664 double pv = rPar.Get32(3)->GetDouble();
2666 // set default values for Optional args
2667 double fv = 0;
2668 double type = 0;
2670 // fv
2671 if ( nArgCount >= 4 )
2673 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2674 fv = rPar.Get32(4)->GetDouble();
2676 // type
2677 if ( nArgCount >= 5 )
2679 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2680 type = rPar.Get32(5)->GetDouble();
2683 Sequence< Any > aParams( 5 );
2684 aParams[ 0 ] <<= rate;
2685 aParams[ 1 ] <<= pmt;
2686 aParams[ 2 ] <<= pv;
2687 aParams[ 3 ] <<= fv;
2688 aParams[ 4 ] <<= type;
2690 CallFunctionAccessFunction( aParams, "NPer", rPar.Get32( 0 ) );
2693 void SbRtl_MIRR(StarBASIC *, SbxArray & rPar, bool)
2695 sal_uInt32 nArgCount = rPar.Count32()-1;
2697 if ( nArgCount < 3 )
2699 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2700 return;
2703 // retrieve non-optional params
2705 Sequence< Any > aParams( 3 );
2706 Any aValues = sbxToUnoValue( rPar.Get32(1),
2707 cppu::UnoType<Sequence<double>>::get() );
2709 // convert for calc functions
2710 Sequence< Sequence< double > > sValues(1);
2711 aValues >>= sValues[ 0 ];
2712 aValues <<= sValues;
2714 aParams[ 0 ] = aValues;
2715 aParams[ 1 ] <<= rPar.Get32(2)->GetDouble();
2716 aParams[ 2 ] <<= rPar.Get32(3)->GetDouble();
2718 CallFunctionAccessFunction( aParams, "MIRR", rPar.Get32( 0 ) );
2721 void SbRtl_IRR(StarBASIC *, SbxArray & rPar, bool)
2723 sal_uInt32 nArgCount = rPar.Count32()-1;
2725 if ( nArgCount < 1 || nArgCount > 2 )
2727 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2728 return;
2730 // retrieve non-optional params
2731 Any aValues = sbxToUnoValue( rPar.Get32(1),
2732 cppu::UnoType<Sequence<double>>::get() );
2734 // convert for calc functions
2735 Sequence< Sequence< double > > sValues(1);
2736 aValues >>= sValues[ 0 ];
2737 aValues <<= sValues;
2739 // set default values for Optional args
2740 double guess = 0.1;
2741 // guess
2742 if ( nArgCount >= 2 )
2744 if( rPar.Get32(2)->GetType() != SbxEMPTY )
2745 guess = rPar.Get32(2)->GetDouble();
2748 Sequence< Any > aParams( 2 );
2749 aParams[ 0 ] = aValues;
2750 aParams[ 1 ] <<= guess;
2752 CallFunctionAccessFunction( aParams, "IRR", rPar.Get32( 0 ) );
2755 void SbRtl_IPmt(StarBASIC *, SbxArray & rPar, bool)
2757 sal_uInt32 nArgCount = rPar.Count32()-1;
2759 if ( nArgCount < 4 || nArgCount > 6 )
2761 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2762 return;
2764 // retrieve non-optional params
2766 double rate = rPar.Get32(1)->GetDouble();
2767 double per = rPar.Get32(2)->GetInteger();
2768 double nper = rPar.Get32(3)->GetDouble();
2769 double pv = rPar.Get32(4)->GetDouble();
2771 // set default values for Optional args
2772 double fv = 0;
2773 double type = 0;
2775 // fv
2776 if ( nArgCount >= 5 )
2778 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2779 fv = rPar.Get32(5)->GetDouble();
2781 // type
2782 if ( nArgCount >= 6 )
2784 if( rPar.Get32(6)->GetType() != SbxEMPTY )
2785 type = rPar.Get32(6)->GetDouble();
2788 Sequence< Any > aParams( 6 );
2789 aParams[ 0 ] <<= rate;
2790 aParams[ 1 ] <<= per;
2791 aParams[ 2 ] <<= nper;
2792 aParams[ 3 ] <<= pv;
2793 aParams[ 4 ] <<= fv;
2794 aParams[ 5 ] <<= type;
2796 CallFunctionAccessFunction( aParams, "IPmt", rPar.Get32( 0 ) );
2799 void SbRtl_FV(StarBASIC *, SbxArray & rPar, bool)
2801 sal_uInt32 nArgCount = rPar.Count32()-1;
2803 if ( nArgCount < 3 || nArgCount > 5 )
2805 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2806 return;
2808 // retrieve non-optional params
2810 double rate = rPar.Get32(1)->GetDouble();
2811 double nper = rPar.Get32(2)->GetDouble();
2812 double pmt = rPar.Get32(3)->GetDouble();
2814 // set default values for Optional args
2815 double pv = 0;
2816 double type = 0;
2818 // pv
2819 if ( nArgCount >= 4 )
2821 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2822 pv = rPar.Get32(4)->GetDouble();
2824 // type
2825 if ( nArgCount >= 5 )
2827 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2828 type = rPar.Get32(5)->GetDouble();
2831 Sequence< Any > aParams( 5 );
2832 aParams[ 0 ] <<= rate;
2833 aParams[ 1 ] <<= nper;
2834 aParams[ 2 ] <<= pmt;
2835 aParams[ 3 ] <<= pv;
2836 aParams[ 4 ] <<= type;
2838 CallFunctionAccessFunction( aParams, "FV", rPar.Get32( 0 ) );
2841 void SbRtl_DDB(StarBASIC *, SbxArray & rPar, bool)
2843 sal_uInt32 nArgCount = rPar.Count32()-1;
2845 if ( nArgCount < 4 || nArgCount > 5 )
2847 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2848 return;
2850 // retrieve non-optional params
2852 double cost = rPar.Get32(1)->GetDouble();
2853 double salvage = rPar.Get32(2)->GetDouble();
2854 double life = rPar.Get32(3)->GetDouble();
2855 double period = rPar.Get32(4)->GetDouble();
2857 // set default values for Optional args
2858 double factor = 2;
2860 // factor
2861 if ( nArgCount >= 5 )
2863 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2864 factor = rPar.Get32(5)->GetDouble();
2867 Sequence< Any > aParams( 5 );
2868 aParams[ 0 ] <<= cost;
2869 aParams[ 1 ] <<= salvage;
2870 aParams[ 2 ] <<= life;
2871 aParams[ 3 ] <<= period;
2872 aParams[ 4 ] <<= factor;
2874 CallFunctionAccessFunction( aParams, "DDB", rPar.Get32( 0 ) );
2877 void SbRtl_Rate(StarBASIC *, SbxArray & rPar, bool)
2879 sal_uInt32 nArgCount = rPar.Count32()-1;
2881 if ( nArgCount < 3 || nArgCount > 6 )
2883 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2884 return;
2886 // retrieve non-optional params
2888 double nper = 0;
2889 double pmt = 0;
2890 double pv = 0;
2892 nper = rPar.Get32(1)->GetDouble();
2893 pmt = rPar.Get32(2)->GetDouble();
2894 pv = rPar.Get32(3)->GetDouble();
2896 // set default values for Optional args
2897 double fv = 0;
2898 double type = 0;
2899 double guess = 0.1;
2901 // fv
2902 if ( nArgCount >= 4 )
2904 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2905 fv = rPar.Get32(4)->GetDouble();
2908 // type
2909 if ( nArgCount >= 5 )
2911 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2912 type = rPar.Get32(5)->GetDouble();
2915 // guess
2916 if ( nArgCount >= 6 )
2918 if( rPar.Get32(6)->GetType() != SbxEMPTY )
2919 guess = rPar.Get32(6)->GetDouble();
2922 Sequence< Any > aParams( 6 );
2923 aParams[ 0 ] <<= nper;
2924 aParams[ 1 ] <<= pmt;
2925 aParams[ 2 ] <<= pv;
2926 aParams[ 3 ] <<= fv;
2927 aParams[ 4 ] <<= type;
2928 aParams[ 5 ] <<= guess;
2930 CallFunctionAccessFunction( aParams, "Rate", rPar.Get32( 0 ) );
2933 void SbRtl_StrReverse(StarBASIC *, SbxArray & rPar, bool)
2935 if ( rPar.Count32() != 2 )
2937 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2938 return;
2941 SbxVariable *pSbxVariable = rPar.Get32(1);
2942 if( pSbxVariable->IsNull() )
2944 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2945 return;
2948 OUString aStr = comphelper::string::reverseString(pSbxVariable->GetOUString());
2949 rPar.Get32(0)->PutString( aStr );
2952 void SbRtl_CompatibilityMode(StarBASIC *, SbxArray & rPar, bool)
2954 bool bEnabled = false;
2955 sal_uInt32 nCount = rPar.Count32();
2956 if ( nCount != 1 && nCount != 2 )
2957 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2959 SbiInstance* pInst = GetSbData()->pInst;
2960 if( pInst )
2962 if ( nCount == 2 )
2964 pInst->EnableCompatibility( rPar.Get32(1)->GetBool() );
2966 bEnabled = pInst->IsCompatibility();
2968 rPar.Get32(0)->PutBool( bEnabled );
2971 void SbRtl_Input(StarBASIC *, SbxArray & rPar, bool)
2973 // 2 parameters needed
2974 if ( rPar.Count32() < 3 )
2976 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2977 return;
2980 sal_uInt16 nByteCount = rPar.Get32(1)->GetUShort();
2981 sal_Int16 nFileNumber = rPar.Get32(2)->GetInteger();
2983 SbiIoSystem* pIosys = GetSbData()->pInst->GetIoSystem();
2984 SbiStream* pSbStrm = pIosys->GetStream( nFileNumber );
2985 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Input)) )
2987 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
2988 return;
2991 OString aByteBuffer;
2992 ErrCode err = pSbStrm->Read( aByteBuffer, nByteCount, true );
2993 if( !err )
2994 err = pIosys->GetError();
2996 if( err )
2998 StarBASIC::Error( err );
2999 return;
3001 rPar.Get32(0)->PutString(OStringToOUString(aByteBuffer, osl_getThreadTextEncoding()));
3004 void SbRtl_Me(StarBASIC *, SbxArray & rPar, bool)
3006 SbModule* pActiveModule = GetSbData()->pInst->GetActiveModule();
3007 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pActiveModule );
3008 SbxVariableRef refVar = rPar.Get32(0);
3009 if( pClassModuleObject == nullptr )
3011 SbObjModule* pMod = dynamic_cast<SbObjModule*>( pActiveModule );
3012 if ( pMod )
3013 refVar->PutObject( pMod );
3014 else
3015 StarBASIC::Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
3017 else
3018 refVar->PutObject( pClassModuleObject );
3021 #endif
3023 sal_Int16 implGetWeekDay( double aDate, bool bFirstDayParam, sal_Int16 nFirstDay )
3025 Date aRefDate( 1,1,1900 );
3026 sal_Int32 nDays = static_cast<sal_Int32>(aDate);
3027 nDays -= 2; // normalize: 1.1.1900 => 0
3028 aRefDate.AddDays( nDays);
3029 DayOfWeek aDay = aRefDate.GetDayOfWeek();
3030 sal_Int16 nDay;
3031 if ( aDay != SUNDAY )
3032 nDay = static_cast<sal_Int16>(aDay) + 2;
3033 else
3034 nDay = 1; // 1 == Sunday
3036 // #117253 optional 2nd parameter "firstdayofweek"
3037 if( bFirstDayParam )
3039 if( nFirstDay < 0 || nFirstDay > 7 )
3041 #if HAVE_FEATURE_SCRIPTING
3042 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3043 #endif
3044 return 0;
3046 if( nFirstDay == 0 )
3048 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
3049 if( !xCalendar.is() )
3051 #if HAVE_FEATURE_SCRIPTING
3052 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
3053 #endif
3054 return 0;
3056 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
3058 nDay = 1 + (nDay + 7 - nFirstDay) % 7;
3060 return nDay;
3063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */