Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / runtime / methods1.cxx
blob19f0acaa8c0a031054209fc76df012e1da4d5b11
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 <vcl/svapp.hxx>
29 #include <vcl/mapmod.hxx>
30 #include <vcl/outdev.hxx>
31 #include <vcl/timer.hxx>
32 #include <vcl/settings.hxx>
33 #include <basic/sbxvar.hxx>
34 #include <basic/sbx.hxx>
35 #include <svl/zforlist.hxx>
36 #include <tools/urlobj.hxx>
37 #include <tools/fract.hxx>
38 #include <o3tl/temporary.hxx>
39 #include <osl/file.hxx>
40 #include <sbobjmod.hxx>
41 #include <basic/sbuno.hxx>
43 #include <date.hxx>
44 #include <sbintern.hxx>
45 #include <runtime.hxx>
46 #include <rtlproto.hxx>
47 #include "dllmgr.hxx"
48 #include <iosys.hxx>
49 #include <sbunoobj.hxx>
50 #include <propacc.hxx>
51 #include <sal/log.hxx>
52 #include <eventatt.hxx>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/string.hxx>
57 #include <com/sun/star/uno/Sequence.hxx>
58 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
59 #include <com/sun/star/i18n/LocaleCalendar2.hpp>
60 #include <com/sun/star/sheet/XFunctionAccess.hpp>
61 #include <memory>
63 using namespace comphelper;
64 using namespace com::sun::star::i18n;
65 using namespace com::sun::star::lang;
66 using namespace com::sun::star::sheet;
67 using namespace com::sun::star::uno;
69 static Reference< XCalendar4 > const & getLocaleCalendar()
71 static Reference< XCalendar4 > xCalendar = LocaleCalendar2::create(getProcessComponentContext());
72 static css::lang::Locale aLastLocale;
73 static bool bNeedsInit = true;
75 css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale();
76 bool bNeedsReload = false;
77 if( bNeedsInit )
79 bNeedsInit = false;
80 bNeedsReload = true;
82 else if( aLocale.Language != aLastLocale.Language ||
83 aLocale.Country != aLastLocale.Country ||
84 aLocale.Variant != aLastLocale.Variant )
86 bNeedsReload = true;
88 if( bNeedsReload )
90 aLastLocale = aLocale;
91 xCalendar->loadDefaultCalendar( aLocale );
93 return xCalendar;
96 #if HAVE_FEATURE_SCRIPTING
98 void SbRtl_CallByName(StarBASIC *, SbxArray & rPar, bool)
100 const sal_Int16 vbGet = 2;
101 const sal_Int16 vbLet = 4;
102 const sal_Int16 vbMethod = 1;
103 const sal_Int16 vbSet = 8;
105 // At least 3 parameter needed plus function itself -> 4
106 sal_uInt16 nParCount = rPar.Count();
107 if ( nParCount < 4 )
109 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
110 return;
113 // 1. parameter is object
114 SbxBase* pObjVar = rPar.Get(1)->GetObject();
115 SbxObject* pObj = nullptr;
116 if( pObjVar )
117 pObj = dynamic_cast<SbxObject*>( pObjVar );
118 if( !pObj && dynamic_cast<const SbxVariable*>( pObjVar) )
120 SbxBase* pObjVarObj = static_cast<SbxVariable*>(pObjVar)->GetObject();
121 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
123 if( !pObj )
125 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
126 return;
129 // 2. parameter is ProcedureName
130 OUString aNameStr = rPar.Get(2)->GetOUString();
132 // 3. parameter is CallType
133 sal_Int16 nCallType = rPar.Get(3)->GetInteger();
135 //SbxObject* pFindObj = NULL;
136 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::DontCare );
137 if( pFindVar == nullptr )
139 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
140 return;
143 switch( nCallType )
145 case vbGet:
147 SbxValues aVals;
148 aVals.eType = SbxVARIANT;
149 pFindVar->Get( aVals );
151 SbxVariableRef refVar = rPar.Get(0);
152 refVar->Put( aVals );
154 break;
155 case vbLet:
156 case vbSet:
158 if ( nParCount != 5 )
160 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
161 return;
163 SbxVariableRef pValVar = rPar.Get(4);
164 if( nCallType == vbLet )
166 SbxValues aVals;
167 aVals.eType = SbxVARIANT;
168 pValVar->Get( aVals );
169 pFindVar->Put( aVals );
171 else
173 SbxVariableRef rFindVar = pFindVar;
174 SbiInstance* pInst = GetSbData()->pInst;
175 SbiRuntime* pRT = pInst ? pInst->pRun : nullptr;
176 if( pRT != nullptr )
178 pRT->StepSET_Impl( pValVar, rFindVar );
182 break;
183 case vbMethod:
185 SbMethod* pMeth = dynamic_cast<SbMethod*>( pFindVar );
186 if( pMeth == nullptr )
188 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
189 return;
192 // Setup parameters
193 SbxArrayRef xArray;
194 sal_uInt16 nMethParamCount = nParCount - 4;
195 if( nMethParamCount > 0 )
197 xArray = new SbxArray;
198 for( sal_uInt16 i = 0 ; i < nMethParamCount ; i++ )
200 SbxVariable* pPar = rPar.Get( i + 4 );
201 xArray->Put( pPar, i + 1 );
205 // Call method
206 SbxVariableRef refVar = rPar.Get(0);
207 if( xArray.is() )
208 pMeth->SetParameters( xArray.get() );
209 pMeth->Call( refVar.get() );
210 pMeth->SetParameters( nullptr );
212 break;
213 default:
214 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
218 void SbRtl_CBool(StarBASIC *, SbxArray & rPar, bool) // JSM
220 bool bVal = false;
221 if ( rPar.Count() == 2 )
223 SbxVariable *pSbxVariable = rPar.Get(1);
224 bVal = pSbxVariable->GetBool();
226 else
228 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
230 rPar.Get(0)->PutBool(bVal);
233 void SbRtl_CByte(StarBASIC *, SbxArray & rPar, bool) // JSM
235 sal_uInt8 nByte = 0;
236 if ( rPar.Count() == 2 )
238 SbxVariable *pSbxVariable = rPar.Get(1);
239 nByte = pSbxVariable->GetByte();
241 else
243 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
245 rPar.Get(0)->PutByte(nByte);
248 void SbRtl_CCur(StarBASIC *, SbxArray & rPar, bool)
250 sal_Int64 nCur = 0;
251 if ( rPar.Count() == 2 )
253 SbxVariable *pSbxVariable = rPar.Get(1);
254 nCur = pSbxVariable->GetCurrency();
256 else
258 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
260 rPar.Get(0)->PutCurrency( nCur );
263 void SbRtl_CDec(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
265 (void)pBasic;
266 (void)bWrite;
268 #ifdef _WIN32
269 SbxDecimal* pDec = nullptr;
270 if ( rPar.Count() == 2 )
272 SbxVariable *pSbxVariable = rPar.Get(1);
273 pDec = pSbxVariable->GetDecimal();
275 else
277 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
279 rPar.Get(0)->PutDecimal( pDec );
280 #else
281 rPar.Get(0)->PutEmpty();
282 StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTED);
283 #endif
286 void SbRtl_CDate(StarBASIC *, SbxArray & rPar, bool) // JSM
288 double nVal = 0.0;
289 if ( rPar.Count() == 2 )
291 SbxVariable *pSbxVariable = rPar.Get(1);
292 nVal = pSbxVariable->GetDate();
294 else
296 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
298 rPar.Get(0)->PutDate(nVal);
301 void SbRtl_CDbl(StarBASIC *, SbxArray & rPar, bool) // JSM
303 double nVal = 0.0;
304 if ( rPar.Count() == 2 )
306 SbxVariable *pSbxVariable = rPar.Get(1);
307 if( pSbxVariable->GetType() == SbxSTRING )
309 // #41690
310 OUString aScanStr = pSbxVariable->GetOUString();
311 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, nVal );
312 if( Error != ERRCODE_NONE )
314 StarBASIC::Error( Error );
317 else
319 nVal = pSbxVariable->GetDouble();
322 else
324 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
327 rPar.Get(0)->PutDouble(nVal);
330 void SbRtl_CInt(StarBASIC *, SbxArray & rPar, bool) // JSM
332 sal_Int16 nVal = 0;
333 if ( rPar.Count() == 2 )
335 SbxVariable *pSbxVariable = rPar.Get(1);
336 nVal = pSbxVariable->GetInteger();
338 else
340 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
342 rPar.Get(0)->PutInteger(nVal);
345 void SbRtl_CLng(StarBASIC *, SbxArray & rPar, bool) // JSM
347 sal_Int32 nVal = 0;
348 if ( rPar.Count() == 2 )
350 SbxVariable *pSbxVariable = rPar.Get(1);
351 nVal = pSbxVariable->GetLong();
353 else
355 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
357 rPar.Get(0)->PutLong(nVal);
360 void SbRtl_CSng(StarBASIC *, SbxArray & rPar, bool) // JSM
362 float nVal = float(0.0);
363 if ( rPar.Count() == 2 )
365 SbxVariable *pSbxVariable = rPar.Get(1);
366 if( pSbxVariable->GetType() == SbxSTRING )
368 // #41690
369 double dVal = 0.0;
370 OUString aScanStr = pSbxVariable->GetOUString();
371 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, dVal, /*bSingle=*/true );
372 if( SbxBase::GetError() == ERRCODE_NONE && Error != ERRCODE_NONE )
374 StarBASIC::Error( Error );
376 nVal = static_cast<float>(dVal);
378 else
380 nVal = pSbxVariable->GetSingle();
383 else
385 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
387 rPar.Get(0)->PutSingle(nVal);
390 void SbRtl_CStr(StarBASIC *, SbxArray & rPar, bool) // JSM
392 OUString aString;
393 if ( rPar.Count() == 2 )
395 SbxVariable *pSbxVariable = rPar.Get(1);
396 aString = pSbxVariable->GetOUString();
398 else
400 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
402 rPar.Get(0)->PutString(aString);
405 void SbRtl_CVar(StarBASIC *, SbxArray & rPar, bool) // JSM
407 SbxValues aVals( SbxVARIANT );
408 if ( rPar.Count() == 2 )
410 SbxVariable *pSbxVariable = rPar.Get(1);
411 pSbxVariable->Get( aVals );
413 else
415 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
417 rPar.Get(0)->Put( aVals );
420 void SbRtl_CVErr(StarBASIC *, SbxArray & rPar, bool)
422 sal_Int16 nErrCode = 0;
423 if ( rPar.Count() == 2 )
425 SbxVariable *pSbxVariable = rPar.Get(1);
426 nErrCode = pSbxVariable->GetInteger();
428 else
430 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
432 rPar.Get(0)->PutErr( nErrCode );
435 void SbRtl_Iif(StarBASIC *, SbxArray & rPar, bool) // JSM
437 if ( rPar.Count() == 4 )
439 if (rPar.Get(1)->GetBool())
441 *rPar.Get(0) = *rPar.Get(2);
443 else
445 *rPar.Get(0) = *rPar.Get(3);
448 else
450 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
454 void SbRtl_GetSystemType(StarBASIC *, SbxArray & rPar, bool)
456 if ( rPar.Count() != 1 )
458 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
460 else
462 // Removed for SRC595
463 rPar.Get(0)->PutInteger( -1 );
467 void SbRtl_GetGUIType(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
469 (void)pBasic;
470 (void)bWrite;
472 if ( rPar.Count() != 1 )
474 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
476 else
478 // 17.7.2000 Make simple solution for testtool / fat office
479 #if defined(_WIN32)
480 rPar.Get(0)->PutInteger( 1 );
481 #elif defined(UNX)
482 rPar.Get(0)->PutInteger( 4 );
483 #else
484 rPar.Get(0)->PutInteger( -1 );
485 #endif
489 void SbRtl_Red(StarBASIC *, SbxArray & rPar, bool)
491 if ( rPar.Count() != 2 )
493 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
495 else
497 sal_Int32 nRGB = rPar.Get(1)->GetLong();
498 nRGB &= 0x00FF0000;
499 nRGB >>= 16;
500 rPar.Get(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
504 void SbRtl_Green(StarBASIC *, SbxArray & rPar, bool)
506 if ( rPar.Count() != 2 )
508 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
510 else
512 sal_Int32 nRGB = rPar.Get(1)->GetLong();
513 nRGB &= 0x0000FF00;
514 nRGB >>= 8;
515 rPar.Get(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
519 void SbRtl_Blue(StarBASIC *, SbxArray & rPar, bool)
521 if ( rPar.Count() != 2 )
523 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
525 else
527 sal_Int32 nRGB = rPar.Get(1)->GetLong();
528 nRGB &= 0x000000FF;
529 rPar.Get(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
534 void SbRtl_Switch(StarBASIC *, SbxArray & rPar, bool)
536 sal_uInt16 nCount = rPar.Count();
537 if( !(nCount & 0x0001 ))
539 // number of arguments must be odd
540 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
542 sal_uInt16 nCurExpr = 1;
543 while( nCurExpr < (nCount-1) )
545 if( rPar.Get( nCurExpr )->GetBool())
547 (*rPar.Get(0)) = *(rPar.Get(nCurExpr+1));
548 return;
550 nCurExpr += 2;
552 rPar.Get(0)->PutNull();
555 //i#64882# Common wait impl for existing Wait and new WaitUntil
556 // rtl functions
557 void Wait_Impl( bool bDurationBased, SbxArray& rPar )
559 if( rPar.Count() != 2 )
561 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
562 return;
564 long nWait = 0;
565 if ( bDurationBased )
567 double dWait = rPar.Get(1)->GetDouble();
568 double dNow = Now_Impl();
569 double dSecs = ( dWait - dNow ) * 24.0 * 3600.0;
570 nWait = static_cast<long>( dSecs * 1000 ); // wait in thousands of sec
572 else
574 nWait = rPar.Get(1)->GetLong();
576 if( nWait < 0 )
578 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
579 return;
582 Timer aTimer;
583 aTimer.SetTimeout( nWait );
584 aTimer.Start();
585 while ( aTimer.IsActive() )
587 Application::Yield();
591 //i#64882#
592 void SbRtl_Wait(StarBASIC *, SbxArray & rPar, bool)
594 Wait_Impl( false, rPar );
597 //i#64882# add new WaitUntil ( for application.wait )
598 // share wait_impl with 'normal' oobasic wait
599 void SbRtl_WaitUntil(StarBASIC *, SbxArray & rPar, bool)
601 Wait_Impl( true, rPar );
604 void SbRtl_DoEvents(StarBASIC *, SbxArray & rPar, bool)
606 // don't understand what upstream are up to
607 // we already process application events etc. in between
608 // basic runtime pcode ( on a timed basis )
609 // always return 0
610 rPar.Get(0)->PutInteger( 0 );
611 Application::Reschedule( true );
614 void SbRtl_GetGUIVersion(StarBASIC *, SbxArray & rPar, bool)
616 if ( rPar.Count() != 1 )
618 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
620 else
622 // Removed for SRC595
623 rPar.Get(0)->PutLong( -1 );
627 void SbRtl_Choose(StarBASIC *, SbxArray & rPar, bool)
629 if ( rPar.Count() < 2 )
631 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
633 sal_Int16 nIndex = rPar.Get(1)->GetInteger();
634 sal_uInt16 nCount = rPar.Count();
635 nCount--;
636 if( nCount == 1 || nIndex > (nCount-1) || nIndex < 1 )
638 rPar.Get(0)->PutNull();
639 return;
641 (*rPar.Get(0)) = *(rPar.Get(nIndex+1));
645 void SbRtl_Trim(StarBASIC *, SbxArray & rPar, bool)
647 if ( rPar.Count() < 2 )
649 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
651 else
653 OUString aStr(comphelper::string::strip(rPar.Get(1)->GetOUString(), ' '));
654 rPar.Get(0)->PutString(aStr);
658 void SbRtl_GetSolarVersion(StarBASIC *, SbxArray & rPar, bool)
660 rPar.Get(0)->PutLong( LIBO_VERSION_MAJOR * 10000 + LIBO_VERSION_MINOR * 100 + LIBO_VERSION_MICRO * 1);
663 void SbRtl_TwipsPerPixelX(StarBASIC *, SbxArray & rPar, bool)
665 sal_Int32 nResult = 0;
666 Size aSize( 100,0 );
667 MapMode aMap( MapUnit::MapTwip );
668 OutputDevice* pDevice = Application::GetDefaultDevice();
669 if( pDevice )
671 aSize = pDevice->PixelToLogic( aSize, aMap );
672 nResult = aSize.Width() / 100;
674 rPar.Get(0)->PutLong( nResult );
677 void SbRtl_TwipsPerPixelY(StarBASIC *, SbxArray & rPar, bool)
679 sal_Int32 nResult = 0;
680 Size aSize( 0,100 );
681 MapMode aMap( MapUnit::MapTwip );
682 OutputDevice* pDevice = Application::GetDefaultDevice();
683 if( pDevice )
685 aSize = pDevice->PixelToLogic( aSize, aMap );
686 nResult = aSize.Height() / 100;
688 rPar.Get(0)->PutLong( nResult );
692 void SbRtl_FreeLibrary(StarBASIC *, SbxArray & rPar, bool)
694 if ( rPar.Count() != 2 )
696 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
698 GetSbData()->pInst->GetDllMgr()->FreeDll( rPar.Get(1)->GetOUString() );
700 bool IsBaseIndexOne()
702 bool bResult = false;
703 if ( GetSbData()->pInst && GetSbData()->pInst->pRun )
705 sal_uInt16 res = GetSbData()->pInst->pRun->GetBase();
706 if ( res )
708 bResult = true;
711 return bResult;
714 void SbRtl_Array(StarBASIC *, SbxArray & rPar, bool)
716 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
717 sal_uInt16 nArraySize = rPar.Count() - 1;
719 // ignore Option Base so far (unfortunately only known by the compiler)
720 bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() );
721 if( nArraySize )
723 if ( bIncIndex )
725 pArray->AddDim( 1, nArraySize );
727 else
729 pArray->AddDim( 0, nArraySize-1 );
732 else
734 pArray->unoAddDim( 0, -1 );
737 // insert parameters into the array
738 for( sal_uInt16 i = 0 ; i < nArraySize ; i++ )
740 SbxVariable* pVar = rPar.Get(i+1);
741 SbxVariable* pNew = new SbxEnsureParentVariable(*pVar);
742 pNew->SetFlag( SbxFlagBits::Write );
743 short aIdx[1];
744 aIdx[0] = static_cast< short >(i);
745 if ( bIncIndex )
747 ++aIdx[0];
749 pArray->Put(pNew, aIdx);
752 // return array
753 SbxVariableRef refVar = rPar.Get(0);
754 SbxFlagBits nFlags = refVar->GetFlags();
755 refVar->ResetFlag( SbxFlagBits::Fixed );
756 refVar->PutObject( pArray );
757 refVar->SetFlags( nFlags );
758 refVar->SetParameters( nullptr );
762 // Featurewish #57868
763 // The function returns a variant-array; if there are no parameters passed,
764 // an empty array is created (according to dim a(); equal to a sequence of
765 // the length 0 in Uno).
766 // If there are parameters passed, there's a dimension created for each of
767 // them; DimArray( 2, 2, 4 ) is equal to DIM a( 2, 2, 4 )
768 // the array is always of the type variant
769 void SbRtl_DimArray(StarBASIC *, SbxArray & rPar, bool)
771 SbxDimArray * pArray = new SbxDimArray( SbxVARIANT );
772 sal_uInt16 nArrayDims = rPar.Count() - 1;
773 if( nArrayDims > 0 )
775 for( sal_uInt16 i = 0; i < nArrayDims ; i++ )
777 sal_Int32 ub = rPar.Get(i+1)->GetLong();
778 if( ub < 0 )
780 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
781 ub = 0;
783 pArray->AddDim32( 0, ub );
786 else
788 pArray->unoAddDim( 0, -1 );
790 SbxVariableRef refVar = rPar.Get(0);
791 SbxFlagBits nFlags = refVar->GetFlags();
792 refVar->ResetFlag( SbxFlagBits::Fixed );
793 refVar->PutObject( pArray );
794 refVar->SetFlags( nFlags );
795 refVar->SetParameters( nullptr );
799 * FindObject and FindPropertyObject make it possible to
800 * address objects and properties of the type Object with
801 * their name as string-parameters at the runtime.
803 * Example:
804 * MyObj.Prop1.Bla = 5
806 * is equal to:
807 * dim ObjVar as Object
808 * dim ObjProp as Object
809 * ObjName$ = "MyObj"
810 * ObjVar = FindObject( ObjName$ )
811 * PropName$ = "Prop1"
812 * ObjProp = FindPropertyObject( ObjVar, PropName$ )
813 * ObjProp.Bla = 5
815 * The names can be created dynamically at the runtime
816 * so that e. g. via controls "TextEdit1" to "TextEdit5"
817 * can be iterated in a dialog in a loop.
821 // 1st parameter = the object's name as string
822 void SbRtl_FindObject(StarBASIC *, SbxArray & rPar, bool)
824 if ( rPar.Count() < 2 )
826 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
827 return;
830 OUString aNameStr = rPar.Get(1)->GetOUString();
832 SbxBase* pFind = StarBASIC::FindSBXInCurrentScope( aNameStr );
833 SbxObject* pFindObj = nullptr;
834 if( pFind )
836 pFindObj = dynamic_cast<SbxObject*>( pFind );
838 SbxVariableRef refVar = rPar.Get(0);
839 refVar->PutObject( pFindObj );
842 // address object-property in an object
843 // 1st parameter = object
844 // 2nd parameter = the property's name as string
845 void SbRtl_FindPropertyObject(StarBASIC *, SbxArray & rPar, bool)
847 if ( rPar.Count() < 3 )
849 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
850 return;
853 SbxBase* pObjVar = rPar.Get(1)->GetObject();
854 SbxObject* pObj = nullptr;
855 if( pObjVar )
857 pObj = dynamic_cast<SbxObject*>( pObjVar );
859 if( !pObj && dynamic_cast<const SbxVariable*>( pObjVar) )
861 SbxBase* pObjVarObj = static_cast<SbxVariable*>(pObjVar)->GetObject();
862 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
865 OUString aNameStr = rPar.Get(2)->GetOUString();
867 SbxObject* pFindObj = nullptr;
868 if( pObj )
870 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::Object );
871 pFindObj = dynamic_cast<SbxObject*>( pFindVar );
873 else
875 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
878 SbxVariableRef refVar = rPar.Get(0);
879 refVar->PutObject( pFindObj );
883 static bool lcl_WriteSbxVariable( const SbxVariable& rVar, SvStream* pStrm,
884 bool bBinary, short nBlockLen, bool bIsArray )
886 sal_uInt64 const nFPos = pStrm->Tell();
888 bool bIsVariant = !rVar.IsFixed();
889 SbxDataType eType = rVar.GetType();
891 switch( eType )
893 case SbxBOOL:
894 case SbxCHAR:
895 case SbxBYTE:
896 if( bIsVariant )
898 pStrm->WriteUInt16( SbxBYTE ); // VarType Id
900 pStrm->WriteUChar( rVar.GetByte() );
901 break;
903 case SbxEMPTY:
904 case SbxNULL:
905 case SbxVOID:
906 case SbxINTEGER:
907 case SbxUSHORT:
908 case SbxINT:
909 case SbxUINT:
910 if( bIsVariant )
912 pStrm->WriteUInt16( SbxINTEGER ); // VarType Id
914 pStrm->WriteInt16( rVar.GetInteger() );
915 break;
917 case SbxLONG:
918 case SbxULONG:
919 if( bIsVariant )
921 pStrm->WriteUInt16( SbxLONG ); // VarType Id
923 pStrm->WriteInt32( rVar.GetLong() );
924 break;
925 case SbxSALINT64:
926 case SbxSALUINT64:
927 if( bIsVariant )
929 pStrm->WriteUInt16( SbxSALINT64 ); // VarType Id
931 pStrm->WriteUInt64( rVar.GetInt64() );
932 break;
933 case SbxSINGLE:
934 if( bIsVariant )
936 pStrm->WriteUInt16( eType ); // VarType Id
938 pStrm->WriteFloat( rVar.GetSingle() );
939 break;
941 case SbxDOUBLE:
942 case SbxCURRENCY:
943 case SbxDATE:
944 if( bIsVariant )
946 pStrm->WriteUInt16( eType ); // VarType Id
948 pStrm->WriteDouble( rVar.GetDouble() );
949 break;
951 case SbxSTRING:
952 case SbxLPSTR:
954 const OUString& rStr = rVar.GetOUString();
955 if( !bBinary || bIsArray )
957 if( bIsVariant )
959 pStrm->WriteUInt16( SbxSTRING );
961 pStrm->WriteUniOrByteString( rStr, osl_getThreadTextEncoding() );
963 else
965 // without any length information! without end-identifier!
966 // What does that mean for Unicode?! Choosing conversion to ByteString...
967 OString aByteStr(OUStringToOString(rStr, osl_getThreadTextEncoding()));
968 pStrm->WriteOString( aByteStr );
971 break;
973 default:
974 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
975 return false;
978 if( nBlockLen )
980 pStrm->Seek( nFPos + nBlockLen );
982 return pStrm->GetErrorCode() == ERRCODE_NONE;
985 static bool lcl_ReadSbxVariable( SbxVariable& rVar, SvStream* pStrm,
986 bool bBinary, short nBlockLen )
988 double aDouble;
990 sal_uInt64 const nFPos = pStrm->Tell();
992 bool bIsVariant = !rVar.IsFixed();
993 SbxDataType eVarType = rVar.GetType();
995 SbxDataType eSrcType = eVarType;
996 if( bIsVariant )
998 sal_uInt16 nTemp;
999 pStrm->ReadUInt16( nTemp );
1000 eSrcType = static_cast<SbxDataType>(nTemp);
1003 switch( eSrcType )
1005 case SbxBOOL:
1006 case SbxCHAR:
1007 case SbxBYTE:
1009 sal_uInt8 aByte;
1010 pStrm->ReadUChar( aByte );
1012 if( bBinary && SbiRuntime::isVBAEnabled() && aByte == 1 && pStrm->eof() )
1014 aByte = 0;
1016 rVar.PutByte( aByte );
1018 break;
1020 case SbxEMPTY:
1021 case SbxNULL:
1022 case SbxVOID:
1023 case SbxINTEGER:
1024 case SbxUSHORT:
1025 case SbxINT:
1026 case SbxUINT:
1028 sal_Int16 aInt;
1029 pStrm->ReadInt16( aInt );
1030 rVar.PutInteger( aInt );
1032 break;
1034 case SbxLONG:
1035 case SbxULONG:
1037 sal_Int32 aInt;
1038 pStrm->ReadInt32( aInt );
1039 rVar.PutLong( aInt );
1041 break;
1042 case SbxSALINT64:
1043 case SbxSALUINT64:
1045 sal_uInt32 aInt;
1046 pStrm->ReadUInt32( aInt );
1047 rVar.PutInt64( static_cast<sal_Int64>(aInt) );
1049 break;
1050 case SbxSINGLE:
1052 float nS;
1053 pStrm->ReadFloat( nS );
1054 rVar.PutSingle( nS );
1056 break;
1058 case SbxDOUBLE:
1059 case SbxCURRENCY:
1061 pStrm->ReadDouble( aDouble );
1062 rVar.PutDouble( aDouble );
1064 break;
1066 case SbxDATE:
1068 pStrm->ReadDouble( aDouble );
1069 rVar.PutDate( aDouble );
1071 break;
1073 case SbxSTRING:
1074 case SbxLPSTR:
1076 OUString aStr = pStrm->ReadUniOrByteString(osl_getThreadTextEncoding());
1077 rVar.PutString( aStr );
1079 break;
1081 default:
1082 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1083 return false;
1086 if( nBlockLen )
1088 pStrm->Seek( nFPos + nBlockLen );
1090 return pStrm->GetErrorCode() == ERRCODE_NONE;
1094 // nCurDim = 1...n
1095 static bool lcl_WriteReadSbxArray( SbxDimArray& rArr, SvStream* pStrm,
1096 bool bBinary, short nCurDim, short* pOtherDims, bool bWrite )
1098 SAL_WARN_IF( nCurDim <= 0,"basic", "Bad Dim");
1099 short nLower, nUpper;
1100 if( !rArr.GetDim( nCurDim, nLower, nUpper ) )
1101 return false;
1102 for( short nCur = nLower; nCur <= nUpper; nCur++ )
1104 pOtherDims[ nCurDim-1 ] = nCur;
1105 if( nCurDim != 1 )
1106 lcl_WriteReadSbxArray(rArr, pStrm, bBinary, nCurDim-1, pOtherDims, bWrite);
1107 else
1109 SbxVariable* pVar = rArr.Get( const_cast<const short*>(pOtherDims) );
1110 bool bRet;
1111 if( bWrite )
1112 bRet = lcl_WriteSbxVariable(*pVar, pStrm, bBinary, 0, true );
1113 else
1114 bRet = lcl_ReadSbxVariable(*pVar, pStrm, bBinary, 0 );
1115 if( !bRet )
1116 return false;
1119 return true;
1122 static void PutGet( SbxArray& rPar, bool bPut )
1124 if ( rPar.Count() != 4 )
1126 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1127 return;
1129 sal_Int16 nFileNo = rPar.Get(1)->GetInteger();
1130 SbxVariable* pVar2 = rPar.Get(2);
1131 SbxDataType eType2 = pVar2->GetType();
1132 bool bHasRecordNo = (eType2 != SbxEMPTY && eType2 != SbxERROR);
1133 long nRecordNo = pVar2->GetLong();
1134 if ( nFileNo < 1 || ( bHasRecordNo && nRecordNo < 1 ) )
1136 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1137 return;
1139 nRecordNo--;
1140 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
1141 SbiStream* pSbStrm = pIO->GetStream( nFileNo );
1143 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Random)) )
1145 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
1146 return;
1149 SvStream* pStrm = pSbStrm->GetStrm();
1150 bool bRandom = pSbStrm->IsRandom();
1151 short nBlockLen = bRandom ? pSbStrm->GetBlockLen() : 0;
1153 if( bPut )
1155 pSbStrm->ExpandFile();
1158 if( bHasRecordNo )
1160 sal_uInt64 const nFilePos = bRandom
1161 ? static_cast<sal_uInt64>(nBlockLen * nRecordNo)
1162 : static_cast<sal_uInt64>(nRecordNo);
1163 pStrm->Seek( nFilePos );
1166 SbxDimArray* pArr = nullptr;
1167 SbxVariable* pVar = rPar.Get(3);
1168 if( pVar->GetType() & SbxARRAY )
1170 SbxBase* pParObj = pVar->GetObject();
1171 pArr = dynamic_cast<SbxDimArray*>( pParObj );
1174 bool bRet;
1176 if( pArr )
1178 sal_uInt64 const nFPos = pStrm->Tell();
1179 short nDims = pArr->GetDims();
1180 std::unique_ptr<short[]> pDims(new short[ nDims ]);
1181 bRet = lcl_WriteReadSbxArray(*pArr,pStrm,!bRandom,nDims,pDims.get(),bPut);
1182 pDims.reset();
1183 if( nBlockLen )
1184 pStrm->Seek( nFPos + nBlockLen );
1186 else
1188 if( bPut )
1189 bRet = lcl_WriteSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, false);
1190 else
1191 bRet = lcl_ReadSbxVariable(*pVar, pStrm, !bRandom, nBlockLen);
1193 if( !bRet || pStrm->GetErrorCode() )
1194 StarBASIC::Error( ERRCODE_BASIC_IO_ERROR );
1197 void SbRtl_Put(StarBASIC *, SbxArray & rPar, bool)
1199 PutGet( rPar, true );
1202 void SbRtl_Get(StarBASIC *, SbxArray & rPar, bool)
1204 PutGet( rPar, false );
1207 void SbRtl_Environ(StarBASIC *, SbxArray & rPar, bool)
1209 if ( rPar.Count() != 2 )
1211 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1212 return;
1214 OUString aResult;
1215 // should be ANSI but that's not possible under Win16 in the DLL
1216 OString aByteStr(OUStringToOString(rPar.Get(1)->GetOUString(),
1217 osl_getThreadTextEncoding()));
1218 const char* pEnvStr = getenv(aByteStr.getStr());
1219 if ( pEnvStr )
1221 aResult = OUString(pEnvStr, strlen(pEnvStr), osl_getThreadTextEncoding());
1223 rPar.Get(0)->PutString( aResult );
1226 static double GetDialogZoomFactor( bool bX, long nValue )
1228 OutputDevice* pDevice = Application::GetDefaultDevice();
1229 double nResult = 0;
1230 if( pDevice )
1232 Size aRefSize( nValue, nValue );
1233 Fraction aFracX( 1, 26 );
1234 Fraction aFracY( 1, 24 );
1235 MapMode aMap( MapUnit::MapAppFont, Point(), aFracX, aFracY );
1236 Size aScaledSize = pDevice->LogicToPixel( aRefSize, aMap );
1237 aRefSize = pDevice->LogicToPixel( aRefSize, MapMode(MapUnit::MapTwip) );
1239 double nRef, nScaled;
1240 if( bX )
1242 nRef = aRefSize.Width();
1243 nScaled = aScaledSize.Width();
1245 else
1247 nRef = aRefSize.Height();
1248 nScaled = aScaledSize.Height();
1250 nResult = nScaled / nRef;
1252 return nResult;
1256 void SbRtl_GetDialogZoomFactorX(StarBASIC *, SbxArray & rPar, bool)
1258 if ( rPar.Count() != 2 )
1260 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1261 return;
1263 rPar.Get(0)->PutDouble( GetDialogZoomFactor( true, rPar.Get(1)->GetLong() ));
1266 void SbRtl_GetDialogZoomFactorY(StarBASIC *, SbxArray & rPar, bool)
1268 if ( rPar.Count() != 2 )
1270 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1271 return;
1273 rPar.Get(0)->PutDouble( GetDialogZoomFactor( false, rPar.Get(1)->GetLong()));
1277 void SbRtl_EnableReschedule(StarBASIC *, SbxArray & rPar, bool)
1279 rPar.Get(0)->PutEmpty();
1280 if ( rPar.Count() != 2 )
1281 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1282 if( GetSbData()->pInst )
1283 GetSbData()->pInst->EnableReschedule( rPar.Get(1)->GetBool() );
1286 void SbRtl_GetSystemTicks(StarBASIC *, SbxArray & rPar, bool)
1288 if ( rPar.Count() != 1 )
1290 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1291 return;
1293 rPar.Get(0)->PutLong( tools::Time::GetSystemTicks() );
1296 void SbRtl_GetPathSeparator(StarBASIC *, SbxArray & rPar, bool)
1298 if ( rPar.Count() != 1 )
1300 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1301 return;
1303 rPar.Get(0)->PutString( OUString( SAL_PATHDELIMITER ) );
1306 void SbRtl_ResolvePath(StarBASIC *, SbxArray & rPar, bool)
1308 if ( rPar.Count() == 2 )
1310 OUString aStr = rPar.Get(1)->GetOUString();
1311 rPar.Get(0)->PutString( aStr );
1313 else
1315 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1319 void SbRtl_TypeLen(StarBASIC *, SbxArray & rPar, bool)
1321 if ( rPar.Count() != 2 )
1323 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1325 else
1327 SbxDataType eType = rPar.Get(1)->GetType();
1328 sal_Int16 nLen = 0;
1329 switch( eType )
1331 case SbxEMPTY:
1332 case SbxNULL:
1333 case SbxVECTOR:
1334 case SbxARRAY:
1335 case SbxBYREF:
1336 case SbxVOID:
1337 case SbxHRESULT:
1338 case SbxPOINTER:
1339 case SbxDIMARRAY:
1340 case SbxCARRAY:
1341 case SbxUSERDEF:
1342 nLen = 0;
1343 break;
1345 case SbxINTEGER:
1346 case SbxERROR:
1347 case SbxUSHORT:
1348 case SbxINT:
1349 case SbxUINT:
1350 nLen = 2;
1351 break;
1353 case SbxLONG:
1354 case SbxSINGLE:
1355 case SbxULONG:
1356 nLen = 4;
1357 break;
1359 case SbxDOUBLE:
1360 case SbxCURRENCY:
1361 case SbxDATE:
1362 case SbxSALINT64:
1363 case SbxSALUINT64:
1364 nLen = 8;
1365 break;
1367 case SbxOBJECT:
1368 case SbxVARIANT:
1369 case SbxDATAOBJECT:
1370 nLen = 0;
1371 break;
1373 case SbxCHAR:
1374 case SbxBYTE:
1375 case SbxBOOL:
1376 nLen = 1;
1377 break;
1379 case SbxLPSTR:
1380 case SbxLPWSTR:
1381 case SbxCoreSTRING:
1382 case SbxSTRING:
1383 nLen = static_cast<sal_Int16>(rPar.Get(1)->GetOUString().getLength());
1384 break;
1386 default:
1387 nLen = 0;
1388 break;
1390 rPar.Get(0)->PutInteger( nLen );
1395 // 1st parameter == class name, other parameters for initialisation
1396 void SbRtl_CreateUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1398 RTL_Impl_CreateUnoStruct( rPar );
1402 // 1st parameter == service-name
1403 void SbRtl_CreateUnoService(StarBASIC *, SbxArray & rPar, bool)
1405 RTL_Impl_CreateUnoService( rPar );
1408 void SbRtl_CreateUnoServiceWithArguments(StarBASIC *, SbxArray & rPar, bool)
1410 RTL_Impl_CreateUnoServiceWithArguments( rPar );
1414 void SbRtl_CreateUnoValue(StarBASIC *, SbxArray & rPar, bool)
1416 RTL_Impl_CreateUnoValue( rPar );
1420 // no parameters
1421 void SbRtl_GetProcessServiceManager(StarBASIC *, SbxArray & rPar, bool)
1423 RTL_Impl_GetProcessServiceManager( rPar );
1427 // 1st parameter == Sequence<PropertyValue>
1428 void SbRtl_CreatePropertySet(StarBASIC *, SbxArray & rPar, bool)
1430 RTL_Impl_CreatePropertySet( rPar );
1434 // multiple interface-names as parameters
1435 void SbRtl_HasUnoInterfaces(StarBASIC *, SbxArray & rPar, bool)
1437 RTL_Impl_HasInterfaces( rPar );
1441 void SbRtl_IsUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1443 RTL_Impl_IsUnoStruct( rPar );
1447 void SbRtl_EqualUnoObjects(StarBASIC *, SbxArray & rPar, bool)
1449 RTL_Impl_EqualUnoObjects( rPar );
1452 void SbRtl_CreateUnoDialog(StarBASIC *, SbxArray & rPar, bool)
1454 RTL_Impl_CreateUnoDialog( rPar );
1457 // Return the application standard lib as root scope
1458 void SbRtl_GlobalScope(StarBASIC * pBasic, SbxArray & rPar, bool)
1460 SbxObject* p = pBasic;
1461 while( p->GetParent() )
1463 p = p->GetParent();
1465 SbxVariableRef refVar = rPar.Get(0);
1466 refVar->PutObject( p );
1469 // Helper functions to convert Url from/to system paths
1470 void SbRtl_ConvertToUrl(StarBASIC *, SbxArray & rPar, bool)
1472 if ( rPar.Count() == 2 )
1474 OUString aStr = rPar.Get(1)->GetOUString();
1475 INetURLObject aURLObj( aStr, INetProtocol::File );
1476 OUString aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1477 if( aFileURL.isEmpty() )
1479 osl::File::getFileURLFromSystemPath(aStr, aFileURL);
1481 if( aFileURL.isEmpty() )
1483 aFileURL = aStr;
1485 rPar.Get(0)->PutString(aFileURL);
1487 else
1489 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1493 void SbRtl_ConvertFromUrl(StarBASIC *, SbxArray & rPar, bool)
1495 if ( rPar.Count() == 2 )
1497 OUString aStr = rPar.Get(1)->GetOUString();
1498 OUString aSysPath;
1499 ::osl::File::getSystemPathFromFileURL( aStr, aSysPath );
1500 if( aSysPath.isEmpty() )
1502 aSysPath = aStr;
1504 rPar.Get(0)->PutString(aSysPath);
1506 else
1508 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1513 // Provide DefaultContext
1514 void SbRtl_GetDefaultContext(StarBASIC *, SbxArray & rPar, bool)
1516 RTL_Impl_GetDefaultContext( rPar );
1519 void SbRtl_Join(StarBASIC *, SbxArray & rPar, bool)
1521 sal_uInt16 nParCount = rPar.Count();
1522 if ( nParCount != 3 && nParCount != 2 )
1524 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1525 return;
1527 SbxBase* pParObj = rPar.Get(1)->GetObject();
1528 SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
1529 if( pArr )
1531 if( pArr->GetDims() != 1 )
1533 StarBASIC::Error( ERRCODE_BASIC_WRONG_DIMS ); // Syntax Error?!
1534 return;
1536 OUString aDelim;
1537 if( nParCount == 3 )
1539 aDelim = rPar.Get(2)->GetOUString();
1541 else
1543 aDelim = " ";
1545 OUStringBuffer aRetStr(32);
1546 short nLower, nUpper;
1547 pArr->GetDim( 1, nLower, nUpper );
1548 short aIdx[1];
1549 for (aIdx[0] = nLower; aIdx[0] <= nUpper; ++aIdx[0])
1551 OUString aStr = pArr->Get(aIdx)->GetOUString();
1552 aRetStr.append(aStr);
1553 if (aIdx[0] != nUpper)
1555 aRetStr.append(aDelim);
1558 rPar.Get(0)->PutString( aRetStr.makeStringAndClear() );
1560 else
1562 StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );
1567 void SbRtl_Split(StarBASIC *, SbxArray & rPar, bool)
1569 sal_uInt16 nParCount = rPar.Count();
1570 if ( nParCount < 2 )
1572 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1573 return;
1576 OUString aExpression = rPar.Get(1)->GetOUString();
1577 short nArraySize = 0;
1578 std::vector< OUString > vRet;
1579 if( !aExpression.isEmpty() )
1581 OUString aDelim;
1582 if( nParCount >= 3 )
1584 aDelim = rPar.Get(2)->GetOUString();
1586 else
1588 aDelim = " ";
1591 sal_Int32 nCount = -1;
1592 if( nParCount == 4 )
1594 nCount = rPar.Get(3)->GetLong();
1596 sal_Int32 nDelimLen = aDelim.getLength();
1597 if( nDelimLen )
1599 sal_Int32 iSearch = -1;
1600 sal_Int32 iStart = 0;
1603 bool bBreak = false;
1604 if( nCount >= 0 && nArraySize == nCount - 1 )
1606 bBreak = true;
1608 iSearch = aExpression.indexOf( aDelim, iStart );
1609 OUString aSubStr;
1610 if( iSearch >= 0 && !bBreak )
1612 aSubStr = aExpression.copy( iStart, iSearch - iStart );
1613 iStart = iSearch + nDelimLen;
1615 else
1617 aSubStr = aExpression.copy( iStart );
1619 vRet.push_back( aSubStr );
1620 nArraySize++;
1622 if( bBreak )
1624 break;
1627 while( iSearch >= 0 );
1629 else
1631 vRet.push_back( aExpression );
1632 nArraySize = 1;
1636 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
1637 pArray->unoAddDim( 0, nArraySize-1 );
1639 // insert parameter(s) into the array
1640 for( short i = 0 ; i < nArraySize ; i++ )
1642 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
1643 xVar->PutString( vRet[i] );
1644 pArray->Put( xVar.get(), &i );
1647 // return array
1648 SbxVariableRef refVar = rPar.Get(0);
1649 SbxFlagBits nFlags = refVar->GetFlags();
1650 refVar->ResetFlag( SbxFlagBits::Fixed );
1651 refVar->PutObject( pArray );
1652 refVar->SetFlags( nFlags );
1653 refVar->SetParameters( nullptr );
1656 // MonthName(month[, abbreviate])
1657 void SbRtl_MonthName(StarBASIC *, SbxArray & rPar, bool)
1659 sal_uInt16 nParCount = rPar.Count();
1660 if( nParCount != 2 && nParCount != 3 )
1662 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1663 return;
1666 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1667 if( !xCalendar.is() )
1669 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
1670 return;
1672 Sequence< CalendarItem2 > aMonthSeq = xCalendar->getMonths2();
1673 sal_Int32 nMonthCount = aMonthSeq.getLength();
1675 sal_Int16 nVal = rPar.Get(1)->GetInteger();
1676 if( nVal < 1 || nVal > nMonthCount )
1678 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1679 return;
1682 bool bAbbreviate = false;
1683 if( nParCount == 3 )
1684 bAbbreviate = rPar.Get(2)->GetBool();
1686 const CalendarItem2* pCalendarItems = aMonthSeq.getConstArray();
1687 const CalendarItem2& rItem = pCalendarItems[nVal - 1];
1689 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1690 rPar.Get(0)->PutString(aRetStr);
1693 // WeekdayName(weekday, abbreviate, firstdayofweek)
1694 void SbRtl_WeekdayName(StarBASIC *, SbxArray & rPar, bool)
1696 sal_uInt16 nParCount = rPar.Count();
1697 if( nParCount < 2 || nParCount > 4 )
1699 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1700 return;
1703 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1704 if( !xCalendar.is() )
1706 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
1707 return;
1710 Sequence< CalendarItem2 > aDaySeq = xCalendar->getDays2();
1711 sal_Int16 nDayCount = static_cast<sal_Int16>(aDaySeq.getLength());
1712 sal_Int16 nDay = rPar.Get(1)->GetInteger();
1713 sal_Int16 nFirstDay = 0;
1714 if( nParCount == 4 )
1716 nFirstDay = rPar.Get(3)->GetInteger();
1717 if( nFirstDay < 0 || nFirstDay > 7 )
1719 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1720 return;
1723 if( nFirstDay == 0 )
1725 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
1727 nDay = 1 + (nDay + nDayCount + nFirstDay - 2) % nDayCount;
1728 if( nDay < 1 || nDay > nDayCount )
1730 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1731 return;
1734 bool bAbbreviate = false;
1735 if( nParCount >= 3 )
1737 SbxVariable* pPar2 = rPar.Get(2);
1738 if( !pPar2->IsErr() )
1740 bAbbreviate = pPar2->GetBool();
1744 const CalendarItem2* pCalendarItems = aDaySeq.getConstArray();
1745 const CalendarItem2& rItem = pCalendarItems[nDay - 1];
1747 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1748 rPar.Get(0)->PutString( aRetStr );
1751 void SbRtl_Weekday(StarBASIC *, SbxArray & rPar, bool)
1753 sal_uInt16 nParCount = rPar.Count();
1754 if ( nParCount < 2 )
1756 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1758 else
1760 double aDate = rPar.Get(1)->GetDate();
1762 bool bFirstDay = false;
1763 sal_Int16 nFirstDay = 0;
1764 if ( nParCount > 2 )
1766 nFirstDay = rPar.Get(2)->GetInteger();
1767 bFirstDay = true;
1769 sal_Int16 nDay = implGetWeekDay( aDate, bFirstDay, nFirstDay );
1770 rPar.Get(0)->PutInteger( nDay );
1775 enum Interval
1777 INTERVAL_YYYY,
1778 INTERVAL_Q,
1779 INTERVAL_M,
1780 INTERVAL_Y,
1781 INTERVAL_D,
1782 INTERVAL_W,
1783 INTERVAL_WW,
1784 INTERVAL_H,
1785 INTERVAL_N,
1786 INTERVAL_S
1789 struct IntervalInfo
1791 Interval meInterval;
1792 char const * mStringCode;
1793 double mdValue;
1794 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_uInt16 nParCount = rPar.Count();
1855 if( nParCount != 4 )
1857 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1858 return;
1861 OUString aStringCode = rPar.Get(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.Get(2)->GetLong();
1870 double dDate = rPar.Get(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.Get(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_uInt16 nParCount = rPar.Count();
1962 if( nParCount < 4 || nParCount > 6 )
1964 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1965 return;
1968 OUString aStringCode = rPar.Get(1)->GetOUString();
1969 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1970 if( !pInfo )
1972 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1973 return;
1976 double dDate1 = rPar.Get(2)->GetDate();
1977 double dDate2 = rPar.Get(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.Get(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.Get(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_uInt16 nParCount = rPar.Count();
2153 if( nParCount < 3 || nParCount > 5 )
2155 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2156 return;
2159 OUString aStringCode = rPar.Get(1)->GetOUString();
2160 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
2161 if( !pInfo )
2163 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2164 return;
2167 double dDate = rPar.Get(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.Get(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.Get(3)->GetInteger();
2218 sal_Int16 nFirstWeek = 1; // Default
2219 if( nParCount == 5 )
2220 nFirstWeek = rPar.Get(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.Get(0)->PutLong( nRet );
2265 // FormatDateTime(Date[,NamedFormat])
2266 void SbRtl_FormatDateTime(StarBASIC *, SbxArray & rPar, bool)
2268 sal_uInt16 nParCount = rPar.Count();
2269 if( nParCount < 2 || nParCount > 3 )
2271 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2272 return;
2275 double dDate = rPar.Get(1)->GetDate();
2276 sal_Int16 nNamedFormat = 0;
2277 if( nParCount > 2 )
2279 nNamedFormat = rPar.Get(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 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.Get(0)->PutString( aRetStr );
2366 void SbRtl_Frac(StarBASIC *, SbxArray & rPar, bool)
2368 sal_uInt16 nParCount = rPar.Count();
2369 if( nParCount != 2)
2371 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2372 return;
2375 SbxVariable *pSbxVariable = rPar.Get(1);
2376 double dVal = pSbxVariable->GetDouble();
2377 if(dVal >= 0)
2378 rPar.Get(0)->PutDouble(dVal - ::rtl::math::approxFloor(dVal));
2379 else
2380 rPar.Get(0)->PutDouble(dVal - ::rtl::math::approxCeil(dVal));
2383 void SbRtl_Round(StarBASIC *, SbxArray & rPar, bool)
2385 sal_uInt16 nParCount = rPar.Count();
2386 if( nParCount != 2 && nParCount != 3 )
2388 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2389 return;
2392 SbxVariable *pSbxVariable = rPar.Get(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.Get(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.Get(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_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2471 aParams[ 1 ] <<= rPar.Get(2)->GetDouble();
2472 aParams[ 2 ] <<= rPar.Get(3)->GetDouble();
2473 aParams[ 3 ] <<= rPar.Get(4)->GetDouble();
2475 CallFunctionAccessFunction( aParams, "SYD", rPar.Get( 0 ) );
2478 void SbRtl_SLN(StarBASIC *, SbxArray & rPar, bool)
2480 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2492 aParams[ 1 ] <<= rPar.Get(2)->GetDouble();
2493 aParams[ 2 ] <<= rPar.Get(3)->GetDouble();
2495 CallFunctionAccessFunction( aParams, "SLN", rPar.Get( 0 ) );
2498 void SbRtl_Pmt(StarBASIC *, SbxArray & rPar, bool)
2500 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2510 double nper = rPar.Get(2)->GetDouble();
2511 double pmt = rPar.Get(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.Get(4)->GetType() != SbxEMPTY )
2521 fv = rPar.Get(4)->GetDouble();
2523 // type
2524 if ( nArgCount >= 5 )
2526 if( rPar.Get(5)->GetType() != SbxEMPTY )
2527 type = rPar.Get(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.Get( 0 ) );
2540 void SbRtl_PPmt(StarBASIC *, SbxArray & rPar, bool)
2542 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2552 double per = rPar.Get(2)->GetDouble();
2553 double nper = rPar.Get(3)->GetDouble();
2554 double pv = rPar.Get(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.Get(5)->GetType() != SbxEMPTY )
2564 fv = rPar.Get(5)->GetDouble();
2566 // type
2567 if ( nArgCount >= 6 )
2569 if( rPar.Get(6)->GetType() != SbxEMPTY )
2570 type = rPar.Get(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.Get( 0 ) );
2584 void SbRtl_PV(StarBASIC *, SbxArray & rPar, bool)
2586 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2596 double nper = rPar.Get(2)->GetDouble();
2597 double pmt = rPar.Get(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.Get(4)->GetType() != SbxEMPTY )
2607 fv = rPar.Get(4)->GetDouble();
2609 // type
2610 if ( nArgCount >= 5 )
2612 if( rPar.Get(5)->GetType() != SbxEMPTY )
2613 type = rPar.Get(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.Get( 0 ) );
2626 void SbRtl_NPV(StarBASIC *, SbxArray & rPar, bool)
2628 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2638 Any aValues = sbxToUnoValue( rPar.Get(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.Get( 0 ) );
2651 void SbRtl_NPer(StarBASIC *, SbxArray & rPar, bool)
2653 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2663 double pmt = rPar.Get(2)->GetDouble();
2664 double pv = rPar.Get(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.Get(4)->GetType() != SbxEMPTY )
2674 fv = rPar.Get(4)->GetDouble();
2676 // type
2677 if ( nArgCount >= 5 )
2679 if( rPar.Get(5)->GetType() != SbxEMPTY )
2680 type = rPar.Get(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.Get( 0 ) );
2693 void SbRtl_MIRR(StarBASIC *, SbxArray & rPar, bool)
2695 sal_uInt16 nArgCount = rPar.Count()-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.Get(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.Get(2)->GetDouble();
2716 aParams[ 2 ] <<= rPar.Get(3)->GetDouble();
2718 CallFunctionAccessFunction( aParams, "MIRR", rPar.Get( 0 ) );
2721 void SbRtl_IRR(StarBASIC *, SbxArray & rPar, bool)
2723 sal_uInt16 nArgCount = rPar.Count()-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.Get(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.Get(2)->GetType() != SbxEMPTY )
2745 guess = rPar.Get(2)->GetDouble();
2748 Sequence< Any > aParams( 2 );
2749 aParams[ 0 ] = aValues;
2750 aParams[ 1 ] <<= guess;
2752 CallFunctionAccessFunction( aParams, "IRR", rPar.Get( 0 ) );
2755 void SbRtl_IPmt(StarBASIC *, SbxArray & rPar, bool)
2757 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2767 double per = rPar.Get(2)->GetInteger();
2768 double nper = rPar.Get(3)->GetDouble();
2769 double pv = rPar.Get(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.Get(5)->GetType() != SbxEMPTY )
2779 fv = rPar.Get(5)->GetDouble();
2781 // type
2782 if ( nArgCount >= 6 )
2784 if( rPar.Get(6)->GetType() != SbxEMPTY )
2785 type = rPar.Get(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.Get( 0 ) );
2799 void SbRtl_FV(StarBASIC *, SbxArray & rPar, bool)
2801 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2811 double nper = rPar.Get(2)->GetDouble();
2812 double pmt = rPar.Get(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.Get(4)->GetType() != SbxEMPTY )
2822 pv = rPar.Get(4)->GetDouble();
2824 // type
2825 if ( nArgCount >= 5 )
2827 if( rPar.Get(5)->GetType() != SbxEMPTY )
2828 type = rPar.Get(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.Get( 0 ) );
2841 void SbRtl_DDB(StarBASIC *, SbxArray & rPar, bool)
2843 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2853 double salvage = rPar.Get(2)->GetDouble();
2854 double life = rPar.Get(3)->GetDouble();
2855 double period = rPar.Get(4)->GetDouble();
2857 // set default values for Optional args
2858 double factor = 2;
2860 // factor
2861 if ( nArgCount >= 5 )
2863 if( rPar.Get(5)->GetType() != SbxEMPTY )
2864 factor = rPar.Get(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.Get( 0 ) );
2877 void SbRtl_Rate(StarBASIC *, SbxArray & rPar, bool)
2879 sal_uInt16 nArgCount = rPar.Count()-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.Get(1)->GetDouble();
2893 pmt = rPar.Get(2)->GetDouble();
2894 pv = rPar.Get(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.Get(4)->GetType() != SbxEMPTY )
2905 fv = rPar.Get(4)->GetDouble();
2908 // type
2909 if ( nArgCount >= 5 )
2911 if( rPar.Get(5)->GetType() != SbxEMPTY )
2912 type = rPar.Get(5)->GetDouble();
2915 // guess
2916 if ( nArgCount >= 6 )
2918 if( rPar.Get(6)->GetType() != SbxEMPTY )
2919 guess = rPar.Get(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.Get( 0 ) );
2933 void SbRtl_StrReverse(StarBASIC *, SbxArray & rPar, bool)
2935 if ( rPar.Count() != 2 )
2937 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2938 return;
2941 SbxVariable *pSbxVariable = rPar.Get(1);
2942 if( pSbxVariable->IsNull() )
2944 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2945 return;
2948 OUString aStr = comphelper::string::reverseString(pSbxVariable->GetOUString());
2949 rPar.Get(0)->PutString( aStr );
2952 void SbRtl_CompatibilityMode(StarBASIC *, SbxArray & rPar, bool)
2954 bool bEnabled = false;
2955 sal_uInt16 nCount = rPar.Count();
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.Get(1)->GetBool() );
2966 bEnabled = pInst->IsCompatibility();
2968 rPar.Get(0)->PutBool( bEnabled );
2971 void SbRtl_Input(StarBASIC *, SbxArray & rPar, bool)
2973 // 2 parameters needed
2974 if ( rPar.Count() < 3 )
2976 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2977 return;
2980 sal_uInt16 nByteCount = rPar.Get(1)->GetUShort();
2981 sal_Int16 nFileNumber = rPar.Get(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.Get(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.Get(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: */