LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / basic / source / runtime / methods1.cxx
blob4e471362932b93df9000bdac50fdc008b0da5cc5
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>
54 #include <rtl/math.h>
55 #include <svl/numformat.hxx>
57 #include <comphelper/processfactory.hxx>
58 #include <comphelper/string.hxx>
60 #include <com/sun/star/uno/Sequence.hxx>
61 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 #include <com/sun/star/i18n/LocaleCalendar2.hpp>
63 #include <com/sun/star/sheet/XFunctionAccess.hpp>
65 #include <officecfg/Office/Scripting.hxx>
67 #include <memory>
69 using namespace comphelper;
70 using namespace com::sun::star::i18n;
71 using namespace com::sun::star::lang;
72 using namespace com::sun::star::sheet;
73 using namespace com::sun::star::uno;
75 static Reference< XCalendar4 > const & getLocaleCalendar()
77 static Reference< XCalendar4 > xCalendar = LocaleCalendar2::create(getProcessComponentContext());
78 static css::lang::Locale aLastLocale;
79 static bool bNeedsReload = true;
81 css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale();
82 bNeedsReload = bNeedsReload ||
83 ( aLocale.Language != aLastLocale.Language ||
84 aLocale.Country != aLastLocale.Country ||
85 aLocale.Variant != aLastLocale.Variant );
86 if( bNeedsReload )
88 bNeedsReload = false;
89 aLastLocale = aLocale;
90 xCalendar->loadDefaultCalendar( aLocale );
92 return xCalendar;
95 #if HAVE_FEATURE_SCRIPTING
97 void SbRtl_CallByName(StarBASIC *, SbxArray & rPar, bool)
99 const sal_Int16 vbGet = 2;
100 const sal_Int16 vbLet = 4;
101 const sal_Int16 vbMethod = 1;
102 const sal_Int16 vbSet = 8;
104 // At least 3 parameter needed plus function itself -> 4
105 sal_uInt32 nParCount = rPar.Count();
106 if ( nParCount < 4 )
108 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
109 return;
112 // 1. parameter is object
113 SbxBase* pObjVar = rPar.Get(1)->GetObject();
114 SbxObject* pObj = nullptr;
115 if( pObjVar )
116 pObj = dynamic_cast<SbxObject*>( pObjVar );
117 if( !pObj )
118 if (auto pSbxVar = dynamic_cast<const SbxVariable*>( pObjVar))
119 pObj = dynamic_cast<SbxObject*>( pSbxVar->GetObject() );
120 if( !pObj )
122 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
123 return;
126 // 2. parameter is ProcName
127 OUString aNameStr = rPar.Get(2)->GetOUString();
129 // 3. parameter is CallType
130 sal_Int16 nCallType = rPar.Get(3)->GetInteger();
132 //SbxObject* pFindObj = NULL;
133 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::DontCare );
134 if( pFindVar == nullptr )
136 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
137 return;
140 switch( nCallType )
142 case vbGet:
144 SbxValues aVals;
145 aVals.eType = SbxVARIANT;
146 pFindVar->Get( aVals );
148 SbxVariableRef refVar = rPar.Get(0);
149 refVar->Put( aVals );
151 break;
152 case vbLet:
153 case vbSet:
155 if ( nParCount != 5 )
157 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
158 return;
160 SbxVariableRef pValVar = rPar.Get(4);
161 if( nCallType == vbLet )
163 SbxValues aVals;
164 aVals.eType = SbxVARIANT;
165 pValVar->Get( aVals );
166 pFindVar->Put( aVals );
168 else
170 SbxVariableRef rFindVar = pFindVar;
171 SbiInstance* pInst = GetSbData()->pInst;
172 SbiRuntime* pRT = pInst ? pInst->pRun : nullptr;
173 if( pRT != nullptr )
175 pRT->StepSET_Impl( pValVar, rFindVar );
179 break;
180 case vbMethod:
182 SbMethod* pMeth = dynamic_cast<SbMethod*>( pFindVar );
183 if( pMeth == nullptr )
185 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
186 return;
189 // Setup parameters
190 SbxArrayRef xArray;
191 sal_uInt32 nMethParamCount = nParCount - 4;
192 if( nMethParamCount > 0 )
194 xArray = new SbxArray;
195 for( sal_uInt32 i = 0 ; i < nMethParamCount ; i++ )
197 SbxVariable* pPar = rPar.Get(i + 4);
198 xArray->Put(pPar, i + 1);
202 // Call method
203 SbxVariableRef refVar = rPar.Get(0);
204 if( xArray.is() )
205 pMeth->SetParameters( xArray.get() );
206 pMeth->Call( refVar.get() );
207 pMeth->SetParameters( nullptr );
209 break;
210 default:
211 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINED );
215 void SbRtl_CBool(StarBASIC *, SbxArray & rPar, bool) // JSM
217 bool bVal = false;
218 if (rPar.Count() == 2)
220 SbxVariable* pSbxVariable = rPar.Get(1);
221 bVal = pSbxVariable->GetBool();
223 else
225 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
227 rPar.Get(0)->PutBool(bVal);
230 void SbRtl_CByte(StarBASIC *, SbxArray & rPar, bool) // JSM
232 sal_uInt8 nByte = 0;
233 if (rPar.Count() == 2)
235 SbxVariable* pSbxVariable = rPar.Get(1);
236 nByte = pSbxVariable->GetByte();
238 else
240 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
242 rPar.Get(0)->PutByte(nByte);
245 void SbRtl_CCur(StarBASIC *, SbxArray & rPar, bool)
247 sal_Int64 nCur = 0;
248 if (rPar.Count() == 2)
250 SbxVariable* pSbxVariable = rPar.Get(1);
251 nCur = pSbxVariable->GetCurrency();
253 else
255 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
257 rPar.Get(0)->PutCurrency(nCur);
260 void SbRtl_CDec(StarBASIC *, SbxArray & rPar, bool)
262 #ifdef _WIN32
263 SbxDecimal* pDec = nullptr;
264 if (rPar.Count() == 2)
266 SbxVariable* pSbxVariable = rPar.Get(1);
267 pDec = pSbxVariable->GetDecimal();
269 else
271 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
273 rPar.Get(0)->PutDecimal(pDec);
274 #else
275 rPar.Get(0)->PutEmpty();
276 StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTED);
277 #endif
280 void SbRtl_CDate(StarBASIC *, SbxArray & rPar, bool) // JSM
282 double nVal = 0.0;
283 if (rPar.Count() == 2)
285 SbxVariable* pSbxVariable = rPar.Get(1);
286 nVal = pSbxVariable->GetDate();
288 else
290 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
292 rPar.Get(0)->PutDate(nVal);
295 void SbRtl_CDbl(StarBASIC *, SbxArray & rPar, bool) // JSM
297 double nVal = 0.0;
298 if (rPar.Count() == 2)
300 SbxVariable* pSbxVariable = rPar.Get(1);
301 if( pSbxVariable->GetType() == SbxSTRING )
303 // #41690
304 OUString aScanStr = pSbxVariable->GetOUString();
305 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, nVal );
306 if( Error != ERRCODE_NONE )
308 StarBASIC::Error( Error );
311 else
313 nVal = pSbxVariable->GetDouble();
316 else
318 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
321 rPar.Get(0)->PutDouble(nVal);
324 void SbRtl_CInt(StarBASIC *, SbxArray & rPar, bool) // JSM
326 sal_Int16 nVal = 0;
327 if (rPar.Count() == 2)
329 SbxVariable* pSbxVariable = rPar.Get(1);
330 nVal = pSbxVariable->GetInteger();
332 else
334 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
336 rPar.Get(0)->PutInteger(nVal);
339 void SbRtl_CLng(StarBASIC *, SbxArray & rPar, bool) // JSM
341 sal_Int32 nVal = 0;
342 if (rPar.Count() == 2)
344 SbxVariable* pSbxVariable = rPar.Get(1);
345 nVal = pSbxVariable->GetLong();
347 else
349 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
351 rPar.Get(0)->PutLong(nVal);
354 void SbRtl_CSng(StarBASIC *, SbxArray & rPar, bool) // JSM
356 float nVal = float(0.0);
357 if (rPar.Count() == 2)
359 SbxVariable* pSbxVariable = rPar.Get(1);
360 if( pSbxVariable->GetType() == SbxSTRING )
362 // #41690
363 double dVal = 0.0;
364 OUString aScanStr = pSbxVariable->GetOUString();
365 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, dVal, /*bSingle=*/true );
366 if( SbxBase::GetError() == ERRCODE_NONE && Error != ERRCODE_NONE )
368 StarBASIC::Error( Error );
370 nVal = static_cast<float>(dVal);
372 else
374 nVal = pSbxVariable->GetSingle();
377 else
379 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
381 rPar.Get(0)->PutSingle(nVal);
384 void SbRtl_CStr(StarBASIC *, SbxArray & rPar, bool) // JSM
386 OUString aString;
387 if (rPar.Count() == 2)
389 SbxVariable* pSbxVariable = rPar.Get(1);
390 aString = pSbxVariable->GetOUString();
392 else
394 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
396 rPar.Get(0)->PutString(aString);
399 void SbRtl_CVar(StarBASIC *, SbxArray & rPar, bool) // JSM
401 SbxValues aVals( SbxVARIANT );
402 if (rPar.Count() == 2)
404 SbxVariable* pSbxVariable = rPar.Get(1);
405 pSbxVariable->Get( aVals );
407 else
409 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
411 rPar.Get(0)->Put(aVals);
414 void SbRtl_CVErr(StarBASIC *, SbxArray & rPar, bool)
416 sal_Int16 nErrCode = 0;
417 if (rPar.Count() == 2)
419 SbxVariable* pSbxVariable = rPar.Get(1);
420 nErrCode = pSbxVariable->GetInteger();
422 else
424 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
426 rPar.Get(0)->PutErr(nErrCode);
429 void SbRtl_Iif(StarBASIC *, SbxArray & rPar, bool) // JSM
431 if (rPar.Count() == 4)
433 if (rPar.Get(1)->GetBool())
435 *rPar.Get(0) = *rPar.Get(2);
437 else
439 *rPar.Get(0) = *rPar.Get(3);
442 else
444 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
448 void SbRtl_GetSystemType(StarBASIC *, SbxArray & rPar, bool)
450 if (rPar.Count() != 1)
452 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
454 else
456 // Removed for SRC595
457 rPar.Get(0)->PutInteger(-1);
461 void SbRtl_GetGUIType(StarBASIC *, SbxArray & rPar, bool)
463 if (rPar.Count() != 1)
465 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
467 else
469 // 17.7.2000 Make simple solution for testtool / fat office
470 #if defined(_WIN32)
471 rPar.Get(0)->PutInteger(1);
472 #elif defined(UNX)
473 rPar.Get(0)->PutInteger(4);
474 #else
475 rPar.Get(0)->PutInteger(-1);
476 #endif
480 void SbRtl_Red(StarBASIC *, SbxArray & rPar, bool)
482 if (rPar.Count() != 2)
484 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
486 else
488 sal_Int32 nRGB = rPar.Get(1)->GetLong();
489 nRGB &= 0x00FF0000;
490 nRGB >>= 16;
491 rPar.Get(0)->PutInteger(static_cast<sal_Int16>(nRGB));
495 void SbRtl_Green(StarBASIC *, SbxArray & rPar, bool)
497 if (rPar.Count() != 2)
499 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
501 else
503 sal_Int32 nRGB = rPar.Get(1)->GetLong();
504 nRGB &= 0x0000FF00;
505 nRGB >>= 8;
506 rPar.Get(0)->PutInteger(static_cast<sal_Int16>(nRGB));
510 void SbRtl_Blue(StarBASIC *, SbxArray & rPar, bool)
512 if (rPar.Count() != 2)
514 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
516 else
518 sal_Int32 nRGB = rPar.Get(1)->GetLong();
519 nRGB &= 0x000000FF;
520 rPar.Get(0)->PutInteger(static_cast<sal_Int16>(nRGB));
525 void SbRtl_Switch(StarBASIC *, SbxArray & rPar, bool)
527 sal_uInt32 nCount = rPar.Count();
528 if( !(nCount & 0x0001 ))
530 // number of arguments must be odd
531 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
533 sal_uInt32 nCurExpr = 1;
534 while( nCurExpr < (nCount-1) )
536 if (rPar.Get(nCurExpr)->GetBool())
538 (*rPar.Get(0)) = *(rPar.Get(nCurExpr + 1));
539 return;
541 nCurExpr += 2;
543 rPar.Get(0)->PutNull();
546 //i#64882# Common wait impl for existing Wait and new WaitUntil
547 // rtl functions
548 void Wait_Impl( bool bDurationBased, SbxArray& rPar )
550 if (rPar.Count() != 2)
552 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
553 return;
555 tools::Long nWait = 0;
556 if ( bDurationBased )
558 double dWait = rPar.Get(1)->GetDouble();
559 double dNow = Now_Impl();
560 double dSecs = ( dWait - dNow ) * 24.0 * 3600.0;
561 nWait = static_cast<tools::Long>( dSecs * 1000 ); // wait in thousands of sec
563 else
565 nWait = rPar.Get(1)->GetLong();
567 if( nWait < 0 )
569 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
570 return;
573 Timer aTimer("basic Wait_Impl");
574 aTimer.SetTimeout( nWait );
575 aTimer.Start();
576 while ( aTimer.IsActive() && !Application::IsQuit())
578 Application::Yield();
582 //i#64882#
583 void SbRtl_Wait(StarBASIC *, SbxArray & rPar, bool)
585 Wait_Impl( false, rPar );
588 //i#64882# add new WaitUntil ( for application.wait )
589 // share wait_impl with 'normal' oobasic wait
590 void SbRtl_WaitUntil(StarBASIC *, SbxArray & rPar, bool)
592 Wait_Impl( true, rPar );
595 void SbRtl_DoEvents(StarBASIC *, SbxArray & rPar, bool)
597 // don't understand what upstream are up to
598 // we already process application events etc. in between
599 // basic runtime pcode ( on a timed basis )
600 // always return 0
601 rPar.Get(0)->PutInteger(0);
602 Application::Reschedule( true );
605 void SbRtl_GetGUIVersion(StarBASIC *, SbxArray & rPar, bool)
607 if (rPar.Count() != 1)
609 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
611 else
613 // Removed for SRC595
614 rPar.Get(0)->PutLong(-1);
618 void SbRtl_Choose(StarBASIC *, SbxArray & rPar, bool)
620 if (rPar.Count() < 2)
622 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
624 sal_Int16 nIndex = rPar.Get(1)->GetInteger();
625 sal_uInt32 nCount = rPar.Count();
626 nCount--;
627 if( nCount == 1 || nIndex > sal::static_int_cast<sal_Int16>(nCount-1) || nIndex < 1 )
629 rPar.Get(0)->PutNull();
630 return;
632 (*rPar.Get(0)) = *(rPar.Get(nIndex + 1));
636 void SbRtl_Trim(StarBASIC *, SbxArray & rPar, bool)
638 if (rPar.Count() < 2)
640 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
642 else
644 OUString aStr(comphelper::string::strip(rPar.Get(1)->GetOUString(), ' '));
645 rPar.Get(0)->PutString(aStr);
649 void SbRtl_GetSolarVersion(StarBASIC *, SbxArray & rPar, bool)
651 rPar.Get(0)->PutLong(LIBO_VERSION_MAJOR * 10000 + LIBO_VERSION_MINOR * 100
652 + LIBO_VERSION_MICRO * 1);
655 void SbRtl_TwipsPerPixelX(StarBASIC *, SbxArray & rPar, bool)
657 sal_Int32 nResult = 0;
658 Size aSize( 100,0 );
659 MapMode aMap( MapUnit::MapTwip );
660 OutputDevice* pDevice = Application::GetDefaultDevice();
661 if( pDevice )
663 aSize = pDevice->PixelToLogic( aSize, aMap );
664 nResult = aSize.Width() / 100;
666 rPar.Get(0)->PutLong(nResult);
669 void SbRtl_TwipsPerPixelY(StarBASIC *, SbxArray & rPar, bool)
671 sal_Int32 nResult = 0;
672 Size aSize( 0,100 );
673 MapMode aMap( MapUnit::MapTwip );
674 OutputDevice* pDevice = Application::GetDefaultDevice();
675 if( pDevice )
677 aSize = pDevice->PixelToLogic( aSize, aMap );
678 nResult = aSize.Height() / 100;
680 rPar.Get(0)->PutLong(nResult);
684 void SbRtl_FreeLibrary(StarBASIC *, SbxArray & rPar, bool)
686 if (rPar.Count() != 2)
688 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
690 GetSbData()->pInst->GetDllMgr()->FreeDll(rPar.Get(1)->GetOUString());
692 bool IsBaseIndexOne()
694 bool bResult = false;
695 if ( GetSbData()->pInst && GetSbData()->pInst->pRun )
697 sal_uInt16 res = GetSbData()->pInst->pRun->GetBase();
698 if ( res )
700 bResult = true;
703 return bResult;
706 void SbRtl_Array(StarBASIC *, SbxArray & rPar, bool)
708 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
709 sal_uInt32 nArraySize = rPar.Count() - 1;
710 bool bIncIndex = IsBaseIndexOne();
711 if( nArraySize )
713 if ( bIncIndex )
715 pArray->AddDim(1, sal::static_int_cast<sal_Int32>(nArraySize));
717 else
719 pArray->AddDim(0, sal::static_int_cast<sal_Int32>(nArraySize) - 1);
722 else
724 pArray->unoAddDim(0, -1);
727 // insert parameters into the array
728 for( sal_uInt32 i = 0 ; i < nArraySize ; i++ )
730 SbxVariable* pVar = rPar.Get(i + 1);
731 SbxVariable* pNew = new SbxEnsureParentVariable(*pVar);
732 pNew->SetFlag( SbxFlagBits::Write );
733 sal_Int32 aIdx[1];
734 aIdx[0] = static_cast<sal_Int32>(i);
735 if ( bIncIndex )
737 ++aIdx[0];
739 pArray->Put(pNew, aIdx);
742 // return array
743 SbxVariableRef refVar = rPar.Get(0);
744 SbxFlagBits nFlags = refVar->GetFlags();
745 refVar->ResetFlag( SbxFlagBits::Fixed );
746 refVar->PutObject( pArray );
747 refVar->SetFlags( nFlags );
748 refVar->SetParameters( nullptr );
752 // Featurewish #57868
753 // The function returns a variant-array; if there are no parameters passed,
754 // an empty array is created (according to dim a(); equal to a sequence of
755 // the length 0 in Uno).
756 // If there are parameters passed, there's a dimension created for each of
757 // them; DimArray( 2, 2, 4 ) is equal to DIM a( 2, 2, 4 )
758 // the array is always of the type variant
759 void SbRtl_DimArray(StarBASIC *, SbxArray & rPar, bool)
761 SbxDimArray * pArray = new SbxDimArray( SbxVARIANT );
762 sal_uInt32 nArrayDims = rPar.Count() - 1;
763 if( nArrayDims > 0 )
765 for( sal_uInt32 i = 0; i < nArrayDims ; i++ )
767 sal_Int32 ub = rPar.Get(i + 1)->GetLong();
768 if( ub < 0 )
770 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
771 ub = 0;
773 pArray->AddDim(0, ub);
776 else
778 pArray->unoAddDim(0, -1);
780 SbxVariableRef refVar = rPar.Get(0);
781 SbxFlagBits nFlags = refVar->GetFlags();
782 refVar->ResetFlag( SbxFlagBits::Fixed );
783 refVar->PutObject( pArray );
784 refVar->SetFlags( nFlags );
785 refVar->SetParameters( nullptr );
789 * FindObject and FindPropertyObject make it possible to
790 * address objects and properties of the type Object with
791 * their name as string-parameters at the runtime.
793 * Example:
794 * MyObj.Prop1.Bla = 5
796 * is equal to:
797 * dim ObjVar as Object
798 * dim ObjProp as Object
799 * ObjName$ = "MyObj"
800 * ObjVar = FindObject( ObjName$ )
801 * PropName$ = "Prop1"
802 * ObjProp = FindPropertyObject( ObjVar, PropName$ )
803 * ObjProp.Bla = 5
805 * The names can be created dynamically at the runtime
806 * so that e. g. via controls "TextEdit1" to "TextEdit5"
807 * can be iterated in a dialog in a loop.
811 // 1st parameter = the object's name as string
812 void SbRtl_FindObject(StarBASIC *, SbxArray & rPar, bool)
814 if (rPar.Count() < 2)
816 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
817 return;
820 OUString aNameStr = rPar.Get(1)->GetOUString();
822 SbxBase* pFind = StarBASIC::FindSBXInCurrentScope( aNameStr );
823 SbxObject* pFindObj = nullptr;
824 if( pFind )
826 pFindObj = dynamic_cast<SbxObject*>( pFind );
828 SbxVariableRef refVar = rPar.Get(0);
829 refVar->PutObject( pFindObj );
832 // address object-property in an object
833 // 1st parameter = object
834 // 2nd parameter = the property's name as string
835 void SbRtl_FindPropertyObject(StarBASIC *, SbxArray & rPar, bool)
837 if (rPar.Count() < 3)
839 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
840 return;
843 SbxBase* pObjVar = rPar.Get(1)->GetObject();
844 SbxObject* pObj = nullptr;
845 if( pObjVar )
847 pObj = dynamic_cast<SbxObject*>( pObjVar );
849 if( !pObj )
850 if (auto pSbxVar = dynamic_cast<const SbxVariable*>( pObjVar))
851 pObj = dynamic_cast<SbxObject*>( pSbxVar->GetObject() );
853 OUString aNameStr = rPar.Get(2)->GetOUString();
855 SbxObject* pFindObj = nullptr;
856 if( pObj )
858 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::Object );
859 pFindObj = dynamic_cast<SbxObject*>( pFindVar );
861 else
863 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETER );
866 SbxVariableRef refVar = rPar.Get(0);
867 refVar->PutObject( pFindObj );
871 static bool lcl_WriteSbxVariable( const SbxVariable& rVar, SvStream* pStrm,
872 bool bBinary, short nBlockLen, bool bIsArray )
874 sal_uInt64 const nFPos = pStrm->Tell();
876 bool bIsVariant = !rVar.IsFixed();
877 SbxDataType eType = rVar.GetType();
879 switch( eType )
881 case SbxBOOL:
882 case SbxCHAR:
883 case SbxBYTE:
884 if( bIsVariant )
886 pStrm->WriteUInt16( SbxBYTE ); // VarType Id
888 pStrm->WriteUChar( rVar.GetByte() );
889 break;
891 case SbxEMPTY:
892 case SbxNULL:
893 case SbxVOID:
894 case SbxINTEGER:
895 case SbxUSHORT:
896 case SbxINT:
897 case SbxUINT:
898 if( bIsVariant )
900 pStrm->WriteUInt16( SbxINTEGER ); // VarType Id
902 pStrm->WriteInt16( rVar.GetInteger() );
903 break;
905 case SbxLONG:
906 case SbxULONG:
907 if( bIsVariant )
909 pStrm->WriteUInt16( SbxLONG ); // VarType Id
911 pStrm->WriteInt32( rVar.GetLong() );
912 break;
913 case SbxSALINT64:
914 case SbxSALUINT64:
915 if( bIsVariant )
917 pStrm->WriteUInt16( SbxSALINT64 ); // VarType Id
919 pStrm->WriteUInt64( rVar.GetInt64() );
920 break;
921 case SbxSINGLE:
922 if( bIsVariant )
924 pStrm->WriteUInt16( eType ); // VarType Id
926 pStrm->WriteFloat( rVar.GetSingle() );
927 break;
929 case SbxDOUBLE:
930 case SbxCURRENCY:
931 case SbxDATE:
932 if( bIsVariant )
934 pStrm->WriteUInt16( eType ); // VarType Id
936 pStrm->WriteDouble( rVar.GetDouble() );
937 break;
939 case SbxSTRING:
940 case SbxLPSTR:
942 const OUString& rStr = rVar.GetOUString();
943 if( !bBinary || bIsArray )
945 if( bIsVariant )
947 pStrm->WriteUInt16( SbxSTRING );
949 pStrm->WriteUniOrByteString( rStr, osl_getThreadTextEncoding() );
951 else
953 // without any length information! without end-identifier!
954 // What does that mean for Unicode?! Choosing conversion to ByteString...
955 OString aByteStr(OUStringToOString(rStr, osl_getThreadTextEncoding()));
956 pStrm->WriteOString( aByteStr );
959 break;
961 default:
962 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
963 return false;
966 if( nBlockLen )
968 pStrm->Seek( nFPos + nBlockLen );
970 return pStrm->GetErrorCode() == ERRCODE_NONE;
973 static bool lcl_ReadSbxVariable( SbxVariable& rVar, SvStream* pStrm,
974 bool bBinary, short nBlockLen )
976 double aDouble;
978 sal_uInt64 const nFPos = pStrm->Tell();
980 bool bIsVariant = !rVar.IsFixed();
981 SbxDataType eVarType = rVar.GetType();
983 SbxDataType eSrcType = eVarType;
984 if( bIsVariant )
986 sal_uInt16 nTemp;
987 pStrm->ReadUInt16( nTemp );
988 eSrcType = static_cast<SbxDataType>(nTemp);
991 switch( eSrcType )
993 case SbxBOOL:
994 case SbxCHAR:
995 case SbxBYTE:
997 sal_uInt8 aByte;
998 pStrm->ReadUChar( aByte );
1000 if( bBinary && SbiRuntime::isVBAEnabled() && aByte == 1 && pStrm->eof() )
1002 aByte = 0;
1004 rVar.PutByte( aByte );
1006 break;
1008 case SbxEMPTY:
1009 case SbxNULL:
1010 case SbxVOID:
1011 case SbxINTEGER:
1012 case SbxUSHORT:
1013 case SbxINT:
1014 case SbxUINT:
1016 sal_Int16 aInt;
1017 pStrm->ReadInt16( aInt );
1018 rVar.PutInteger( aInt );
1020 break;
1022 case SbxLONG:
1023 case SbxULONG:
1025 sal_Int32 aInt;
1026 pStrm->ReadInt32( aInt );
1027 rVar.PutLong( aInt );
1029 break;
1030 case SbxSALINT64:
1031 case SbxSALUINT64:
1033 sal_uInt32 aInt;
1034 pStrm->ReadUInt32( aInt );
1035 rVar.PutInt64( static_cast<sal_Int64>(aInt) );
1037 break;
1038 case SbxSINGLE:
1040 float nS;
1041 pStrm->ReadFloat( nS );
1042 rVar.PutSingle( nS );
1044 break;
1046 case SbxDOUBLE:
1047 case SbxCURRENCY:
1049 pStrm->ReadDouble( aDouble );
1050 rVar.PutDouble( aDouble );
1052 break;
1054 case SbxDATE:
1056 pStrm->ReadDouble( aDouble );
1057 rVar.PutDate( aDouble );
1059 break;
1061 case SbxSTRING:
1062 case SbxLPSTR:
1064 OUString aStr = pStrm->ReadUniOrByteString(osl_getThreadTextEncoding());
1065 rVar.PutString( aStr );
1067 break;
1069 default:
1070 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1071 return false;
1074 if( nBlockLen )
1076 pStrm->Seek( nFPos + nBlockLen );
1078 return pStrm->GetErrorCode() == ERRCODE_NONE;
1082 // nCurDim = 1...n
1083 static bool lcl_WriteReadSbxArray( SbxDimArray& rArr, SvStream* pStrm,
1084 bool bBinary, sal_Int32 nCurDim, sal_Int32* pOtherDims, bool bWrite )
1086 SAL_WARN_IF( nCurDim <= 0,"basic", "Bad Dim");
1087 sal_Int32 nLower, nUpper;
1088 if (!rArr.GetDim(nCurDim, nLower, nUpper))
1089 return false;
1090 for(sal_Int32 nCur = nLower; nCur <= nUpper; nCur++ )
1092 pOtherDims[ nCurDim-1 ] = nCur;
1093 if( nCurDim != 1 )
1094 lcl_WriteReadSbxArray(rArr, pStrm, bBinary, nCurDim-1, pOtherDims, bWrite);
1095 else
1097 SbxVariable* pVar = rArr.Get(pOtherDims);
1098 bool bRet;
1099 if( bWrite )
1100 bRet = lcl_WriteSbxVariable(*pVar, pStrm, bBinary, 0, true );
1101 else
1102 bRet = lcl_ReadSbxVariable(*pVar, pStrm, bBinary, 0 );
1103 if( !bRet )
1104 return false;
1107 return true;
1110 static void PutGet( SbxArray& rPar, bool bPut )
1112 if (rPar.Count() != 4)
1114 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1115 return;
1117 sal_Int16 nFileNo = rPar.Get(1)->GetInteger();
1118 SbxVariable* pVar2 = rPar.Get(2);
1119 SbxDataType eType2 = pVar2->GetType();
1120 bool bHasRecordNo = (eType2 != SbxEMPTY && eType2 != SbxERROR);
1121 tools::Long nRecordNo = pVar2->GetLong();
1122 if ( nFileNo < 1 || ( bHasRecordNo && nRecordNo < 1 ) )
1124 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1125 return;
1127 nRecordNo--;
1128 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
1129 SbiStream* pSbStrm = pIO->GetStream( nFileNo );
1131 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Random)) )
1133 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
1134 return;
1137 SvStream* pStrm = pSbStrm->GetStrm();
1138 bool bRandom = pSbStrm->IsRandom();
1139 short nBlockLen = bRandom ? pSbStrm->GetBlockLen() : 0;
1141 if( bPut )
1143 pSbStrm->ExpandFile();
1146 if( bHasRecordNo )
1148 sal_uInt64 const nFilePos = bRandom
1149 ? static_cast<sal_uInt64>(nBlockLen * nRecordNo)
1150 : static_cast<sal_uInt64>(nRecordNo);
1151 pStrm->Seek( nFilePos );
1154 SbxDimArray* pArr = nullptr;
1155 SbxVariable* pVar = rPar.Get(3);
1156 if( pVar->GetType() & SbxARRAY )
1158 SbxBase* pParObj = pVar->GetObject();
1159 pArr = dynamic_cast<SbxDimArray*>( pParObj );
1162 bool bRet;
1164 if( pArr )
1166 sal_uInt64 const nFPos = pStrm->Tell();
1167 sal_Int32 nDims = pArr->GetDims();
1168 std::unique_ptr<sal_Int32[]> pDims(new sal_Int32[ nDims ]);
1169 bRet = lcl_WriteReadSbxArray(*pArr,pStrm,!bRandom,nDims,pDims.get(),bPut);
1170 pDims.reset();
1171 if( nBlockLen )
1172 pStrm->Seek( nFPos + nBlockLen );
1174 else
1176 if( bPut )
1177 bRet = lcl_WriteSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, false);
1178 else
1179 bRet = lcl_ReadSbxVariable(*pVar, pStrm, !bRandom, nBlockLen);
1181 if( !bRet || pStrm->GetErrorCode() )
1182 StarBASIC::Error( ERRCODE_BASIC_IO_ERROR );
1185 void SbRtl_Put(StarBASIC *, SbxArray & rPar, bool)
1187 PutGet( rPar, true );
1190 void SbRtl_Get(StarBASIC *, SbxArray & rPar, bool)
1192 PutGet( rPar, false );
1195 void SbRtl_Environ(StarBASIC *, SbxArray & rPar, bool)
1197 if (rPar.Count() != 2)
1199 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1200 return;
1202 OUString aResult;
1203 // should be ANSI but that's not possible under Win16 in the DLL
1204 OString aByteStr(OUStringToOString(rPar.Get(1)->GetOUString(),
1205 osl_getThreadTextEncoding()));
1206 const char* pEnvStr = getenv(aByteStr.getStr());
1207 if ( pEnvStr )
1209 aResult = OUString(pEnvStr, strlen(pEnvStr), osl_getThreadTextEncoding());
1211 rPar.Get(0)->PutString(aResult);
1214 static double GetDialogZoomFactor( bool bX, tools::Long nValue )
1216 OutputDevice* pDevice = Application::GetDefaultDevice();
1217 double nResult = 0;
1218 if( pDevice )
1220 Size aRefSize( nValue, nValue );
1221 Fraction aFracX( 1, 26 );
1222 Fraction aFracY( 1, 24 );
1223 MapMode aMap( MapUnit::MapAppFont, Point(), aFracX, aFracY );
1224 Size aScaledSize = pDevice->LogicToPixel( aRefSize, aMap );
1225 aRefSize = pDevice->LogicToPixel( aRefSize, MapMode(MapUnit::MapTwip) );
1227 double nRef, nScaled;
1228 if( bX )
1230 nRef = aRefSize.Width();
1231 nScaled = aScaledSize.Width();
1233 else
1235 nRef = aRefSize.Height();
1236 nScaled = aScaledSize.Height();
1238 nResult = nScaled / nRef;
1240 return nResult;
1244 void SbRtl_GetDialogZoomFactorX(StarBASIC *, SbxArray & rPar, bool)
1246 if (rPar.Count() != 2)
1248 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1249 return;
1251 rPar.Get(0)->PutDouble(GetDialogZoomFactor(true, rPar.Get(1)->GetLong()));
1254 void SbRtl_GetDialogZoomFactorY(StarBASIC *, SbxArray & rPar, bool)
1256 if (rPar.Count() != 2)
1258 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1259 return;
1261 rPar.Get(0)->PutDouble(GetDialogZoomFactor(false, rPar.Get(1)->GetLong()));
1265 void SbRtl_EnableReschedule(StarBASIC *, SbxArray & rPar, bool)
1267 rPar.Get(0)->PutEmpty();
1268 if (rPar.Count() != 2)
1269 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1270 if( GetSbData()->pInst )
1271 GetSbData()->pInst->EnableReschedule(rPar.Get(1)->GetBool());
1274 void SbRtl_GetSystemTicks(StarBASIC *, SbxArray & rPar, bool)
1276 if (rPar.Count() != 1)
1278 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1279 return;
1281 rPar.Get(0)->PutLong(tools::Time::GetSystemTicks());
1284 void SbRtl_GetPathSeparator(StarBASIC *, SbxArray & rPar, bool)
1286 if (rPar.Count() != 1)
1288 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1289 return;
1291 rPar.Get(0)->PutString(OUString(SAL_PATHDELIMITER));
1294 void SbRtl_ResolvePath(StarBASIC *, SbxArray & rPar, bool)
1296 if (rPar.Count() == 2)
1298 OUString aStr = rPar.Get(1)->GetOUString();
1299 rPar.Get(0)->PutString(aStr);
1301 else
1303 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1307 void SbRtl_TypeLen(StarBASIC *, SbxArray & rPar, bool)
1309 if (rPar.Count() != 2)
1311 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1313 else
1315 SbxDataType eType = rPar.Get(1)->GetType();
1316 sal_Int16 nLen = 0;
1317 switch( eType )
1319 case SbxEMPTY:
1320 case SbxNULL:
1321 case SbxVECTOR:
1322 case SbxARRAY:
1323 case SbxBYREF:
1324 case SbxVOID:
1325 case SbxHRESULT:
1326 case SbxPOINTER:
1327 case SbxDIMARRAY:
1328 case SbxCARRAY:
1329 case SbxUSERDEF:
1330 nLen = 0;
1331 break;
1333 case SbxINTEGER:
1334 case SbxERROR:
1335 case SbxUSHORT:
1336 case SbxINT:
1337 case SbxUINT:
1338 nLen = 2;
1339 break;
1341 case SbxLONG:
1342 case SbxSINGLE:
1343 case SbxULONG:
1344 nLen = 4;
1345 break;
1347 case SbxDOUBLE:
1348 case SbxCURRENCY:
1349 case SbxDATE:
1350 case SbxSALINT64:
1351 case SbxSALUINT64:
1352 nLen = 8;
1353 break;
1355 case SbxOBJECT:
1356 case SbxVARIANT:
1357 case SbxDATAOBJECT:
1358 nLen = 0;
1359 break;
1361 case SbxCHAR:
1362 case SbxBYTE:
1363 case SbxBOOL:
1364 nLen = 1;
1365 break;
1367 case SbxLPSTR:
1368 case SbxLPWSTR:
1369 case SbxCoreSTRING:
1370 case SbxSTRING:
1371 nLen = static_cast<sal_Int16>(rPar.Get(1)->GetOUString().getLength());
1372 break;
1374 default:
1375 nLen = 0;
1376 break;
1378 rPar.Get(0)->PutInteger(nLen);
1383 // 1st parameter == class name, other parameters for initialisation
1384 void SbRtl_CreateUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1386 RTL_Impl_CreateUnoStruct( rPar );
1390 // 1st parameter == service-name
1391 void SbRtl_CreateUnoService(StarBASIC *, SbxArray & rPar, bool)
1393 RTL_Impl_CreateUnoService( rPar );
1396 void SbRtl_CreateUnoServiceWithArguments(StarBASIC *, SbxArray & rPar, bool)
1398 RTL_Impl_CreateUnoServiceWithArguments( rPar );
1402 void SbRtl_CreateUnoValue(StarBASIC *, SbxArray & rPar, bool)
1404 RTL_Impl_CreateUnoValue( rPar );
1408 // no parameters
1409 void SbRtl_GetProcessServiceManager(StarBASIC *, SbxArray & rPar, bool)
1411 RTL_Impl_GetProcessServiceManager( rPar );
1415 // 1st parameter == Sequence<PropertyValue>
1416 void SbRtl_CreatePropertySet(StarBASIC *, SbxArray & rPar, bool)
1418 RTL_Impl_CreatePropertySet( rPar );
1422 // multiple interface-names as parameters
1423 void SbRtl_HasUnoInterfaces(StarBASIC *, SbxArray & rPar, bool)
1425 RTL_Impl_HasInterfaces( rPar );
1429 void SbRtl_IsUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1431 RTL_Impl_IsUnoStruct( rPar );
1435 void SbRtl_EqualUnoObjects(StarBASIC *, SbxArray & rPar, bool)
1437 RTL_Impl_EqualUnoObjects( rPar );
1440 void SbRtl_CreateUnoDialog(StarBASIC *, SbxArray & rPar, bool)
1442 RTL_Impl_CreateUnoDialog( rPar );
1445 // Return the application standard lib as root scope
1446 void SbRtl_GlobalScope(StarBASIC * pBasic, SbxArray & rPar, bool)
1448 SbxObject* p = pBasic;
1449 while( p->GetParent() )
1451 p = p->GetParent();
1453 SbxVariableRef refVar = rPar.Get(0);
1454 refVar->PutObject( p );
1457 // Helper functions to convert Url from/to system paths
1458 void SbRtl_ConvertToUrl(StarBASIC *, SbxArray & rPar, bool)
1460 if (rPar.Count() == 2)
1462 OUString aStr = rPar.Get(1)->GetOUString();
1463 INetURLObject aURLObj( aStr, INetProtocol::File );
1464 OUString aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1465 if( aFileURL.isEmpty() )
1467 osl::File::getFileURLFromSystemPath(aStr, aFileURL);
1469 if( aFileURL.isEmpty() )
1471 aFileURL = aStr;
1473 rPar.Get(0)->PutString(aFileURL);
1475 else
1477 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1481 void SbRtl_ConvertFromUrl(StarBASIC *, SbxArray & rPar, bool)
1483 if (rPar.Count() == 2)
1485 OUString aStr = rPar.Get(1)->GetOUString();
1486 OUString aSysPath;
1487 ::osl::File::getSystemPathFromFileURL( aStr, aSysPath );
1488 if( aSysPath.isEmpty() )
1490 aSysPath = aStr;
1492 rPar.Get(0)->PutString(aSysPath);
1494 else
1496 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1501 // Provide DefaultContext
1502 void SbRtl_GetDefaultContext(StarBASIC *, SbxArray & rPar, bool)
1504 RTL_Impl_GetDefaultContext( rPar );
1507 void SbRtl_Join(StarBASIC *, SbxArray & rPar, bool)
1509 sal_uInt32 nParCount = rPar.Count();
1510 if ( nParCount != 3 && nParCount != 2 )
1512 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1513 return;
1515 SbxBase* pParObj = rPar.Get(1)->GetObject();
1516 SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
1517 if( pArr )
1519 if (pArr->GetDims() != 1)
1521 StarBASIC::Error( ERRCODE_BASIC_WRONG_DIMS ); // Syntax Error?!
1522 return;
1524 OUString aDelim;
1525 if( nParCount == 3 )
1527 aDelim = rPar.Get(2)->GetOUString();
1529 else
1531 aDelim = " ";
1533 OUStringBuffer aRetStr(32);
1534 sal_Int32 nLower, nUpper;
1535 pArr->GetDim(1, nLower, nUpper);
1536 sal_Int32 aIdx[1];
1537 for (aIdx[0] = nLower; aIdx[0] <= nUpper; ++aIdx[0])
1539 OUString aStr = pArr->Get(aIdx)->GetOUString();
1540 aRetStr.append(aStr);
1541 if (aIdx[0] != nUpper)
1543 aRetStr.append(aDelim);
1546 rPar.Get(0)->PutString(aRetStr.makeStringAndClear());
1548 else
1550 StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );
1555 void SbRtl_Split(StarBASIC *, SbxArray & rPar, bool)
1557 sal_uInt32 nParCount = rPar.Count();
1558 if ( nParCount < 2 )
1560 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1561 return;
1564 OUString aExpression = rPar.Get(1)->GetOUString();
1565 sal_Int32 nArraySize = 0;
1566 std::vector< OUString > vRet;
1567 if( !aExpression.isEmpty() )
1569 OUString aDelim;
1570 if( nParCount >= 3 )
1572 aDelim = rPar.Get(2)->GetOUString();
1574 else
1576 aDelim = " ";
1579 sal_Int32 nCount = -1;
1580 if( nParCount == 4 )
1582 nCount = rPar.Get(3)->GetLong();
1584 sal_Int32 nDelimLen = aDelim.getLength();
1585 if( nDelimLen )
1587 sal_Int32 iSearch = -1;
1588 sal_Int32 iStart = 0;
1591 bool bBreak = false;
1592 if( nCount >= 0 && nArraySize == nCount - 1 )
1594 bBreak = true;
1596 iSearch = aExpression.indexOf( aDelim, iStart );
1597 OUString aSubStr;
1598 if( iSearch >= 0 && !bBreak )
1600 aSubStr = aExpression.copy( iStart, iSearch - iStart );
1601 iStart = iSearch + nDelimLen;
1603 else
1605 aSubStr = aExpression.copy( iStart );
1607 vRet.push_back( aSubStr );
1608 nArraySize++;
1610 if( bBreak )
1612 break;
1615 while( iSearch >= 0 );
1617 else
1619 vRet.push_back( aExpression );
1620 nArraySize = 1;
1624 // tdf#123025 - split returns an array of substrings
1625 SbxDimArray* pArray = new SbxDimArray( SbxSTRING );
1626 pArray->unoAddDim(0, nArraySize - 1);
1628 // insert parameter(s) into the array
1629 const bool bIsVBAInterOp = SbiRuntime::isVBAEnabled();
1630 for(sal_Int32 i = 0 ; i < nArraySize ; i++ )
1632 // tdf#123025 - split returns an array of substrings
1633 SbxVariableRef xVar = new SbxVariable( SbxSTRING );
1634 xVar->PutString( vRet[i] );
1635 // tdf#144924 - allow the assignment of different data types to the individual elements
1636 if (!bIsVBAInterOp)
1638 xVar->ResetFlag(SbxFlagBits::Fixed);
1640 pArray->Put(xVar.get(), &i);
1643 // return array
1644 SbxVariableRef refVar = rPar.Get(0);
1645 SbxFlagBits nFlags = refVar->GetFlags();
1646 refVar->ResetFlag( SbxFlagBits::Fixed );
1647 refVar->PutObject( pArray );
1648 refVar->SetFlags( nFlags );
1649 refVar->SetParameters( nullptr );
1652 // MonthName(month[, abbreviate])
1653 void SbRtl_MonthName(StarBASIC *, SbxArray & rPar, bool)
1655 sal_uInt32 nParCount = rPar.Count();
1656 if( nParCount != 2 && nParCount != 3 )
1658 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1659 return;
1662 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1663 if( !xCalendar.is() )
1665 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
1666 return;
1668 Sequence< CalendarItem2 > aMonthSeq = xCalendar->getMonths2();
1669 sal_Int32 nMonthCount = aMonthSeq.getLength();
1671 sal_Int16 nVal = rPar.Get(1)->GetInteger();
1672 if( nVal < 1 || nVal > nMonthCount )
1674 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1675 return;
1678 bool bAbbreviate = false;
1679 if( nParCount == 3 )
1680 bAbbreviate = rPar.Get(2)->GetBool();
1682 const CalendarItem2* pCalendarItems = aMonthSeq.getConstArray();
1683 const CalendarItem2& rItem = pCalendarItems[nVal - 1];
1685 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1686 rPar.Get(0)->PutString(aRetStr);
1689 // WeekdayName(weekday, abbreviate, firstdayofweek)
1690 void SbRtl_WeekdayName(StarBASIC *, SbxArray & rPar, bool)
1692 sal_uInt32 nParCount = rPar.Count();
1693 if( nParCount < 2 || nParCount > 4 )
1695 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1696 return;
1699 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1700 if( !xCalendar.is() )
1702 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
1703 return;
1706 Sequence< CalendarItem2 > aDaySeq = xCalendar->getDays2();
1707 sal_Int16 nDayCount = static_cast<sal_Int16>(aDaySeq.getLength());
1708 sal_Int16 nDay = rPar.Get(1)->GetInteger();
1709 sal_Int16 nFirstDay = 0;
1710 if( nParCount == 4 )
1712 nFirstDay = rPar.Get(3)->GetInteger();
1713 if( nFirstDay < 0 || nFirstDay > 7 )
1715 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1716 return;
1719 if( nFirstDay == 0 )
1721 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
1723 nDay = 1 + (nDay + nDayCount + nFirstDay - 2) % nDayCount;
1724 if( nDay < 1 || nDay > nDayCount )
1726 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1727 return;
1730 bool bAbbreviate = false;
1731 if( nParCount >= 3 )
1733 SbxVariable* pPar2 = rPar.Get(2);
1734 if( !pPar2->IsErr() )
1736 bAbbreviate = pPar2->GetBool();
1740 const CalendarItem2* pCalendarItems = aDaySeq.getConstArray();
1741 const CalendarItem2& rItem = pCalendarItems[nDay - 1];
1743 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1744 rPar.Get(0)->PutString(aRetStr);
1747 void SbRtl_Weekday(StarBASIC *, SbxArray & rPar, bool)
1749 sal_uInt32 nParCount = rPar.Count();
1750 if ( nParCount < 2 )
1752 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1754 else
1756 double aDate = rPar.Get(1)->GetDate();
1758 bool bFirstDay = false;
1759 sal_Int16 nFirstDay = 0;
1760 if ( nParCount > 2 )
1762 nFirstDay = rPar.Get(2)->GetInteger();
1763 bFirstDay = true;
1765 sal_Int16 nDay = implGetWeekDay( aDate, bFirstDay, nFirstDay );
1766 rPar.Get(0)->PutInteger(nDay);
1770 namespace {
1772 enum Interval
1774 INTERVAL_YYYY,
1775 INTERVAL_Q,
1776 INTERVAL_M,
1777 INTERVAL_Y,
1778 INTERVAL_D,
1779 INTERVAL_W,
1780 INTERVAL_WW,
1781 INTERVAL_H,
1782 INTERVAL_N,
1783 INTERVAL_S
1786 struct IntervalInfo
1788 Interval meInterval;
1789 char const * mStringCode;
1790 double mdValue;
1791 bool mbSimple;
1796 static IntervalInfo const * getIntervalInfo( const OUString& rStringCode )
1798 static IntervalInfo const aIntervalTable[] =
1800 { INTERVAL_YYYY, "yyyy", 0.0, false }, // Year
1801 { INTERVAL_Q, "q", 0.0, false }, // Quarter
1802 { INTERVAL_M, "m", 0.0, false }, // Month
1803 { INTERVAL_Y, "y", 1.0, true }, // Day of year
1804 { INTERVAL_D, "d", 1.0, true }, // Day
1805 { INTERVAL_W, "w", 1.0, true }, // Weekday
1806 { INTERVAL_WW, "ww", 7.0, true }, // Week
1807 { INTERVAL_H, "h", 1.0 / 24.0, true }, // Hour
1808 { INTERVAL_N, "n", 1.0 / 1440.0, true }, // Minute
1809 { INTERVAL_S, "s", 1.0 / 86400.0, true } // Second
1811 for( std::size_t i = 0; i != SAL_N_ELEMENTS(aIntervalTable); ++i )
1813 if( rStringCode.equalsIgnoreAsciiCaseAscii(
1814 aIntervalTable[i].mStringCode ) )
1816 return &aIntervalTable[i];
1819 return nullptr;
1822 static void implGetDayMonthYear( sal_Int16& rnYear, sal_Int16& rnMonth, sal_Int16& rnDay, double dDate )
1824 rnDay = implGetDateDay( dDate );
1825 rnMonth = implGetDateMonth( dDate );
1826 rnYear = implGetDateYear( dDate );
1829 /** Limits a date to valid dates within tools' class Date capabilities.
1831 @return the year number, truncated if necessary and in that case also
1832 rMonth and rDay adjusted.
1834 static sal_Int16 limitDate( sal_Int32 n32Year, sal_Int16& rMonth, sal_Int16& rDay )
1836 if( n32Year > SAL_MAX_INT16 )
1838 n32Year = SAL_MAX_INT16;
1839 rMonth = 12;
1840 rDay = 31;
1842 else if( n32Year < SAL_MIN_INT16 )
1844 n32Year = SAL_MIN_INT16;
1845 rMonth = 1;
1846 rDay = 1;
1848 return static_cast<sal_Int16>(n32Year);
1851 void SbRtl_DateAdd(StarBASIC *, SbxArray & rPar, bool)
1853 sal_uInt32 nParCount = rPar.Count();
1854 if( nParCount != 4 )
1856 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1857 return;
1860 OUString aStringCode = rPar.Get(1)->GetOUString();
1861 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1862 if( !pInfo )
1864 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1865 return;
1868 sal_Int32 lNumber = rPar.Get(2)->GetLong();
1869 double dDate = rPar.Get(3)->GetDate();
1870 double dNewDate = 0;
1871 if( pInfo->mbSimple )
1873 double dAdd = pInfo->mdValue * lNumber;
1874 dNewDate = dDate + dAdd;
1876 else
1878 // Keep hours, minutes, seconds
1879 double dHoursMinutesSeconds = dDate - floor( dDate );
1881 bool bOk = true;
1882 sal_Int16 nYear, nMonth, nDay;
1883 sal_Int16 nTargetYear16 = 0, nTargetMonth = 0;
1884 implGetDayMonthYear( nYear, nMonth, nDay, dDate );
1885 switch( pInfo->meInterval )
1887 case INTERVAL_YYYY:
1889 sal_Int32 nTargetYear = lNumber + nYear;
1890 nTargetYear16 = limitDate( nTargetYear, nMonth, nDay );
1891 /* TODO: should the result be error if the date was limited? It never was. */
1892 nTargetMonth = nMonth;
1893 bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
1894 break;
1896 case INTERVAL_Q:
1897 case INTERVAL_M:
1899 bool bNeg = (lNumber < 0);
1900 if( bNeg )
1901 lNumber = -lNumber;
1902 sal_Int32 nYearsAdd;
1903 sal_Int16 nMonthAdd;
1904 if( pInfo->meInterval == INTERVAL_Q )
1906 nYearsAdd = lNumber / 4;
1907 nMonthAdd = static_cast<sal_Int16>( 3 * (lNumber % 4) );
1909 else
1911 nYearsAdd = lNumber / 12;
1912 nMonthAdd = static_cast<sal_Int16>( lNumber % 12 );
1915 sal_Int32 nTargetYear;
1916 if( bNeg )
1918 nTargetMonth = nMonth - nMonthAdd;
1919 if( nTargetMonth <= 0 )
1921 nTargetMonth += 12;
1922 nYearsAdd++;
1924 nTargetYear = static_cast<sal_Int32>(nYear) - nYearsAdd;
1926 else
1928 nTargetMonth = nMonth + nMonthAdd;
1929 if( nTargetMonth > 12 )
1931 nTargetMonth -= 12;
1932 nYearsAdd++;
1934 nTargetYear = static_cast<sal_Int32>(nYear) + nYearsAdd;
1936 nTargetYear16 = limitDate( nTargetYear, nTargetMonth, nDay );
1937 /* TODO: should the result be error if the date was limited? It never was. */
1938 bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
1939 break;
1941 default: break;
1944 if( bOk )
1945 dNewDate += dHoursMinutesSeconds;
1948 rPar.Get(0)->PutDate(dNewDate);
1951 static double RoundImpl( double d )
1953 return ( d >= 0 ) ? floor( d + 0.5 ) : -floor( -d + 0.5 );
1956 void SbRtl_DateDiff(StarBASIC *, SbxArray & rPar, bool)
1958 // DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])
1960 sal_uInt32 nParCount = rPar.Count();
1961 if( nParCount < 4 || nParCount > 6 )
1963 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1964 return;
1967 OUString aStringCode = rPar.Get(1)->GetOUString();
1968 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1969 if( !pInfo )
1971 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
1972 return;
1975 double dDate1 = rPar.Get(2)->GetDate();
1976 double dDate2 = rPar.Get(3)->GetDate();
1978 double dRet = 0.0;
1979 switch( pInfo->meInterval )
1981 case INTERVAL_YYYY:
1983 sal_Int16 nYear1 = implGetDateYear( dDate1 );
1984 sal_Int16 nYear2 = implGetDateYear( dDate2 );
1985 dRet = nYear2 - nYear1;
1986 break;
1988 case INTERVAL_Q:
1990 sal_Int16 nYear1 = implGetDateYear( dDate1 );
1991 sal_Int16 nYear2 = implGetDateYear( dDate2 );
1992 sal_Int16 nQ1 = 1 + (implGetDateMonth( dDate1 ) - 1) / 3;
1993 sal_Int16 nQ2 = 1 + (implGetDateMonth( dDate2 ) - 1) / 3;
1994 sal_Int16 nQGes1 = 4 * nYear1 + nQ1;
1995 sal_Int16 nQGes2 = 4 * nYear2 + nQ2;
1996 dRet = nQGes2 - nQGes1;
1997 break;
1999 case INTERVAL_M:
2001 sal_Int16 nYear1 = implGetDateYear( dDate1 );
2002 sal_Int16 nYear2 = implGetDateYear( dDate2 );
2003 sal_Int16 nMonth1 = implGetDateMonth( dDate1 );
2004 sal_Int16 nMonth2 = implGetDateMonth( dDate2 );
2005 sal_Int16 nMonthGes1 = 12 * nYear1 + nMonth1;
2006 sal_Int16 nMonthGes2 = 12 * nYear2 + nMonth2;
2007 dRet = nMonthGes2 - nMonthGes1;
2008 break;
2010 case INTERVAL_Y:
2011 case INTERVAL_D:
2013 double dDays1 = floor( dDate1 );
2014 double dDays2 = floor( dDate2 );
2015 dRet = dDays2 - dDays1;
2016 break;
2018 case INTERVAL_W:
2019 case INTERVAL_WW:
2021 double dDays1 = floor( dDate1 );
2022 double dDays2 = floor( dDate2 );
2023 if( pInfo->meInterval == INTERVAL_WW )
2025 sal_Int16 nFirstDay = 1; // Default
2026 if( nParCount >= 5 )
2028 nFirstDay = rPar.Get(4)->GetInteger();
2029 if( nFirstDay < 0 || nFirstDay > 7 )
2031 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2032 return;
2034 if( nFirstDay == 0 )
2036 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
2037 if( !xCalendar.is() )
2039 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
2040 return;
2042 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
2045 sal_Int16 nDay1 = implGetWeekDay( dDate1 );
2046 sal_Int16 nDay1_Diff = nDay1 - nFirstDay;
2047 if( nDay1_Diff < 0 )
2048 nDay1_Diff += 7;
2049 dDays1 -= nDay1_Diff;
2051 sal_Int16 nDay2 = implGetWeekDay( dDate2 );
2052 sal_Int16 nDay2_Diff = nDay2 - nFirstDay;
2053 if( nDay2_Diff < 0 )
2054 nDay2_Diff += 7;
2055 dDays2 -= nDay2_Diff;
2058 double dDiff = dDays2 - dDays1;
2059 dRet = ( dDiff >= 0 ) ? floor( dDiff / 7.0 ) : -floor( -dDiff / 7.0 );
2060 break;
2062 case INTERVAL_H:
2064 dRet = RoundImpl( 24.0 * (dDate2 - dDate1) );
2065 break;
2067 case INTERVAL_N:
2069 dRet = RoundImpl( 1440.0 * (dDate2 - dDate1) );
2070 break;
2072 case INTERVAL_S:
2074 dRet = RoundImpl( 86400.0 * (dDate2 - dDate1) );
2075 break;
2078 rPar.Get(0)->PutDouble(dRet);
2081 static double implGetDateOfFirstDayInFirstWeek
2082 ( sal_Int16 nYear, sal_Int16& nFirstDay, sal_Int16& nFirstWeek, bool* pbError = nullptr )
2084 ErrCode nError = ERRCODE_NONE;
2085 if( nFirstDay < 0 || nFirstDay > 7 )
2086 nError = ERRCODE_BASIC_BAD_ARGUMENT;
2088 if( nFirstWeek < 0 || nFirstWeek > 3 )
2089 nError = ERRCODE_BASIC_BAD_ARGUMENT;
2091 Reference< XCalendar4 > xCalendar;
2092 if( nFirstDay == 0 || nFirstWeek == 0 )
2094 xCalendar = getLocaleCalendar();
2095 if( !xCalendar.is() )
2096 nError = ERRCODE_BASIC_BAD_ARGUMENT;
2099 if( nError != ERRCODE_NONE )
2101 StarBASIC::Error( nError );
2102 if( pbError )
2103 *pbError = true;
2104 return 0.0;
2107 if( nFirstDay == 0 )
2108 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
2110 sal_Int16 nFirstWeekMinDays = 0; // Not used for vbFirstJan1 = default
2111 if( nFirstWeek == 0 )
2113 nFirstWeekMinDays = xCalendar->getMinimumNumberOfDaysForFirstWeek();
2114 if( nFirstWeekMinDays == 1 )
2116 nFirstWeekMinDays = 0;
2117 nFirstWeek = 1;
2119 else if( nFirstWeekMinDays == 4 )
2120 nFirstWeek = 2;
2121 else if( nFirstWeekMinDays == 7 )
2122 nFirstWeek = 3;
2124 else if( nFirstWeek == 2 )
2125 nFirstWeekMinDays = 4; // vbFirstFourDays
2126 else if( nFirstWeek == 3 )
2127 nFirstWeekMinDays = 7; // vbFirstFourDays
2129 double dBaseDate;
2130 implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
2132 sal_Int16 nWeekDay0101 = implGetWeekDay( dBaseDate );
2133 sal_Int16 nDayDiff = nWeekDay0101 - nFirstDay;
2134 if( nDayDiff < 0 )
2135 nDayDiff += 7;
2137 if( nFirstWeekMinDays )
2139 sal_Int16 nThisWeeksDaysInYearCount = 7 - nDayDiff;
2140 if( nThisWeeksDaysInYearCount < nFirstWeekMinDays )
2141 nDayDiff -= 7;
2143 double dRetDate = dBaseDate - nDayDiff;
2144 return dRetDate;
2147 void SbRtl_DatePart(StarBASIC *, SbxArray & rPar, bool)
2149 // DatePart(interval, date[,firstdayofweek[, firstweekofyear]])
2151 sal_uInt32 nParCount = rPar.Count();
2152 if( nParCount < 3 || nParCount > 5 )
2154 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2155 return;
2158 OUString aStringCode = rPar.Get(1)->GetOUString();
2159 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
2160 if( !pInfo )
2162 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2163 return;
2166 double dDate = rPar.Get(2)->GetDate();
2168 sal_Int32 nRet = 0;
2169 switch( pInfo->meInterval )
2171 case INTERVAL_YYYY:
2173 nRet = implGetDateYear( dDate );
2174 break;
2176 case INTERVAL_Q:
2178 nRet = 1 + (implGetDateMonth( dDate ) - 1) / 3;
2179 break;
2181 case INTERVAL_M:
2183 nRet = implGetDateMonth( dDate );
2184 break;
2186 case INTERVAL_Y:
2188 sal_Int16 nYear = implGetDateYear( dDate );
2189 double dBaseDate;
2190 implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
2191 nRet = 1 + sal_Int32( dDate - dBaseDate );
2192 break;
2194 case INTERVAL_D:
2196 nRet = implGetDateDay( dDate );
2197 break;
2199 case INTERVAL_W:
2201 bool bFirstDay = false;
2202 sal_Int16 nFirstDay = 1; // Default
2203 if( nParCount >= 4 )
2205 nFirstDay = rPar.Get(3)->GetInteger();
2206 bFirstDay = true;
2208 nRet = implGetWeekDay( dDate, bFirstDay, nFirstDay );
2209 break;
2211 case INTERVAL_WW:
2213 sal_Int16 nFirstDay = 1; // Default
2214 if( nParCount >= 4 )
2215 nFirstDay = rPar.Get(3)->GetInteger();
2217 sal_Int16 nFirstWeek = 1; // Default
2218 if( nParCount == 5 )
2219 nFirstWeek = rPar.Get(4)->GetInteger();
2221 sal_Int16 nYear = implGetDateYear( dDate );
2222 bool bError = false;
2223 double dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear, nFirstDay, nFirstWeek, &bError );
2224 if( !bError )
2226 if( dYearFirstDay > dDate )
2228 // Date belongs to last year's week
2229 dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear - 1, nFirstDay, nFirstWeek );
2231 else if( nFirstWeek != 1 )
2233 // Check if date belongs to next year
2234 double dNextYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear + 1, nFirstDay, nFirstWeek );
2235 if( dDate >= dNextYearFirstDay )
2236 dYearFirstDay = dNextYearFirstDay;
2239 // Calculate week
2240 double dDiff = dDate - dYearFirstDay;
2241 nRet = 1 + sal_Int32( dDiff / 7 );
2243 break;
2245 case INTERVAL_H:
2247 nRet = implGetHour( dDate );
2248 break;
2250 case INTERVAL_N:
2252 nRet = implGetMinute( dDate );
2253 break;
2255 case INTERVAL_S:
2257 nRet = implGetSecond( dDate );
2258 break;
2261 rPar.Get(0)->PutLong(nRet);
2264 // FormatDateTime(Date[,NamedFormat])
2265 void SbRtl_FormatDateTime(StarBASIC *, SbxArray & rPar, bool)
2267 sal_uInt32 nParCount = rPar.Count();
2268 if( nParCount < 2 || nParCount > 3 )
2270 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2271 return;
2274 double dDate = rPar.Get(1)->GetDate();
2275 sal_Int16 nNamedFormat = 0;
2276 if( nParCount > 2 )
2278 nNamedFormat = rPar.Get(2)->GetInteger();
2279 if( nNamedFormat < 0 || nNamedFormat > 4 )
2281 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2282 return;
2286 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
2287 if( !xCalendar.is() )
2289 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
2290 return;
2293 OUString aRetStr;
2294 SbxVariableRef pSbxVar = new SbxVariable( SbxSTRING );
2295 switch( nNamedFormat )
2297 // GeneralDate:
2298 // Display a date and/or time. If there is a date part,
2299 // display it as a short date. If there is a time part,
2300 // display it as a long time. If present, both parts are displayed.
2302 // 12/21/2004 11:24:50 AM
2303 // 21.12.2004 12:13:51
2304 case 0:
2305 pSbxVar->PutDate( dDate );
2306 aRetStr = pSbxVar->GetOUString();
2307 break;
2309 // LongDate: Display a date using the long date format specified
2310 // in your computer's regional settings.
2311 // Tuesday, December 21, 2004
2312 // Dienstag, 21. December 2004
2313 case 1:
2315 std::shared_ptr<SvNumberFormatter> pFormatter;
2316 if( GetSbData()->pInst )
2318 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2320 else
2322 sal_uInt32 n; // Dummy
2323 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
2326 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
2327 const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, eLangType );
2328 const Color* pCol;
2329 pFormatter->GetOutputString( dDate, nIndex, aRetStr, &pCol );
2330 break;
2333 // ShortDate: Display a date using the short date format specified
2334 // in your computer's regional settings.
2335 // 21.12.2004
2336 case 2:
2337 pSbxVar->PutDate( floor(dDate) );
2338 aRetStr = pSbxVar->GetOUString();
2339 break;
2341 // LongTime: Display a time using the time format specified
2342 // in your computer's regional settings.
2343 // 11:24:50 AM
2344 // 12:13:51
2345 case 3:
2346 // ShortTime: Display a time using the 24-hour format (hh:mm).
2347 // 11:24
2348 case 4:
2349 double dTime = modf( dDate, &o3tl::temporary(double()) );
2350 pSbxVar->PutDate( dTime );
2351 if( nNamedFormat == 3 )
2353 aRetStr = pSbxVar->GetOUString();
2355 else
2357 aRetStr = pSbxVar->GetOUString().copy( 0, 5 );
2359 break;
2362 rPar.Get(0)->PutString(aRetStr);
2365 void SbRtl_Frac(StarBASIC *, SbxArray & rPar, bool)
2367 sal_uInt32 nParCount = rPar.Count();
2368 if( nParCount != 2)
2370 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2371 return;
2374 SbxVariable* pSbxVariable = rPar.Get(1);
2375 double dVal = pSbxVariable->GetDouble();
2376 if(dVal >= 0)
2377 rPar.Get(0)->PutDouble(dVal - ::rtl::math::approxFloor(dVal));
2378 else
2379 rPar.Get(0)->PutDouble(dVal - ::rtl::math::approxCeil(dVal));
2382 void SbRtl_Round(StarBASIC *, SbxArray & rPar, bool)
2384 sal_uInt32 nParCount = rPar.Count();
2385 if( nParCount != 2 && nParCount != 3 )
2387 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2388 return;
2391 SbxVariable* pSbxVariable = rPar.Get(1);
2392 double dVal = pSbxVariable->GetDouble();
2393 double dRes = 0.0;
2394 if( dVal != 0.0 )
2396 sal_Int16 numdecimalplaces = 0;
2397 if( nParCount == 3 )
2399 numdecimalplaces = rPar.Get(2)->GetInteger();
2400 if( numdecimalplaces < 0 || numdecimalplaces > 22 )
2402 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2403 return;
2407 dRes = rtl_math_round(dVal, numdecimalplaces, rtl_math_RoundingMode_HalfEven);
2409 rPar.Get(0)->PutDouble(dRes);
2412 static void CallFunctionAccessFunction( const Sequence< Any >& aArgs, const OUString& sFuncName, SbxVariable* pRet )
2414 static Reference< XFunctionAccess > xFunc;
2417 if ( !xFunc.is() )
2419 Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() );
2420 if( xFactory.is() )
2422 xFunc.set( xFactory->createInstance("com.sun.star.sheet.FunctionAccess"), UNO_QUERY_THROW);
2425 Any aRet = xFunc->callFunction( sFuncName, aArgs );
2427 unoToSbxValue( pRet, aRet );
2430 catch(const Exception& )
2432 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2436 void SbRtl_SYD(StarBASIC *, SbxArray & rPar, bool)
2438 sal_uInt32 nArgCount = rPar.Count() - 1;
2440 if ( nArgCount < 4 )
2442 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2443 return;
2446 // retrieve non-optional params
2448 Sequence< Any > aParams
2450 makeAny(rPar.Get(1)->GetDouble()),
2451 makeAny(rPar.Get(2)->GetDouble()),
2452 makeAny(rPar.Get(3)->GetDouble()),
2453 makeAny(rPar.Get(4)->GetDouble())
2456 CallFunctionAccessFunction(aParams, "SYD", rPar.Get(0));
2459 void SbRtl_SLN(StarBASIC *, SbxArray & rPar, bool)
2461 sal_uInt32 nArgCount = rPar.Count() - 1;
2463 if ( nArgCount < 3 )
2465 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2466 return;
2469 // retrieve non-optional params
2471 Sequence< Any > aParams
2473 makeAny(rPar.Get(1)->GetDouble()),
2474 makeAny(rPar.Get(2)->GetDouble()),
2475 makeAny(rPar.Get(3)->GetDouble())
2478 CallFunctionAccessFunction(aParams, "SLN", rPar.Get(0));
2481 void SbRtl_Pmt(StarBASIC *, SbxArray & rPar, bool)
2483 sal_uInt32 nArgCount = rPar.Count() - 1;
2485 if ( nArgCount < 3 || nArgCount > 5 )
2487 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2488 return;
2490 // retrieve non-optional params
2492 double rate = rPar.Get(1)->GetDouble();
2493 double nper = rPar.Get(2)->GetDouble();
2494 double pmt = rPar.Get(3)->GetDouble();
2496 // set default values for Optional args
2497 double fv = 0;
2498 double type = 0;
2500 // fv
2501 if ( nArgCount >= 4 )
2503 if (rPar.Get(4)->GetType() != SbxEMPTY)
2504 fv = rPar.Get(4)->GetDouble();
2506 // type
2507 if ( nArgCount >= 5 )
2509 if (rPar.Get(5)->GetType() != SbxEMPTY)
2510 type = rPar.Get(5)->GetDouble();
2513 Sequence< Any > aParams
2515 makeAny(rate),
2516 makeAny(nper),
2517 makeAny(pmt),
2518 makeAny(fv),
2519 makeAny(type)
2522 CallFunctionAccessFunction(aParams, "Pmt", rPar.Get(0));
2525 void SbRtl_PPmt(StarBASIC *, SbxArray & rPar, bool)
2527 sal_uInt32 nArgCount = rPar.Count() - 1;
2529 if ( nArgCount < 4 || nArgCount > 6 )
2531 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2532 return;
2534 // retrieve non-optional params
2536 double rate = rPar.Get(1)->GetDouble();
2537 double per = rPar.Get(2)->GetDouble();
2538 double nper = rPar.Get(3)->GetDouble();
2539 double pv = rPar.Get(4)->GetDouble();
2541 // set default values for Optional args
2542 double fv = 0;
2543 double type = 0;
2545 // fv
2546 if ( nArgCount >= 5 )
2548 if (rPar.Get(5)->GetType() != SbxEMPTY)
2549 fv = rPar.Get(5)->GetDouble();
2551 // type
2552 if ( nArgCount >= 6 )
2554 if (rPar.Get(6)->GetType() != SbxEMPTY)
2555 type = rPar.Get(6)->GetDouble();
2558 Sequence< Any > aParams
2560 makeAny(rate),
2561 makeAny(per),
2562 makeAny(nper),
2563 makeAny(pv),
2564 makeAny(fv),
2565 makeAny(type)
2568 CallFunctionAccessFunction(aParams, "PPmt", rPar.Get(0));
2571 void SbRtl_PV(StarBASIC *, SbxArray & rPar, bool)
2573 sal_uInt32 nArgCount = rPar.Count() - 1;
2575 if ( nArgCount < 3 || nArgCount > 5 )
2577 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2578 return;
2580 // retrieve non-optional params
2582 double rate = rPar.Get(1)->GetDouble();
2583 double nper = rPar.Get(2)->GetDouble();
2584 double pmt = rPar.Get(3)->GetDouble();
2586 // set default values for Optional args
2587 double fv = 0;
2588 double type = 0;
2590 // fv
2591 if ( nArgCount >= 4 )
2593 if (rPar.Get(4)->GetType() != SbxEMPTY)
2594 fv = rPar.Get(4)->GetDouble();
2596 // type
2597 if ( nArgCount >= 5 )
2599 if (rPar.Get(5)->GetType() != SbxEMPTY)
2600 type = rPar.Get(5)->GetDouble();
2603 Sequence< Any > aParams
2605 makeAny(rate),
2606 makeAny(nper),
2607 makeAny(pmt),
2608 makeAny(fv),
2609 makeAny(type)
2612 CallFunctionAccessFunction(aParams, "PV", rPar.Get(0));
2615 void SbRtl_NPV(StarBASIC *, SbxArray & rPar, bool)
2617 sal_uInt32 nArgCount = rPar.Count() - 1;
2619 if ( nArgCount < 1 || nArgCount > 2 )
2621 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2622 return;
2625 Any aValues = sbxToUnoValue(rPar.Get(2),
2626 cppu::UnoType<Sequence<double>>::get() );
2628 // convert for calc functions
2629 Sequence< Sequence< double > > sValues(1);
2630 aValues >>= sValues.getArray()[ 0 ];
2631 aValues <<= sValues;
2633 Sequence< Any > aParams
2635 makeAny(rPar.Get(1)->GetDouble()),
2636 aValues
2639 CallFunctionAccessFunction(aParams, "NPV", rPar.Get(0));
2642 void SbRtl_NPer(StarBASIC *, SbxArray & rPar, bool)
2644 sal_uInt32 nArgCount = rPar.Count() - 1;
2646 if ( nArgCount < 3 || nArgCount > 5 )
2648 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2649 return;
2651 // retrieve non-optional params
2653 double rate = rPar.Get(1)->GetDouble();
2654 double pmt = rPar.Get(2)->GetDouble();
2655 double pv = rPar.Get(3)->GetDouble();
2657 // set default values for Optional args
2658 double fv = 0;
2659 double type = 0;
2661 // fv
2662 if ( nArgCount >= 4 )
2664 if (rPar.Get(4)->GetType() != SbxEMPTY)
2665 fv = rPar.Get(4)->GetDouble();
2667 // type
2668 if ( nArgCount >= 5 )
2670 if (rPar.Get(5)->GetType() != SbxEMPTY)
2671 type = rPar.Get(5)->GetDouble();
2674 Sequence< Any > aParams
2676 makeAny(rate),
2677 makeAny(pmt),
2678 makeAny(pv),
2679 makeAny(fv),
2680 makeAny(type)
2683 CallFunctionAccessFunction(aParams, "NPer", rPar.Get(0));
2686 void SbRtl_MIRR(StarBASIC *, SbxArray & rPar, bool)
2688 sal_uInt32 nArgCount = rPar.Count() - 1;
2690 if ( nArgCount < 3 )
2692 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2693 return;
2696 // retrieve non-optional params
2698 Any aValues = sbxToUnoValue(rPar.Get(1),
2699 cppu::UnoType<Sequence<double>>::get() );
2701 // convert for calc functions
2702 Sequence< Sequence< double > > sValues(1);
2703 aValues >>= sValues.getArray()[ 0 ];
2704 aValues <<= sValues;
2706 Sequence< Any > aParams
2708 aValues,
2709 makeAny(rPar.Get(2)->GetDouble()),
2710 makeAny(rPar.Get(3)->GetDouble())
2713 CallFunctionAccessFunction(aParams, "MIRR", rPar.Get(0));
2716 void SbRtl_IRR(StarBASIC *, SbxArray & rPar, bool)
2718 sal_uInt32 nArgCount = rPar.Count() - 1;
2720 if ( nArgCount < 1 || nArgCount > 2 )
2722 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2723 return;
2725 // retrieve non-optional params
2726 Any aValues = sbxToUnoValue(rPar.Get(1),
2727 cppu::UnoType<Sequence<double>>::get() );
2729 // convert for calc functions
2730 Sequence< Sequence< double > > sValues(1);
2731 aValues >>= sValues.getArray()[ 0 ];
2732 aValues <<= sValues;
2734 // set default values for Optional args
2735 double guess = 0.1;
2736 // guess
2737 if ( nArgCount >= 2 )
2739 if (rPar.Get(2)->GetType() != SbxEMPTY)
2740 guess = rPar.Get(2)->GetDouble();
2743 Sequence< Any > aParams
2745 aValues,
2746 makeAny(guess)
2749 CallFunctionAccessFunction(aParams, "IRR", rPar.Get(0));
2752 void SbRtl_IPmt(StarBASIC *, SbxArray & rPar, bool)
2754 sal_uInt32 nArgCount = rPar.Count() - 1;
2756 if ( nArgCount < 4 || nArgCount > 6 )
2758 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2759 return;
2761 // retrieve non-optional params
2763 double rate = rPar.Get(1)->GetDouble();
2764 double per = rPar.Get(2)->GetInteger();
2765 double nper = rPar.Get(3)->GetDouble();
2766 double pv = rPar.Get(4)->GetDouble();
2768 // set default values for Optional args
2769 double fv = 0;
2770 double type = 0;
2772 // fv
2773 if ( nArgCount >= 5 )
2775 if (rPar.Get(5)->GetType() != SbxEMPTY)
2776 fv = rPar.Get(5)->GetDouble();
2778 // type
2779 if ( nArgCount >= 6 )
2781 if (rPar.Get(6)->GetType() != SbxEMPTY)
2782 type = rPar.Get(6)->GetDouble();
2785 Sequence< Any > aParams
2787 makeAny(rate),
2788 makeAny(per),
2789 makeAny(nper),
2790 makeAny(pv),
2791 makeAny(fv),
2792 makeAny(type)
2795 CallFunctionAccessFunction(aParams, "IPmt", rPar.Get(0));
2798 void SbRtl_FV(StarBASIC *, SbxArray & rPar, bool)
2800 sal_uInt32 nArgCount = rPar.Count() - 1;
2802 if ( nArgCount < 3 || nArgCount > 5 )
2804 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2805 return;
2807 // retrieve non-optional params
2809 double rate = rPar.Get(1)->GetDouble();
2810 double nper = rPar.Get(2)->GetDouble();
2811 double pmt = rPar.Get(3)->GetDouble();
2813 // set default values for Optional args
2814 double pv = 0;
2815 double type = 0;
2817 // pv
2818 if ( nArgCount >= 4 )
2820 if (rPar.Get(4)->GetType() != SbxEMPTY)
2821 pv = rPar.Get(4)->GetDouble();
2823 // type
2824 if ( nArgCount >= 5 )
2826 if (rPar.Get(5)->GetType() != SbxEMPTY)
2827 type = rPar.Get(5)->GetDouble();
2830 Sequence< Any > aParams
2832 makeAny(rate),
2833 makeAny(nper),
2834 makeAny(pmt),
2835 makeAny(pv),
2836 makeAny(type)
2839 CallFunctionAccessFunction(aParams, "FV", rPar.Get(0));
2842 void SbRtl_DDB(StarBASIC *, SbxArray & rPar, bool)
2844 sal_uInt32 nArgCount = rPar.Count() - 1;
2846 if ( nArgCount < 4 || nArgCount > 5 )
2848 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2849 return;
2851 // retrieve non-optional params
2853 double cost = rPar.Get(1)->GetDouble();
2854 double salvage = rPar.Get(2)->GetDouble();
2855 double life = rPar.Get(3)->GetDouble();
2856 double period = rPar.Get(4)->GetDouble();
2858 // set default values for Optional args
2859 double factor = 2;
2861 // factor
2862 if ( nArgCount >= 5 )
2864 if (rPar.Get(5)->GetType() != SbxEMPTY)
2865 factor = rPar.Get(5)->GetDouble();
2868 Sequence< Any > aParams
2870 makeAny(cost),
2871 makeAny(salvage),
2872 makeAny(life),
2873 makeAny(period),
2874 makeAny(factor)
2877 CallFunctionAccessFunction(aParams, "DDB", rPar.Get(0));
2880 void SbRtl_Rate(StarBASIC *, SbxArray & rPar, bool)
2882 sal_uInt32 nArgCount = rPar.Count() - 1;
2884 if ( nArgCount < 3 || nArgCount > 6 )
2886 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2887 return;
2889 // retrieve non-optional params
2891 double nper = 0;
2892 double pmt = 0;
2893 double pv = 0;
2895 nper = rPar.Get(1)->GetDouble();
2896 pmt = rPar.Get(2)->GetDouble();
2897 pv = rPar.Get(3)->GetDouble();
2899 // set default values for Optional args
2900 double fv = 0;
2901 double type = 0;
2902 double guess = 0.1;
2904 // fv
2905 if ( nArgCount >= 4 )
2907 if (rPar.Get(4)->GetType() != SbxEMPTY)
2908 fv = rPar.Get(4)->GetDouble();
2911 // type
2912 if ( nArgCount >= 5 )
2914 if (rPar.Get(5)->GetType() != SbxEMPTY)
2915 type = rPar.Get(5)->GetDouble();
2918 // guess
2919 if ( nArgCount >= 6 )
2921 if (rPar.Get(6)->GetType() != SbxEMPTY)
2922 guess = rPar.Get(6)->GetDouble();
2925 Sequence< Any > aParams
2927 makeAny(nper),
2928 makeAny(pmt),
2929 makeAny(pv),
2930 makeAny(fv),
2931 makeAny(type),
2932 makeAny(guess)
2935 CallFunctionAccessFunction(aParams, "Rate", rPar.Get(0));
2938 void SbRtl_StrReverse(StarBASIC *, SbxArray & rPar, bool)
2940 if (rPar.Count() != 2)
2942 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2943 return;
2946 SbxVariable* pSbxVariable = rPar.Get(1);
2947 if( pSbxVariable->IsNull() )
2949 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2950 return;
2953 OUString aStr = comphelper::string::reverseString(pSbxVariable->GetOUString());
2954 rPar.Get(0)->PutString(aStr);
2957 void SbRtl_CompatibilityMode(StarBASIC *, SbxArray & rPar, bool)
2959 bool bEnabled = false;
2960 sal_uInt32 nCount = rPar.Count();
2961 if ( nCount != 1 && nCount != 2 )
2962 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2964 SbiInstance* pInst = GetSbData()->pInst;
2965 if( pInst )
2967 if ( nCount == 2 )
2969 pInst->EnableCompatibility(rPar.Get(1)->GetBool());
2971 bEnabled = pInst->IsCompatibility();
2973 rPar.Get(0)->PutBool(bEnabled);
2976 bool LibreOffice6FloatingPointMode()
2978 static bool bMode = std::getenv("LIBREOFFICE6FLOATINGPOINTMODE") != nullptr;
2980 return bMode || officecfg::Office::Scripting::Basic::Compatibility::UseLibreOffice6FloatingPointConversion::get();
2983 void SbRtl_Input(StarBASIC *, SbxArray & rPar, bool)
2985 // 2 parameters needed
2986 if (rPar.Count() < 3)
2988 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2989 return;
2992 sal_uInt16 nByteCount = rPar.Get(1)->GetUShort();
2993 sal_Int16 nFileNumber = rPar.Get(2)->GetInteger();
2995 SbiIoSystem* pIosys = GetSbData()->pInst->GetIoSystem();
2996 SbiStream* pSbStrm = pIosys->GetStream( nFileNumber );
2997 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Input)) )
2999 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
3000 return;
3003 OString aByteBuffer;
3004 ErrCode err = pSbStrm->Read( aByteBuffer, nByteCount, true );
3005 if( !err )
3006 err = pIosys->GetError();
3008 if( err )
3010 StarBASIC::Error( err );
3011 return;
3013 rPar.Get(0)->PutString(OStringToOUString(aByteBuffer, osl_getThreadTextEncoding()));
3016 void SbRtl_Me(StarBASIC *, SbxArray & rPar, bool)
3018 SbModule* pActiveModule = GetSbData()->pInst->GetActiveModule();
3019 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pActiveModule );
3020 SbxVariableRef refVar = rPar.Get(0);
3021 if( pClassModuleObject == nullptr )
3023 SbObjModule* pMod = dynamic_cast<SbObjModule*>( pActiveModule );
3024 if ( pMod )
3025 refVar->PutObject( pMod );
3026 else
3027 StarBASIC::Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
3029 else
3030 refVar->PutObject( pClassModuleObject );
3033 #endif
3035 sal_Int16 implGetWeekDay( double aDate, bool bFirstDayParam, sal_Int16 nFirstDay )
3037 Date aRefDate( 1,1,1900 );
3038 sal_Int32 nDays = static_cast<sal_Int32>(aDate);
3039 nDays -= 2; // normalize: 1.1.1900 => 0
3040 aRefDate.AddDays( nDays);
3041 DayOfWeek aDay = aRefDate.GetDayOfWeek();
3042 sal_Int16 nDay;
3043 if ( aDay != SUNDAY )
3044 nDay = static_cast<sal_Int16>(aDay) + 2;
3045 else
3046 nDay = 1; // 1 == Sunday
3048 // #117253 optional 2nd parameter "firstdayofweek"
3049 if( bFirstDayParam )
3051 if( nFirstDay < 0 || nFirstDay > 7 )
3053 #if HAVE_FEATURE_SCRIPTING
3054 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3055 #endif
3056 return 0;
3058 if( nFirstDay == 0 )
3060 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
3061 if( !xCalendar.is() )
3063 #if HAVE_FEATURE_SCRIPTING
3064 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
3065 #endif
3066 return 0;
3068 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
3070 nDay = 1 + (nDay + 7 - nFirstDay) % 7;
3072 return nDay;
3075 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */