Bug Summary

File:home/maarten/src/libreoffice/core/basic/source/runtime/methods1.cxx
Warning:line 2365, column 1
Potential leak of memory pointed to by 'pSbxVar.pObj'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name methods1.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D BASIC_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/basic/inc -I /home/maarten/src/libreoffice/core/basic/source/inc -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/basic/source/runtime/methods1.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <config_features.h>
21
22#include <sal/config.h>
23#include <config_version.h>
24
25#include <cstddef>
26
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>
42
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>
53
54#include <comphelper/processfactory.hxx>
55#include <comphelper/string.hxx>
56
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>
62
63using namespace comphelper;
64using namespace com::sun::star::i18n;
65using namespace com::sun::star::lang;
66using namespace com::sun::star::sheet;
67using namespace com::sun::star::uno;
68
69static Reference< XCalendar4 > const & getLocaleCalendar()
70{
71 static Reference< XCalendar4 > xCalendar = LocaleCalendar2::create(getProcessComponentContext());
72 static css::lang::Locale aLastLocale;
73 static bool bNeedsInit = true;
74
75 css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale();
76 bool bNeedsReload = false;
77 if( bNeedsInit )
78 {
79 bNeedsInit = false;
80 bNeedsReload = true;
81 }
82 else if( aLocale.Language != aLastLocale.Language ||
83 aLocale.Country != aLastLocale.Country ||
84 aLocale.Variant != aLastLocale.Variant )
85 {
86 bNeedsReload = true;
87 }
88 if( bNeedsReload )
89 {
90 aLastLocale = aLocale;
91 xCalendar->loadDefaultCalendar( aLocale );
92 }
93 return xCalendar;
94}
95
96#if HAVE_FEATURE_SCRIPTING1
97
98void SbRtl_CallByName(StarBASIC *, SbxArray & rPar, bool)
99{
100 const sal_Int16 vbGet = 2;
101 const sal_Int16 vbLet = 4;
102 const sal_Int16 vbMethod = 1;
103 const sal_Int16 vbSet = 8;
104
105 // At least 3 parameter needed plus function itself -> 4
106 sal_uInt32 nParCount = rPar.Count32();
107 if ( nParCount < 4 )
108 {
109 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
110 return;
111 }
112
113 // 1. parameter is object
114 SbxBase* pObjVar = rPar.Get32(1)->GetObject();
115 SbxObject* pObj = nullptr;
116 if( pObjVar )
117 pObj = dynamic_cast<SbxObject*>( pObjVar );
118 if( !pObj && dynamic_cast<const SbxVariable*>( pObjVar) )
119 {
120 SbxBase* pObjVarObj = static_cast<SbxVariable*>(pObjVar)->GetObject();
121 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
122 }
123 if( !pObj )
124 {
125 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETERErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 7) );
126 return;
127 }
128
129 // 2. parameter is ProcedureName
130 OUString aNameStr = rPar.Get32(2)->GetOUString();
131
132 // 3. parameter is CallType
133 sal_Int16 nCallType = rPar.Get32(3)->GetInteger();
134
135 //SbxObject* pFindObj = NULL;
136 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::DontCare );
137 if( pFindVar == nullptr )
138 {
139 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINEDErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 8) );
140 return;
141 }
142
143 switch( nCallType )
144 {
145 case vbGet:
146 {
147 SbxValues aVals;
148 aVals.eType = SbxVARIANT;
149 pFindVar->Get( aVals );
150
151 SbxVariableRef refVar = rPar.Get32(0);
152 refVar->Put( aVals );
153 }
154 break;
155 case vbLet:
156 case vbSet:
157 {
158 if ( nParCount != 5 )
159 {
160 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
161 return;
162 }
163 SbxVariableRef pValVar = rPar.Get32(4);
164 if( nCallType == vbLet )
165 {
166 SbxValues aVals;
167 aVals.eType = SbxVARIANT;
168 pValVar->Get( aVals );
169 pFindVar->Put( aVals );
170 }
171 else
172 {
173 SbxVariableRef rFindVar = pFindVar;
174 SbiInstance* pInst = GetSbData()->pInst;
175 SbiRuntime* pRT = pInst ? pInst->pRun : nullptr;
176 if( pRT != nullptr )
177 {
178 pRT->StepSET_Impl( pValVar, rFindVar );
179 }
180 }
181 }
182 break;
183 case vbMethod:
184 {
185 SbMethod* pMeth = dynamic_cast<SbMethod*>( pFindVar );
186 if( pMeth == nullptr )
187 {
188 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINEDErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 8) );
189 return;
190 }
191
192 // Setup parameters
193 SbxArrayRef xArray;
194 sal_uInt32 nMethParamCount = nParCount - 4;
195 if( nMethParamCount > 0 )
196 {
197 xArray = new SbxArray;
198 for( sal_uInt32 i = 0 ; i < nMethParamCount ; i++ )
199 {
200 SbxVariable* pPar = rPar.Get32( i + 4 );
201 xArray->Put32( pPar, i + 1 );
202 }
203 }
204
205 // Call method
206 SbxVariableRef refVar = rPar.Get32(0);
207 if( xArray.is() )
208 pMeth->SetParameters( xArray.get() );
209 pMeth->Call( refVar.get() );
210 pMeth->SetParameters( nullptr );
211 }
212 break;
213 default:
214 StarBASIC::Error( ERRCODE_BASIC_PROC_UNDEFINEDErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 8) );
215 }
216}
217
218void SbRtl_CBool(StarBASIC *, SbxArray & rPar, bool) // JSM
219{
220 bool bVal = false;
221 if ( rPar.Count32() == 2 )
222 {
223 SbxVariable *pSbxVariable = rPar.Get32(1);
224 bVal = pSbxVariable->GetBool();
225 }
226 else
227 {
228 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
229 }
230 rPar.Get32(0)->PutBool(bVal);
231}
232
233void SbRtl_CByte(StarBASIC *, SbxArray & rPar, bool) // JSM
234{
235 sal_uInt8 nByte = 0;
236 if ( rPar.Count32() == 2 )
237 {
238 SbxVariable *pSbxVariable = rPar.Get32(1);
239 nByte = pSbxVariable->GetByte();
240 }
241 else
242 {
243 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
244 }
245 rPar.Get32(0)->PutByte(nByte);
246}
247
248void SbRtl_CCur(StarBASIC *, SbxArray & rPar, bool)
249{
250 sal_Int64 nCur = 0;
251 if ( rPar.Count32() == 2 )
252 {
253 SbxVariable *pSbxVariable = rPar.Get32(1);
254 nCur = pSbxVariable->GetCurrency();
255 }
256 else
257 {
258 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
259 }
260 rPar.Get32(0)->PutCurrency( nCur );
261}
262
263void SbRtl_CDec(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
264{
265 (void)pBasic;
266 (void)bWrite;
267
268#ifdef _WIN32
269 SbxDecimal* pDec = nullptr;
270 if ( rPar.Count32() == 2 )
271 {
272 SbxVariable *pSbxVariable = rPar.Get32(1);
273 pDec = pSbxVariable->GetDecimal();
274 }
275 else
276 {
277 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
278 }
279 rPar.Get32(0)->PutDecimal( pDec );
280#else
281 rPar.Get32(0)->PutEmpty();
282 StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTEDErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 55 ));
283#endif
284}
285
286void SbRtl_CDate(StarBASIC *, SbxArray & rPar, bool) // JSM
287{
288 double nVal = 0.0;
289 if ( rPar.Count32() == 2 )
290 {
291 SbxVariable *pSbxVariable = rPar.Get32(1);
292 nVal = pSbxVariable->GetDate();
293 }
294 else
295 {
296 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
297 }
298 rPar.Get32(0)->PutDate(nVal);
299}
300
301void SbRtl_CDbl(StarBASIC *, SbxArray & rPar, bool) // JSM
302{
303 double nVal = 0.0;
304 if ( rPar.Count32() == 2 )
305 {
306 SbxVariable *pSbxVariable = rPar.Get32(1);
307 if( pSbxVariable->GetType() == SbxSTRING )
308 {
309 // #41690
310 OUString aScanStr = pSbxVariable->GetOUString();
311 ErrCode Error = SbxValue::ScanNumIntnl( aScanStr, nVal );
312 if( Error != ERRCODE_NONEErrCode(0) )
313 {
314 StarBASIC::Error( Error );
315 }
316 }
317 else
318 {
319 nVal = pSbxVariable->GetDouble();
320 }
321 }
322 else
323 {
324 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
325 }
326
327 rPar.Get32(0)->PutDouble(nVal);
328}
329
330void SbRtl_CInt(StarBASIC *, SbxArray & rPar, bool) // JSM
331{
332 sal_Int16 nVal = 0;
333 if ( rPar.Count32() == 2 )
334 {
335 SbxVariable *pSbxVariable = rPar.Get32(1);
336 nVal = pSbxVariable->GetInteger();
337 }
338 else
339 {
340 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
341 }
342 rPar.Get32(0)->PutInteger(nVal);
343}
344
345void SbRtl_CLng(StarBASIC *, SbxArray & rPar, bool) // JSM
346{
347 sal_Int32 nVal = 0;
348 if ( rPar.Count32() == 2 )
349 {
350 SbxVariable *pSbxVariable = rPar.Get32(1);
351 nVal = pSbxVariable->GetLong();
352 }
353 else
354 {
355 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
356 }
357 rPar.Get32(0)->PutLong(nVal);
358}
359
360void SbRtl_CSng(StarBASIC *, SbxArray & rPar, bool) // JSM
361{
362 float nVal = float(0.0);
363 if ( rPar.Count32() == 2 )
364 {
365 SbxVariable *pSbxVariable = rPar.Get32(1);
366 if( pSbxVariable->GetType() == SbxSTRING )
367 {
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_NONEErrCode(0) && Error != ERRCODE_NONEErrCode(0) )
373 {
374 StarBASIC::Error( Error );
375 }
376 nVal = static_cast<float>(dVal);
377 }
378 else
379 {
380 nVal = pSbxVariable->GetSingle();
381 }
382 }
383 else
384 {
385 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
386 }
387 rPar.Get32(0)->PutSingle(nVal);
388}
389
390void SbRtl_CStr(StarBASIC *, SbxArray & rPar, bool) // JSM
391{
392 OUString aString;
393 if ( rPar.Count32() == 2 )
394 {
395 SbxVariable *pSbxVariable = rPar.Get32(1);
396 aString = pSbxVariable->GetOUString();
397 }
398 else
399 {
400 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
401 }
402 rPar.Get32(0)->PutString(aString);
403}
404
405void SbRtl_CVar(StarBASIC *, SbxArray & rPar, bool) // JSM
406{
407 SbxValues aVals( SbxVARIANT );
408 if ( rPar.Count32() == 2 )
409 {
410 SbxVariable *pSbxVariable = rPar.Get32(1);
411 pSbxVariable->Get( aVals );
412 }
413 else
414 {
415 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
416 }
417 rPar.Get32(0)->Put( aVals );
418}
419
420void SbRtl_CVErr(StarBASIC *, SbxArray & rPar, bool)
421{
422 sal_Int16 nErrCode = 0;
423 if ( rPar.Count32() == 2 )
424 {
425 SbxVariable *pSbxVariable = rPar.Get32(1);
426 nErrCode = pSbxVariable->GetInteger();
427 }
428 else
429 {
430 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
431 }
432 rPar.Get32(0)->PutErr( nErrCode );
433}
434
435void SbRtl_Iif(StarBASIC *, SbxArray & rPar, bool) // JSM
436{
437 if ( rPar.Count32() == 4 )
438 {
439 if (rPar.Get32(1)->GetBool())
440 {
441 *rPar.Get32(0) = *rPar.Get32(2);
442 }
443 else
444 {
445 *rPar.Get32(0) = *rPar.Get32(3);
446 }
447 }
448 else
449 {
450 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
451 }
452}
453
454void SbRtl_GetSystemType(StarBASIC *, SbxArray & rPar, bool)
455{
456 if ( rPar.Count32() != 1 )
457 {
458 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
459 }
460 else
461 {
462 // Removed for SRC595
463 rPar.Get32(0)->PutInteger( -1 );
464 }
465}
466
467void SbRtl_GetGUIType(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
468{
469 (void)pBasic;
470 (void)bWrite;
471
472 if ( rPar.Count32() != 1 )
473 {
474 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
475 }
476 else
477 {
478 // 17.7.2000 Make simple solution for testtool / fat office
479#if defined(_WIN32)
480 rPar.Get32(0)->PutInteger( 1 );
481#elif defined(UNX1)
482 rPar.Get32(0)->PutInteger( 4 );
483#else
484 rPar.Get32(0)->PutInteger( -1 );
485#endif
486 }
487}
488
489void SbRtl_Red(StarBASIC *, SbxArray & rPar, bool)
490{
491 if ( rPar.Count32() != 2 )
492 {
493 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
494 }
495 else
496 {
497 sal_Int32 nRGB = rPar.Get32(1)->GetLong();
498 nRGB &= 0x00FF0000;
499 nRGB >>= 16;
500 rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
501 }
502}
503
504void SbRtl_Green(StarBASIC *, SbxArray & rPar, bool)
505{
506 if ( rPar.Count32() != 2 )
507 {
508 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
509 }
510 else
511 {
512 sal_Int32 nRGB = rPar.Get32(1)->GetLong();
513 nRGB &= 0x0000FF00;
514 nRGB >>= 8;
515 rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
516 }
517}
518
519void SbRtl_Blue(StarBASIC *, SbxArray & rPar, bool)
520{
521 if ( rPar.Count32() != 2 )
522 {
523 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
524 }
525 else
526 {
527 sal_Int32 nRGB = rPar.Get32(1)->GetLong();
528 nRGB &= 0x000000FF;
529 rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nRGB) );
530 }
531}
532
533
534void SbRtl_Switch(StarBASIC *, SbxArray & rPar, bool)
535{
536 sal_uInt32 nCount = rPar.Count32();
537 if( !(nCount & 0x0001 ))
538 {
539 // number of arguments must be odd
540 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
541 }
542 sal_uInt32 nCurExpr = 1;
543 while( nCurExpr < (nCount-1) )
544 {
545 if( rPar.Get32( nCurExpr )->GetBool())
546 {
547 (*rPar.Get32(0)) = *(rPar.Get32(nCurExpr+1));
548 return;
549 }
550 nCurExpr += 2;
551 }
552 rPar.Get32(0)->PutNull();
553}
554
555//i#64882# Common wait impl for existing Wait and new WaitUntil
556// rtl functions
557void Wait_Impl( bool bDurationBased, SbxArray& rPar )
558{
559 if( rPar.Count32() != 2 )
560 {
561 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
562 return;
563 }
564 long nWait = 0;
565 if ( bDurationBased )
566 {
567 double dWait = rPar.Get32(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
571 }
572 else
573 {
574 nWait = rPar.Get32(1)->GetLong();
575 }
576 if( nWait < 0 )
577 {
578 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
579 return;
580 }
581
582 Timer aTimer;
583 aTimer.SetTimeout( nWait );
584 aTimer.Start();
585 while ( aTimer.IsActive() )
586 {
587 Application::Yield();
588 }
589}
590
591//i#64882#
592void SbRtl_Wait(StarBASIC *, SbxArray & rPar, bool)
593{
594 Wait_Impl( false, rPar );
595}
596
597//i#64882# add new WaitUntil ( for application.wait )
598// share wait_impl with 'normal' oobasic wait
599void SbRtl_WaitUntil(StarBASIC *, SbxArray & rPar, bool)
600{
601 Wait_Impl( true, rPar );
602}
603
604void SbRtl_DoEvents(StarBASIC *, SbxArray & rPar, bool)
605{
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.Get32(0)->PutInteger( 0 );
611 Application::Reschedule( true );
612}
613
614void SbRtl_GetGUIVersion(StarBASIC *, SbxArray & rPar, bool)
615{
616 if ( rPar.Count32() != 1 )
617 {
618 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
619 }
620 else
621 {
622 // Removed for SRC595
623 rPar.Get32(0)->PutLong( -1 );
624 }
625}
626
627void SbRtl_Choose(StarBASIC *, SbxArray & rPar, bool)
628{
629 if ( rPar.Count32() < 2 )
630 {
631 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
632 }
633 sal_Int16 nIndex = rPar.Get32(1)->GetInteger();
634 sal_uInt32 nCount = rPar.Count32();
635 nCount--;
636 if( nCount == 1 || nIndex > sal::static_int_cast<sal_Int16>(nCount-1) || nIndex < 1 )
637 {
638 rPar.Get32(0)->PutNull();
639 return;
640 }
641 (*rPar.Get32(0)) = *(rPar.Get32(nIndex+1));
642}
643
644
645void SbRtl_Trim(StarBASIC *, SbxArray & rPar, bool)
646{
647 if ( rPar.Count32() < 2 )
648 {
649 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
650 }
651 else
652 {
653 OUString aStr(comphelper::string::strip(rPar.Get32(1)->GetOUString(), ' '));
654 rPar.Get32(0)->PutString(aStr);
655 }
656}
657
658void SbRtl_GetSolarVersion(StarBASIC *, SbxArray & rPar, bool)
659{
660 rPar.Get32(0)->PutLong( LIBO_VERSION_MAJOR7 * 10000 + LIBO_VERSION_MINOR1 * 100 + LIBO_VERSION_MICRO0 * 1);
661}
662
663void SbRtl_TwipsPerPixelX(StarBASIC *, SbxArray & rPar, bool)
664{
665 sal_Int32 nResult = 0;
666 Size aSize( 100,0 );
667 MapMode aMap( MapUnit::MapTwip );
668 OutputDevice* pDevice = Application::GetDefaultDevice();
669 if( pDevice )
670 {
671 aSize = pDevice->PixelToLogic( aSize, aMap );
672 nResult = aSize.Width() / 100;
673 }
674 rPar.Get32(0)->PutLong( nResult );
675}
676
677void SbRtl_TwipsPerPixelY(StarBASIC *, SbxArray & rPar, bool)
678{
679 sal_Int32 nResult = 0;
680 Size aSize( 0,100 );
681 MapMode aMap( MapUnit::MapTwip );
682 OutputDevice* pDevice = Application::GetDefaultDevice();
683 if( pDevice )
684 {
685 aSize = pDevice->PixelToLogic( aSize, aMap );
686 nResult = aSize.Height() / 100;
687 }
688 rPar.Get32(0)->PutLong( nResult );
689}
690
691
692void SbRtl_FreeLibrary(StarBASIC *, SbxArray & rPar, bool)
693{
694 if ( rPar.Count32() != 2 )
695 {
696 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
697 }
698 GetSbData()->pInst->GetDllMgr()->FreeDll( rPar.Get32(1)->GetOUString() );
699}
700bool IsBaseIndexOne()
701{
702 bool bResult = false;
703 if ( GetSbData()->pInst && GetSbData()->pInst->pRun )
704 {
705 sal_uInt16 res = GetSbData()->pInst->pRun->GetBase();
706 if ( res )
707 {
708 bResult = true;
709 }
710 }
711 return bResult;
712}
713
714void SbRtl_Array(StarBASIC *, SbxArray & rPar, bool)
715{
716 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
717 sal_uInt32 nArraySize = rPar.Count32() - 1;
718 bool bIncIndex = IsBaseIndexOne();
719 if( nArraySize )
720 {
721 if ( bIncIndex )
722 {
723 pArray->AddDim32( 1, sal::static_int_cast<sal_Int32>(nArraySize) );
724 }
725 else
726 {
727 pArray->AddDim32( 0, sal::static_int_cast<sal_Int32>(nArraySize) - 1 );
728 }
729 }
730 else
731 {
732 pArray->unoAddDim32( 0, -1 );
733 }
734
735 // insert parameters into the array
736 for( sal_uInt32 i = 0 ; i < nArraySize ; i++ )
737 {
738 SbxVariable* pVar = rPar.Get32(i+1);
739 SbxVariable* pNew = new SbxEnsureParentVariable(*pVar);
740 pNew->SetFlag( SbxFlagBits::Write );
741 sal_Int32 aIdx[1];
742 aIdx[0] = static_cast<sal_Int32>(i);
743 if ( bIncIndex )
744 {
745 ++aIdx[0];
746 }
747 pArray->Put32(pNew, aIdx);
748 }
749
750 // return array
751 SbxVariableRef refVar = rPar.Get32(0);
752 SbxFlagBits nFlags = refVar->GetFlags();
753 refVar->ResetFlag( SbxFlagBits::Fixed );
754 refVar->PutObject( pArray );
755 refVar->SetFlags( nFlags );
756 refVar->SetParameters( nullptr );
757}
758
759
760// Featurewish #57868
761// The function returns a variant-array; if there are no parameters passed,
762// an empty array is created (according to dim a(); equal to a sequence of
763// the length 0 in Uno).
764// If there are parameters passed, there's a dimension created for each of
765// them; DimArray( 2, 2, 4 ) is equal to DIM a( 2, 2, 4 )
766// the array is always of the type variant
767void SbRtl_DimArray(StarBASIC *, SbxArray & rPar, bool)
768{
769 SbxDimArray * pArray = new SbxDimArray( SbxVARIANT );
770 sal_uInt32 nArrayDims = rPar.Count32() - 1;
771 if( nArrayDims > 0 )
772 {
773 for( sal_uInt32 i = 0; i < nArrayDims ; i++ )
774 {
775 sal_Int32 ub = rPar.Get32(i+1)->GetLong();
776 if( ub < 0 )
777 {
778 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGEErrCode( ErrCodeArea::Sbx, ErrCodeClass::Sbx, 4) );
779 ub = 0;
780 }
781 pArray->AddDim32( 0, ub );
782 }
783 }
784 else
785 {
786 pArray->unoAddDim32( 0, -1 );
787 }
788 SbxVariableRef refVar = rPar.Get32(0);
789 SbxFlagBits nFlags = refVar->GetFlags();
790 refVar->ResetFlag( SbxFlagBits::Fixed );
791 refVar->PutObject( pArray );
792 refVar->SetFlags( nFlags );
793 refVar->SetParameters( nullptr );
794}
795
796/*
797 * FindObject and FindPropertyObject make it possible to
798 * address objects and properties of the type Object with
799 * their name as string-parameters at the runtime.
800 *
801 * Example:
802 * MyObj.Prop1.Bla = 5
803 *
804 * is equal to:
805 * dim ObjVar as Object
806 * dim ObjProp as Object
807 * ObjName$ = "MyObj"
808 * ObjVar = FindObject( ObjName$ )
809 * PropName$ = "Prop1"
810 * ObjProp = FindPropertyObject( ObjVar, PropName$ )
811 * ObjProp.Bla = 5
812 *
813 * The names can be created dynamically at the runtime
814 * so that e. g. via controls "TextEdit1" to "TextEdit5"
815 * can be iterated in a dialog in a loop.
816 */
817
818
819// 1st parameter = the object's name as string
820void SbRtl_FindObject(StarBASIC *, SbxArray & rPar, bool)
821{
822 if ( rPar.Count32() < 2 )
823 {
824 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
825 return;
826 }
827
828 OUString aNameStr = rPar.Get32(1)->GetOUString();
829
830 SbxBase* pFind = StarBASIC::FindSBXInCurrentScope( aNameStr );
831 SbxObject* pFindObj = nullptr;
832 if( pFind )
833 {
834 pFindObj = dynamic_cast<SbxObject*>( pFind );
835 }
836 SbxVariableRef refVar = rPar.Get32(0);
837 refVar->PutObject( pFindObj );
838}
839
840// address object-property in an object
841// 1st parameter = object
842// 2nd parameter = the property's name as string
843void SbRtl_FindPropertyObject(StarBASIC *, SbxArray & rPar, bool)
844{
845 if ( rPar.Count32() < 3 )
846 {
847 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
848 return;
849 }
850
851 SbxBase* pObjVar = rPar.Get32(1)->GetObject();
852 SbxObject* pObj = nullptr;
853 if( pObjVar )
854 {
855 pObj = dynamic_cast<SbxObject*>( pObjVar );
856 }
857 if( !pObj && dynamic_cast<const SbxVariable*>( pObjVar) )
858 {
859 SbxBase* pObjVarObj = static_cast<SbxVariable*>(pObjVar)->GetObject();
860 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
861 }
862
863 OUString aNameStr = rPar.Get32(2)->GetOUString();
864
865 SbxObject* pFindObj = nullptr;
866 if( pObj )
867 {
868 SbxVariable* pFindVar = pObj->Find( aNameStr, SbxClassType::Object );
869 pFindObj = dynamic_cast<SbxObject*>( pFindVar );
870 }
871 else
872 {
873 StarBASIC::Error( ERRCODE_BASIC_BAD_PARAMETERErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 7) );
874 }
875
876 SbxVariableRef refVar = rPar.Get32(0);
877 refVar->PutObject( pFindObj );
878}
879
880
881static bool lcl_WriteSbxVariable( const SbxVariable& rVar, SvStream* pStrm,
882 bool bBinary, short nBlockLen, bool bIsArray )
883{
884 sal_uInt64 const nFPos = pStrm->Tell();
885
886 bool bIsVariant = !rVar.IsFixed();
887 SbxDataType eType = rVar.GetType();
888
889 switch( eType )
890 {
891 case SbxBOOL:
892 case SbxCHAR:
893 case SbxBYTE:
894 if( bIsVariant )
895 {
896 pStrm->WriteUInt16( SbxBYTE ); // VarType Id
897 }
898 pStrm->WriteUChar( rVar.GetByte() );
899 break;
900
901 case SbxEMPTY:
902 case SbxNULL:
903 case SbxVOID:
904 case SbxINTEGER:
905 case SbxUSHORT:
906 case SbxINT:
907 case SbxUINT:
908 if( bIsVariant )
909 {
910 pStrm->WriteUInt16( SbxINTEGER ); // VarType Id
911 }
912 pStrm->WriteInt16( rVar.GetInteger() );
913 break;
914
915 case SbxLONG:
916 case SbxULONG:
917 if( bIsVariant )
918 {
919 pStrm->WriteUInt16( SbxLONG ); // VarType Id
920 }
921 pStrm->WriteInt32( rVar.GetLong() );
922 break;
923 case SbxSALINT64:
924 case SbxSALUINT64:
925 if( bIsVariant )
926 {
927 pStrm->WriteUInt16( SbxSALINT64 ); // VarType Id
928 }
929 pStrm->WriteUInt64( rVar.GetInt64() );
930 break;
931 case SbxSINGLE:
932 if( bIsVariant )
933 {
934 pStrm->WriteUInt16( eType ); // VarType Id
935 }
936 pStrm->WriteFloat( rVar.GetSingle() );
937 break;
938
939 case SbxDOUBLE:
940 case SbxCURRENCY:
941 case SbxDATE:
942 if( bIsVariant )
943 {
944 pStrm->WriteUInt16( eType ); // VarType Id
945 }
946 pStrm->WriteDouble( rVar.GetDouble() );
947 break;
948
949 case SbxSTRING:
950 case SbxLPSTR:
951 {
952 const OUString& rStr = rVar.GetOUString();
953 if( !bBinary || bIsArray )
954 {
955 if( bIsVariant )
956 {
957 pStrm->WriteUInt16( SbxSTRING );
958 }
959 pStrm->WriteUniOrByteString( rStr, osl_getThreadTextEncoding() );
960 }
961 else
962 {
963 // without any length information! without end-identifier!
964 // What does that mean for Unicode?! Choosing conversion to ByteString...
965 OString aByteStr(OUStringToOString(rStr, osl_getThreadTextEncoding()));
966 pStrm->WriteOString( aByteStr );
967 }
968 }
969 break;
970
971 default:
972 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
973 return false;
974 }
975
976 if( nBlockLen )
977 {
978 pStrm->Seek( nFPos + nBlockLen );
979 }
980 return pStrm->GetErrorCode() == ERRCODE_NONEErrCode(0);
981}
982
983static bool lcl_ReadSbxVariable( SbxVariable& rVar, SvStream* pStrm,
984 bool bBinary, short nBlockLen )
985{
986 double aDouble;
987
988 sal_uInt64 const nFPos = pStrm->Tell();
989
990 bool bIsVariant = !rVar.IsFixed();
991 SbxDataType eVarType = rVar.GetType();
992
993 SbxDataType eSrcType = eVarType;
994 if( bIsVariant )
995 {
996 sal_uInt16 nTemp;
997 pStrm->ReadUInt16( nTemp );
998 eSrcType = static_cast<SbxDataType>(nTemp);
999 }
1000
1001 switch( eSrcType )
1002 {
1003 case SbxBOOL:
1004 case SbxCHAR:
1005 case SbxBYTE:
1006 {
1007 sal_uInt8 aByte;
1008 pStrm->ReadUChar( aByte );
1009
1010 if( bBinary && SbiRuntime::isVBAEnabled() && aByte == 1 && pStrm->eof() )
1011 {
1012 aByte = 0;
1013 }
1014 rVar.PutByte( aByte );
1015 }
1016 break;
1017
1018 case SbxEMPTY:
1019 case SbxNULL:
1020 case SbxVOID:
1021 case SbxINTEGER:
1022 case SbxUSHORT:
1023 case SbxINT:
1024 case SbxUINT:
1025 {
1026 sal_Int16 aInt;
1027 pStrm->ReadInt16( aInt );
1028 rVar.PutInteger( aInt );
1029 }
1030 break;
1031
1032 case SbxLONG:
1033 case SbxULONG:
1034 {
1035 sal_Int32 aInt;
1036 pStrm->ReadInt32( aInt );
1037 rVar.PutLong( aInt );
1038 }
1039 break;
1040 case SbxSALINT64:
1041 case SbxSALUINT64:
1042 {
1043 sal_uInt32 aInt;
1044 pStrm->ReadUInt32( aInt );
1045 rVar.PutInt64( static_cast<sal_Int64>(aInt) );
1046 }
1047 break;
1048 case SbxSINGLE:
1049 {
1050 float nS;
1051 pStrm->ReadFloat( nS );
1052 rVar.PutSingle( nS );
1053 }
1054 break;
1055
1056 case SbxDOUBLE:
1057 case SbxCURRENCY:
1058 {
1059 pStrm->ReadDouble( aDouble );
1060 rVar.PutDouble( aDouble );
1061 }
1062 break;
1063
1064 case SbxDATE:
1065 {
1066 pStrm->ReadDouble( aDouble );
1067 rVar.PutDate( aDouble );
1068 }
1069 break;
1070
1071 case SbxSTRING:
1072 case SbxLPSTR:
1073 {
1074 OUString aStr = pStrm->ReadUniOrByteString(osl_getThreadTextEncoding());
1075 rVar.PutString( aStr );
1076 }
1077 break;
1078
1079 default:
1080 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1081 return false;
1082 }
1083
1084 if( nBlockLen )
1085 {
1086 pStrm->Seek( nFPos + nBlockLen );
1087 }
1088 return pStrm->GetErrorCode() == ERRCODE_NONEErrCode(0);
1089}
1090
1091
1092// nCurDim = 1...n
1093static bool lcl_WriteReadSbxArray( SbxDimArray& rArr, SvStream* pStrm,
1094 bool bBinary, sal_Int32 nCurDim, sal_Int32* pOtherDims, bool bWrite )
1095{
1096 SAL_WARN_IF( nCurDim <= 0,"basic", "Bad Dim")do { if (true && (nCurDim <= 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "basic")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Bad Dim")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("basic"
), ("/home/maarten/src/libreoffice/core/basic/source/runtime/methods1.cxx"
":" "1096" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Bad Dim"), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "Bad Dim"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("basic"), ("/home/maarten/src/libreoffice/core/basic/source/runtime/methods1.cxx"
":" "1096" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Bad Dim") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("basic"), ("/home/maarten/src/libreoffice/core/basic/source/runtime/methods1.cxx"
":" "1096" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Bad Dim"), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "Bad Dim"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("basic"), ("/home/maarten/src/libreoffice/core/basic/source/runtime/methods1.cxx"
":" "1096" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1097 sal_Int32 nLower, nUpper;
1098 if( !rArr.GetDim32( nCurDim, nLower, nUpper ) )
1099 return false;
1100 for(sal_Int32 nCur = nLower; nCur <= nUpper; nCur++ )
1101 {
1102 pOtherDims[ nCurDim-1 ] = nCur;
1103 if( nCurDim != 1 )
1104 lcl_WriteReadSbxArray(rArr, pStrm, bBinary, nCurDim-1, pOtherDims, bWrite);
1105 else
1106 {
1107 SbxVariable* pVar = rArr.Get32( pOtherDims );
1108 bool bRet;
1109 if( bWrite )
1110 bRet = lcl_WriteSbxVariable(*pVar, pStrm, bBinary, 0, true );
1111 else
1112 bRet = lcl_ReadSbxVariable(*pVar, pStrm, bBinary, 0 );
1113 if( !bRet )
1114 return false;
1115 }
1116 }
1117 return true;
1118}
1119
1120static void PutGet( SbxArray& rPar, bool bPut )
1121{
1122 if ( rPar.Count32() != 4 )
1123 {
1124 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1125 return;
1126 }
1127 sal_Int16 nFileNo = rPar.Get32(1)->GetInteger();
1128 SbxVariable* pVar2 = rPar.Get32(2);
1129 SbxDataType eType2 = pVar2->GetType();
1130 bool bHasRecordNo = (eType2 != SbxEMPTY && eType2 != SbxERROR);
1131 long nRecordNo = pVar2->GetLong();
1132 if ( nFileNo < 1 || ( bHasRecordNo && nRecordNo < 1 ) )
1133 {
1134 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1135 return;
1136 }
1137 nRecordNo--;
1138 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
1139 SbiStream* pSbStrm = pIO->GetStream( nFileNo );
1140
1141 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Random)) )
1142 {
1143 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNELErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 41 ) );
1144 return;
1145 }
1146
1147 SvStream* pStrm = pSbStrm->GetStrm();
1148 bool bRandom = pSbStrm->IsRandom();
1149 short nBlockLen = bRandom ? pSbStrm->GetBlockLen() : 0;
1150
1151 if( bPut )
1152 {
1153 pSbStrm->ExpandFile();
1154 }
1155
1156 if( bHasRecordNo )
1157 {
1158 sal_uInt64 const nFilePos = bRandom
1159 ? static_cast<sal_uInt64>(nBlockLen * nRecordNo)
1160 : static_cast<sal_uInt64>(nRecordNo);
1161 pStrm->Seek( nFilePos );
1162 }
1163
1164 SbxDimArray* pArr = nullptr;
1165 SbxVariable* pVar = rPar.Get32(3);
1166 if( pVar->GetType() & SbxARRAY )
1167 {
1168 SbxBase* pParObj = pVar->GetObject();
1169 pArr = dynamic_cast<SbxDimArray*>( pParObj );
1170 }
1171
1172 bool bRet;
1173
1174 if( pArr )
1175 {
1176 sal_uInt64 const nFPos = pStrm->Tell();
1177 sal_Int32 nDims = pArr->GetDims32();
1178 std::unique_ptr<sal_Int32[]> pDims(new sal_Int32[ nDims ]);
1179 bRet = lcl_WriteReadSbxArray(*pArr,pStrm,!bRandom,nDims,pDims.get(),bPut);
1180 pDims.reset();
1181 if( nBlockLen )
1182 pStrm->Seek( nFPos + nBlockLen );
1183 }
1184 else
1185 {
1186 if( bPut )
1187 bRet = lcl_WriteSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, false);
1188 else
1189 bRet = lcl_ReadSbxVariable(*pVar, pStrm, !bRandom, nBlockLen);
1190 }
1191 if( !bRet || pStrm->GetErrorCode() )
1192 StarBASIC::Error( ERRCODE_BASIC_IO_ERRORErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 45 ) );
1193}
1194
1195void SbRtl_Put(StarBASIC *, SbxArray & rPar, bool)
1196{
1197 PutGet( rPar, true );
1198}
1199
1200void SbRtl_Get(StarBASIC *, SbxArray & rPar, bool)
1201{
1202 PutGet( rPar, false );
1203}
1204
1205void SbRtl_Environ(StarBASIC *, SbxArray & rPar, bool)
1206{
1207 if ( rPar.Count32() != 2 )
1208 {
1209 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1210 return;
1211 }
1212 OUString aResult;
1213 // should be ANSI but that's not possible under Win16 in the DLL
1214 OString aByteStr(OUStringToOString(rPar.Get32(1)->GetOUString(),
1215 osl_getThreadTextEncoding()));
1216 const char* pEnvStr = getenv(aByteStr.getStr());
1217 if ( pEnvStr )
1218 {
1219 aResult = OUString(pEnvStr, strlen(pEnvStr), osl_getThreadTextEncoding());
1220 }
1221 rPar.Get32(0)->PutString( aResult );
1222}
1223
1224static double GetDialogZoomFactor( bool bX, long nValue )
1225{
1226 OutputDevice* pDevice = Application::GetDefaultDevice();
1227 double nResult = 0;
1228 if( pDevice )
1229 {
1230 Size aRefSize( nValue, nValue );
1231 Fraction aFracX( 1, 26 );
1232 Fraction aFracY( 1, 24 );
1233 MapMode aMap( MapUnit::MapAppFont, Point(), aFracX, aFracY );
1234 Size aScaledSize = pDevice->LogicToPixel( aRefSize, aMap );
1235 aRefSize = pDevice->LogicToPixel( aRefSize, MapMode(MapUnit::MapTwip) );
1236
1237 double nRef, nScaled;
1238 if( bX )
1239 {
1240 nRef = aRefSize.Width();
1241 nScaled = aScaledSize.Width();
1242 }
1243 else
1244 {
1245 nRef = aRefSize.Height();
1246 nScaled = aScaledSize.Height();
1247 }
1248 nResult = nScaled / nRef;
1249 }
1250 return nResult;
1251}
1252
1253
1254void SbRtl_GetDialogZoomFactorX(StarBASIC *, SbxArray & rPar, bool)
1255{
1256 if ( rPar.Count32() != 2 )
1257 {
1258 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1259 return;
1260 }
1261 rPar.Get32(0)->PutDouble( GetDialogZoomFactor( true, rPar.Get32(1)->GetLong() ));
1262}
1263
1264void SbRtl_GetDialogZoomFactorY(StarBASIC *, SbxArray & rPar, bool)
1265{
1266 if ( rPar.Count32() != 2 )
1267 {
1268 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1269 return;
1270 }
1271 rPar.Get32(0)->PutDouble( GetDialogZoomFactor( false, rPar.Get32(1)->GetLong()));
1272}
1273
1274
1275void SbRtl_EnableReschedule(StarBASIC *, SbxArray & rPar, bool)
1276{
1277 rPar.Get32(0)->PutEmpty();
1278 if ( rPar.Count32() != 2 )
1279 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1280 if( GetSbData()->pInst )
1281 GetSbData()->pInst->EnableReschedule( rPar.Get32(1)->GetBool() );
1282}
1283
1284void SbRtl_GetSystemTicks(StarBASIC *, SbxArray & rPar, bool)
1285{
1286 if ( rPar.Count32() != 1 )
1287 {
1288 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1289 return;
1290 }
1291 rPar.Get32(0)->PutLong( tools::Time::GetSystemTicks() );
1292}
1293
1294void SbRtl_GetPathSeparator(StarBASIC *, SbxArray & rPar, bool)
1295{
1296 if ( rPar.Count32() != 1 )
1297 {
1298 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1299 return;
1300 }
1301 rPar.Get32(0)->PutString( OUString( SAL_PATHDELIMITER'/' ) );
1302}
1303
1304void SbRtl_ResolvePath(StarBASIC *, SbxArray & rPar, bool)
1305{
1306 if ( rPar.Count32() == 2 )
1307 {
1308 OUString aStr = rPar.Get32(1)->GetOUString();
1309 rPar.Get32(0)->PutString( aStr );
1310 }
1311 else
1312 {
1313 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1314 }
1315}
1316
1317void SbRtl_TypeLen(StarBASIC *, SbxArray & rPar, bool)
1318{
1319 if ( rPar.Count32() != 2 )
1320 {
1321 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1322 }
1323 else
1324 {
1325 SbxDataType eType = rPar.Get32(1)->GetType();
1326 sal_Int16 nLen = 0;
1327 switch( eType )
1328 {
1329 case SbxEMPTY:
1330 case SbxNULL:
1331 case SbxVECTOR:
1332 case SbxARRAY:
1333 case SbxBYREF:
1334 case SbxVOID:
1335 case SbxHRESULT:
1336 case SbxPOINTER:
1337 case SbxDIMARRAY:
1338 case SbxCARRAY:
1339 case SbxUSERDEF:
1340 nLen = 0;
1341 break;
1342
1343 case SbxINTEGER:
1344 case SbxERROR:
1345 case SbxUSHORT:
1346 case SbxINT:
1347 case SbxUINT:
1348 nLen = 2;
1349 break;
1350
1351 case SbxLONG:
1352 case SbxSINGLE:
1353 case SbxULONG:
1354 nLen = 4;
1355 break;
1356
1357 case SbxDOUBLE:
1358 case SbxCURRENCY:
1359 case SbxDATE:
1360 case SbxSALINT64:
1361 case SbxSALUINT64:
1362 nLen = 8;
1363 break;
1364
1365 case SbxOBJECT:
1366 case SbxVARIANT:
1367 case SbxDATAOBJECT:
1368 nLen = 0;
1369 break;
1370
1371 case SbxCHAR:
1372 case SbxBYTE:
1373 case SbxBOOL:
1374 nLen = 1;
1375 break;
1376
1377 case SbxLPSTR:
1378 case SbxLPWSTR:
1379 case SbxCoreSTRING:
1380 case SbxSTRING:
1381 nLen = static_cast<sal_Int16>(rPar.Get32(1)->GetOUString().getLength());
1382 break;
1383
1384 default:
1385 nLen = 0;
1386 break;
1387 }
1388 rPar.Get32(0)->PutInteger( nLen );
1389 }
1390}
1391
1392
1393// 1st parameter == class name, other parameters for initialisation
1394void SbRtl_CreateUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1395{
1396 RTL_Impl_CreateUnoStruct( rPar );
1397}
1398
1399
1400// 1st parameter == service-name
1401void SbRtl_CreateUnoService(StarBASIC *, SbxArray & rPar, bool)
1402{
1403 RTL_Impl_CreateUnoService( rPar );
1404}
1405
1406void SbRtl_CreateUnoServiceWithArguments(StarBASIC *, SbxArray & rPar, bool)
1407{
1408 RTL_Impl_CreateUnoServiceWithArguments( rPar );
1409}
1410
1411
1412void SbRtl_CreateUnoValue(StarBASIC *, SbxArray & rPar, bool)
1413{
1414 RTL_Impl_CreateUnoValue( rPar );
1415}
1416
1417
1418// no parameters
1419void SbRtl_GetProcessServiceManager(StarBASIC *, SbxArray & rPar, bool)
1420{
1421 RTL_Impl_GetProcessServiceManager( rPar );
1422}
1423
1424
1425// 1st parameter == Sequence<PropertyValue>
1426void SbRtl_CreatePropertySet(StarBASIC *, SbxArray & rPar, bool)
1427{
1428 RTL_Impl_CreatePropertySet( rPar );
1429}
1430
1431
1432// multiple interface-names as parameters
1433void SbRtl_HasUnoInterfaces(StarBASIC *, SbxArray & rPar, bool)
1434{
1435 RTL_Impl_HasInterfaces( rPar );
1436}
1437
1438
1439void SbRtl_IsUnoStruct(StarBASIC *, SbxArray & rPar, bool)
1440{
1441 RTL_Impl_IsUnoStruct( rPar );
1442}
1443
1444
1445void SbRtl_EqualUnoObjects(StarBASIC *, SbxArray & rPar, bool)
1446{
1447 RTL_Impl_EqualUnoObjects( rPar );
1448}
1449
1450void SbRtl_CreateUnoDialog(StarBASIC *, SbxArray & rPar, bool)
1451{
1452 RTL_Impl_CreateUnoDialog( rPar );
1453}
1454
1455// Return the application standard lib as root scope
1456void SbRtl_GlobalScope(StarBASIC * pBasic, SbxArray & rPar, bool)
1457{
1458 SbxObject* p = pBasic;
1459 while( p->GetParent() )
1460 {
1461 p = p->GetParent();
1462 }
1463 SbxVariableRef refVar = rPar.Get32(0);
1464 refVar->PutObject( p );
1465}
1466
1467// Helper functions to convert Url from/to system paths
1468void SbRtl_ConvertToUrl(StarBASIC *, SbxArray & rPar, bool)
1469{
1470 if ( rPar.Count32() == 2 )
1471 {
1472 OUString aStr = rPar.Get32(1)->GetOUString();
1473 INetURLObject aURLObj( aStr, INetProtocol::File );
1474 OUString aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1475 if( aFileURL.isEmpty() )
1476 {
1477 osl::File::getFileURLFromSystemPath(aStr, aFileURL);
1478 }
1479 if( aFileURL.isEmpty() )
1480 {
1481 aFileURL = aStr;
1482 }
1483 rPar.Get32(0)->PutString(aFileURL);
1484 }
1485 else
1486 {
1487 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1488 }
1489}
1490
1491void SbRtl_ConvertFromUrl(StarBASIC *, SbxArray & rPar, bool)
1492{
1493 if ( rPar.Count32() == 2 )
1494 {
1495 OUString aStr = rPar.Get32(1)->GetOUString();
1496 OUString aSysPath;
1497 ::osl::File::getSystemPathFromFileURL( aStr, aSysPath );
1498 if( aSysPath.isEmpty() )
1499 {
1500 aSysPath = aStr;
1501 }
1502 rPar.Get32(0)->PutString(aSysPath);
1503 }
1504 else
1505 {
1506 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1507 }
1508}
1509
1510
1511// Provide DefaultContext
1512void SbRtl_GetDefaultContext(StarBASIC *, SbxArray & rPar, bool)
1513{
1514 RTL_Impl_GetDefaultContext( rPar );
1515}
1516
1517void SbRtl_Join(StarBASIC *, SbxArray & rPar, bool)
1518{
1519 sal_uInt32 nParCount = rPar.Count32();
1520 if ( nParCount != 3 && nParCount != 2 )
1521 {
1522 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1523 return;
1524 }
1525 SbxBase* pParObj = rPar.Get32(1)->GetObject();
1526 SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
1527 if( pArr )
1528 {
1529 if( pArr->GetDims32() != 1 )
1530 {
1531 StarBASIC::Error( ERRCODE_BASIC_WRONG_DIMSErrCode( ErrCodeArea::Sbx, ErrCodeClass::Compiler, 116 ) ); // Syntax Error?!
1532 return;
1533 }
1534 OUString aDelim;
1535 if( nParCount == 3 )
1536 {
1537 aDelim = rPar.Get32(2)->GetOUString();
1538 }
1539 else
1540 {
1541 aDelim = " ";
1542 }
1543 OUStringBuffer aRetStr(32);
1544 sal_Int32 nLower, nUpper;
1545 pArr->GetDim32( 1, nLower, nUpper );
1546 sal_Int32 aIdx[1];
1547 for (aIdx[0] = nLower; aIdx[0] <= nUpper; ++aIdx[0])
1548 {
1549 OUString aStr = pArr->Get32(aIdx)->GetOUString();
1550 aRetStr.append(aStr);
1551 if (aIdx[0] != nUpper)
1552 {
1553 aRetStr.append(aDelim);
1554 }
1555 }
1556 rPar.Get32(0)->PutString( aRetStr.makeStringAndClear() );
1557 }
1558 else
1559 {
1560 StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMSErrCode( ErrCodeArea::Sbx, ErrCodeClass::Compiler, 112 ) );
1561 }
1562}
1563
1564
1565void SbRtl_Split(StarBASIC *, SbxArray & rPar, bool)
1566{
1567 sal_uInt32 nParCount = rPar.Count32();
1568 if ( nParCount < 2 )
1569 {
1570 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1571 return;
1572 }
1573
1574 OUString aExpression = rPar.Get32(1)->GetOUString();
1575 sal_Int32 nArraySize = 0;
1576 std::vector< OUString > vRet;
1577 if( !aExpression.isEmpty() )
1578 {
1579 OUString aDelim;
1580 if( nParCount >= 3 )
1581 {
1582 aDelim = rPar.Get32(2)->GetOUString();
1583 }
1584 else
1585 {
1586 aDelim = " ";
1587 }
1588
1589 sal_Int32 nCount = -1;
1590 if( nParCount == 4 )
1591 {
1592 nCount = rPar.Get32(3)->GetLong();
1593 }
1594 sal_Int32 nDelimLen = aDelim.getLength();
1595 if( nDelimLen )
1596 {
1597 sal_Int32 iSearch = -1;
1598 sal_Int32 iStart = 0;
1599 do
1600 {
1601 bool bBreak = false;
1602 if( nCount >= 0 && nArraySize == nCount - 1 )
1603 {
1604 bBreak = true;
1605 }
1606 iSearch = aExpression.indexOf( aDelim, iStart );
1607 OUString aSubStr;
1608 if( iSearch >= 0 && !bBreak )
1609 {
1610 aSubStr = aExpression.copy( iStart, iSearch - iStart );
1611 iStart = iSearch + nDelimLen;
1612 }
1613 else
1614 {
1615 aSubStr = aExpression.copy( iStart );
1616 }
1617 vRet.push_back( aSubStr );
1618 nArraySize++;
1619
1620 if( bBreak )
1621 {
1622 break;
1623 }
1624 }
1625 while( iSearch >= 0 );
1626 }
1627 else
1628 {
1629 vRet.push_back( aExpression );
1630 nArraySize = 1;
1631 }
1632 }
1633
1634 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
1635 pArray->unoAddDim32( 0, nArraySize-1 );
1636
1637 // insert parameter(s) into the array
1638 for(sal_Int32 i = 0 ; i < nArraySize ; i++ )
1639 {
1640 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
1641 xVar->PutString( vRet[i] );
1642 pArray->Put32( xVar.get(), &i );
1643 }
1644
1645 // return array
1646 SbxVariableRef refVar = rPar.Get32(0);
1647 SbxFlagBits nFlags = refVar->GetFlags();
1648 refVar->ResetFlag( SbxFlagBits::Fixed );
1649 refVar->PutObject( pArray );
1650 refVar->SetFlags( nFlags );
1651 refVar->SetParameters( nullptr );
1652}
1653
1654// MonthName(month[, abbreviate])
1655void SbRtl_MonthName(StarBASIC *, SbxArray & rPar, bool)
1656{
1657 sal_uInt32 nParCount = rPar.Count32();
1658 if( nParCount != 2 && nParCount != 3 )
1659 {
1660 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1661 return;
1662 }
1663
1664 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1665 if( !xCalendar.is() )
1666 {
1667 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERRORErrCode( ErrCodeArea::Sbx, ErrCodeClass::Unknown, 9) );
1668 return;
1669 }
1670 Sequence< CalendarItem2 > aMonthSeq = xCalendar->getMonths2();
1671 sal_Int32 nMonthCount = aMonthSeq.getLength();
1672
1673 sal_Int16 nVal = rPar.Get32(1)->GetInteger();
1674 if( nVal < 1 || nVal > nMonthCount )
1675 {
1676 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1677 return;
1678 }
1679
1680 bool bAbbreviate = false;
1681 if( nParCount == 3 )
1682 bAbbreviate = rPar.Get32(2)->GetBool();
1683
1684 const CalendarItem2* pCalendarItems = aMonthSeq.getConstArray();
1685 const CalendarItem2& rItem = pCalendarItems[nVal - 1];
1686
1687 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1688 rPar.Get32(0)->PutString(aRetStr);
1689}
1690
1691// WeekdayName(weekday, abbreviate, firstdayofweek)
1692void SbRtl_WeekdayName(StarBASIC *, SbxArray & rPar, bool)
1693{
1694 sal_uInt32 nParCount = rPar.Count32();
1695 if( nParCount < 2 || nParCount > 4 )
1696 {
1697 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1698 return;
1699 }
1700
1701 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
1702 if( !xCalendar.is() )
1703 {
1704 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERRORErrCode( ErrCodeArea::Sbx, ErrCodeClass::Unknown, 9) );
1705 return;
1706 }
1707
1708 Sequence< CalendarItem2 > aDaySeq = xCalendar->getDays2();
1709 sal_Int16 nDayCount = static_cast<sal_Int16>(aDaySeq.getLength());
1710 sal_Int16 nDay = rPar.Get32(1)->GetInteger();
1711 sal_Int16 nFirstDay = 0;
1712 if( nParCount == 4 )
1713 {
1714 nFirstDay = rPar.Get32(3)->GetInteger();
1715 if( nFirstDay < 0 || nFirstDay > 7 )
1716 {
1717 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1718 return;
1719 }
1720 }
1721 if( nFirstDay == 0 )
1722 {
1723 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
1724 }
1725 nDay = 1 + (nDay + nDayCount + nFirstDay - 2) % nDayCount;
1726 if( nDay < 1 || nDay > nDayCount )
1727 {
1728 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1729 return;
1730 }
1731
1732 bool bAbbreviate = false;
1733 if( nParCount >= 3 )
1734 {
1735 SbxVariable* pPar2 = rPar.Get32(2);
1736 if( !pPar2->IsErr() )
1737 {
1738 bAbbreviate = pPar2->GetBool();
1739 }
1740 }
1741
1742 const CalendarItem2* pCalendarItems = aDaySeq.getConstArray();
1743 const CalendarItem2& rItem = pCalendarItems[nDay - 1];
1744
1745 OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName );
1746 rPar.Get32(0)->PutString( aRetStr );
1747}
1748
1749void SbRtl_Weekday(StarBASIC *, SbxArray & rPar, bool)
1750{
1751 sal_uInt32 nParCount = rPar.Count32();
1752 if ( nParCount < 2 )
1753 {
1754 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1755 }
1756 else
1757 {
1758 double aDate = rPar.Get32(1)->GetDate();
1759
1760 bool bFirstDay = false;
1761 sal_Int16 nFirstDay = 0;
1762 if ( nParCount > 2 )
1763 {
1764 nFirstDay = rPar.Get32(2)->GetInteger();
1765 bFirstDay = true;
1766 }
1767 sal_Int16 nDay = implGetWeekDay( aDate, bFirstDay, nFirstDay );
1768 rPar.Get32(0)->PutInteger( nDay );
1769 }
1770}
1771
1772namespace {
1773
1774enum Interval
1775{
1776 INTERVAL_YYYY,
1777 INTERVAL_Q,
1778 INTERVAL_M,
1779 INTERVAL_Y,
1780 INTERVAL_D,
1781 INTERVAL_W,
1782 INTERVAL_WW,
1783 INTERVAL_H,
1784 INTERVAL_N,
1785 INTERVAL_S
1786};
1787
1788struct IntervalInfo
1789{
1790 Interval meInterval;
1791 char const * mStringCode;
1792 double mdValue;
1793 bool mbSimple;
1794};
1795
1796}
1797
1798static IntervalInfo const * getIntervalInfo( const OUString& rStringCode )
1799{
1800 static IntervalInfo const aIntervalTable[] =
1801 {
1802 { INTERVAL_YYYY, "yyyy", 0.0, false }, // Year
1803 { INTERVAL_Q, "q", 0.0, false }, // Quarter
1804 { INTERVAL_M, "m", 0.0, false }, // Month
1805 { INTERVAL_Y, "y", 1.0, true }, // Day of year
1806 { INTERVAL_D, "d", 1.0, true }, // Day
1807 { INTERVAL_W, "w", 1.0, true }, // Weekday
1808 { INTERVAL_WW, "ww", 7.0, true }, // Week
1809 { INTERVAL_H, "h", 1.0 / 24.0, true }, // Hour
1810 { INTERVAL_N, "n", 1.0 / 1440.0, true }, // Minute
1811 { INTERVAL_S, "s", 1.0 / 86400.0, true } // Second
1812 };
1813 for( std::size_t i = 0; i != SAL_N_ELEMENTS(aIntervalTable)(sizeof(sal_n_array_size(aIntervalTable))); ++i )
1814 {
1815 if( rStringCode.equalsIgnoreAsciiCaseAscii(
1816 aIntervalTable[i].mStringCode ) )
1817 {
1818 return &aIntervalTable[i];
1819 }
1820 }
1821 return nullptr;
1822}
1823
1824static void implGetDayMonthYear( sal_Int16& rnYear, sal_Int16& rnMonth, sal_Int16& rnDay, double dDate )
1825{
1826 rnDay = implGetDateDay( dDate );
1827 rnMonth = implGetDateMonth( dDate );
1828 rnYear = implGetDateYear( dDate );
1829}
1830
1831/** Limits a date to valid dates within tools' class Date capabilities.
1832
1833 @return the year number, truncated if necessary and in that case also
1834 rMonth and rDay adjusted.
1835 */
1836static sal_Int16 limitDate( sal_Int32 n32Year, sal_Int16& rMonth, sal_Int16& rDay )
1837{
1838 if( n32Year > SAL_MAX_INT16((sal_Int16) 0x7FFF) )
1839 {
1840 n32Year = SAL_MAX_INT16((sal_Int16) 0x7FFF);
1841 rMonth = 12;
1842 rDay = 31;
1843 }
1844 else if( n32Year < SAL_MIN_INT16((sal_Int16) (-0x7FFF - 1)) )
1845 {
1846 n32Year = SAL_MIN_INT16((sal_Int16) (-0x7FFF - 1));
1847 rMonth = 1;
1848 rDay = 1;
1849 }
1850 return static_cast<sal_Int16>(n32Year);
1851}
1852
1853void SbRtl_DateAdd(StarBASIC *, SbxArray & rPar, bool)
1854{
1855 sal_uInt32 nParCount = rPar.Count32();
1856 if( nParCount != 4 )
1857 {
1858 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1859 return;
1860 }
1861
1862 OUString aStringCode = rPar.Get32(1)->GetOUString();
1863 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1864 if( !pInfo )
1865 {
1866 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1867 return;
1868 }
1869
1870 sal_Int32 lNumber = rPar.Get32(2)->GetLong();
1871 double dDate = rPar.Get32(3)->GetDate();
1872 double dNewDate = 0;
1873 if( pInfo->mbSimple )
1874 {
1875 double dAdd = pInfo->mdValue * lNumber;
1876 dNewDate = dDate + dAdd;
1877 }
1878 else
1879 {
1880 // Keep hours, minutes, seconds
1881 double dHoursMinutesSeconds = dDate - floor( dDate );
1882
1883 bool bOk = true;
1884 sal_Int16 nYear, nMonth, nDay;
1885 sal_Int16 nTargetYear16 = 0, nTargetMonth = 0;
1886 implGetDayMonthYear( nYear, nMonth, nDay, dDate );
1887 switch( pInfo->meInterval )
1888 {
1889 case INTERVAL_YYYY:
1890 {
1891 sal_Int32 nTargetYear = lNumber + nYear;
1892 nTargetYear16 = limitDate( nTargetYear, nMonth, nDay );
1893 /* TODO: should the result be error if the date was limited? It never was. */
1894 nTargetMonth = nMonth;
1895 bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
1896 break;
1897 }
1898 case INTERVAL_Q:
1899 case INTERVAL_M:
1900 {
1901 bool bNeg = (lNumber < 0);
1902 if( bNeg )
1903 lNumber = -lNumber;
1904 sal_Int32 nYearsAdd;
1905 sal_Int16 nMonthAdd;
1906 if( pInfo->meInterval == INTERVAL_Q )
1907 {
1908 nYearsAdd = lNumber / 4;
1909 nMonthAdd = static_cast<sal_Int16>( 3 * (lNumber % 4) );
1910 }
1911 else
1912 {
1913 nYearsAdd = lNumber / 12;
1914 nMonthAdd = static_cast<sal_Int16>( lNumber % 12 );
1915 }
1916
1917 sal_Int32 nTargetYear;
1918 if( bNeg )
1919 {
1920 nTargetMonth = nMonth - nMonthAdd;
1921 if( nTargetMonth <= 0 )
1922 {
1923 nTargetMonth += 12;
1924 nYearsAdd++;
1925 }
1926 nTargetYear = static_cast<sal_Int32>(nYear) - nYearsAdd;
1927 }
1928 else
1929 {
1930 nTargetMonth = nMonth + nMonthAdd;
1931 if( nTargetMonth > 12 )
1932 {
1933 nTargetMonth -= 12;
1934 nYearsAdd++;
1935 }
1936 nTargetYear = static_cast<sal_Int32>(nYear) + nYearsAdd;
1937 }
1938 nTargetYear16 = limitDate( nTargetYear, nTargetMonth, nDay );
1939 /* TODO: should the result be error if the date was limited? It never was. */
1940 bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate );
1941 break;
1942 }
1943 default: break;
1944 }
1945
1946 if( bOk )
1947 dNewDate += dHoursMinutesSeconds;
1948 }
1949
1950 rPar.Get32(0)->PutDate( dNewDate );
1951}
1952
1953static double RoundImpl( double d )
1954{
1955 return ( d >= 0 ) ? floor( d + 0.5 ) : -floor( -d + 0.5 );
1956}
1957
1958void SbRtl_DateDiff(StarBASIC *, SbxArray & rPar, bool)
1959{
1960 // DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])
1961
1962 sal_uInt32 nParCount = rPar.Count32();
1963 if( nParCount < 4 || nParCount > 6 )
1964 {
1965 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1966 return;
1967 }
1968
1969 OUString aStringCode = rPar.Get32(1)->GetOUString();
1970 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
1971 if( !pInfo )
1972 {
1973 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
1974 return;
1975 }
1976
1977 double dDate1 = rPar.Get32(2)->GetDate();
1978 double dDate2 = rPar.Get32(3)->GetDate();
1979
1980 double dRet = 0.0;
1981 switch( pInfo->meInterval )
1982 {
1983 case INTERVAL_YYYY:
1984 {
1985 sal_Int16 nYear1 = implGetDateYear( dDate1 );
1986 sal_Int16 nYear2 = implGetDateYear( dDate2 );
1987 dRet = nYear2 - nYear1;
1988 break;
1989 }
1990 case INTERVAL_Q:
1991 {
1992 sal_Int16 nYear1 = implGetDateYear( dDate1 );
1993 sal_Int16 nYear2 = implGetDateYear( dDate2 );
1994 sal_Int16 nQ1 = 1 + (implGetDateMonth( dDate1 ) - 1) / 3;
1995 sal_Int16 nQ2 = 1 + (implGetDateMonth( dDate2 ) - 1) / 3;
1996 sal_Int16 nQGes1 = 4 * nYear1 + nQ1;
1997 sal_Int16 nQGes2 = 4 * nYear2 + nQ2;
1998 dRet = nQGes2 - nQGes1;
1999 break;
2000 }
2001 case INTERVAL_M:
2002 {
2003 sal_Int16 nYear1 = implGetDateYear( dDate1 );
2004 sal_Int16 nYear2 = implGetDateYear( dDate2 );
2005 sal_Int16 nMonth1 = implGetDateMonth( dDate1 );
2006 sal_Int16 nMonth2 = implGetDateMonth( dDate2 );
2007 sal_Int16 nMonthGes1 = 12 * nYear1 + nMonth1;
2008 sal_Int16 nMonthGes2 = 12 * nYear2 + nMonth2;
2009 dRet = nMonthGes2 - nMonthGes1;
2010 break;
2011 }
2012 case INTERVAL_Y:
2013 case INTERVAL_D:
2014 {
2015 double dDays1 = floor( dDate1 );
2016 double dDays2 = floor( dDate2 );
2017 dRet = dDays2 - dDays1;
2018 break;
2019 }
2020 case INTERVAL_W:
2021 case INTERVAL_WW:
2022 {
2023 double dDays1 = floor( dDate1 );
2024 double dDays2 = floor( dDate2 );
2025 if( pInfo->meInterval == INTERVAL_WW )
2026 {
2027 sal_Int16 nFirstDay = 1; // Default
2028 if( nParCount >= 5 )
2029 {
2030 nFirstDay = rPar.Get32(4)->GetInteger();
2031 if( nFirstDay < 0 || nFirstDay > 7 )
2032 {
2033 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2034 return;
2035 }
2036 if( nFirstDay == 0 )
2037 {
2038 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
2039 if( !xCalendar.is() )
2040 {
2041 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERRORErrCode( ErrCodeArea::Sbx, ErrCodeClass::Unknown, 9) );
2042 return;
2043 }
2044 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
2045 }
2046 }
2047 sal_Int16 nDay1 = implGetWeekDay( dDate1 );
2048 sal_Int16 nDay1_Diff = nDay1 - nFirstDay;
2049 if( nDay1_Diff < 0 )
2050 nDay1_Diff += 7;
2051 dDays1 -= nDay1_Diff;
2052
2053 sal_Int16 nDay2 = implGetWeekDay( dDate2 );
2054 sal_Int16 nDay2_Diff = nDay2 - nFirstDay;
2055 if( nDay2_Diff < 0 )
2056 nDay2_Diff += 7;
2057 dDays2 -= nDay2_Diff;
2058 }
2059
2060 double dDiff = dDays2 - dDays1;
2061 dRet = ( dDiff >= 0 ) ? floor( dDiff / 7.0 ) : -floor( -dDiff / 7.0 );
2062 break;
2063 }
2064 case INTERVAL_H:
2065 {
2066 dRet = RoundImpl( 24.0 * (dDate2 - dDate1) );
2067 break;
2068 }
2069 case INTERVAL_N:
2070 {
2071 dRet = RoundImpl( 1440.0 * (dDate2 - dDate1) );
2072 break;
2073 }
2074 case INTERVAL_S:
2075 {
2076 dRet = RoundImpl( 86400.0 * (dDate2 - dDate1) );
2077 break;
2078 }
2079 }
2080 rPar.Get32(0)->PutDouble( dRet );
2081}
2082
2083static double implGetDateOfFirstDayInFirstWeek
2084 ( sal_Int16 nYear, sal_Int16& nFirstDay, sal_Int16& nFirstWeek, bool* pbError = nullptr )
2085{
2086 ErrCode nError = ERRCODE_NONEErrCode(0);
2087 if( nFirstDay < 0 || nFirstDay > 7 )
2088 nError = ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2);
2089
2090 if( nFirstWeek < 0 || nFirstWeek > 3 )
2091 nError = ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2);
2092
2093 Reference< XCalendar4 > xCalendar;
2094 if( nFirstDay == 0 || nFirstWeek == 0 )
2095 {
2096 xCalendar = getLocaleCalendar();
2097 if( !xCalendar.is() )
2098 nError = ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2);
2099 }
2100
2101 if( nError != ERRCODE_NONEErrCode(0) )
2102 {
2103 StarBASIC::Error( nError );
2104 if( pbError )
2105 *pbError = true;
2106 return 0.0;
2107 }
2108
2109 if( nFirstDay == 0 )
2110 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
2111
2112 sal_Int16 nFirstWeekMinDays = 0; // Not used for vbFirstJan1 = default
2113 if( nFirstWeek == 0 )
2114 {
2115 nFirstWeekMinDays = xCalendar->getMinimumNumberOfDaysForFirstWeek();
2116 if( nFirstWeekMinDays == 1 )
2117 {
2118 nFirstWeekMinDays = 0;
2119 nFirstWeek = 1;
2120 }
2121 else if( nFirstWeekMinDays == 4 )
2122 nFirstWeek = 2;
2123 else if( nFirstWeekMinDays == 7 )
2124 nFirstWeek = 3;
2125 }
2126 else if( nFirstWeek == 2 )
2127 nFirstWeekMinDays = 4; // vbFirstFourDays
2128 else if( nFirstWeek == 3 )
2129 nFirstWeekMinDays = 7; // vbFirstFourDays
2130
2131 double dBaseDate;
2132 implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
2133
2134 sal_Int16 nWeekDay0101 = implGetWeekDay( dBaseDate );
2135 sal_Int16 nDayDiff = nWeekDay0101 - nFirstDay;
2136 if( nDayDiff < 0 )
2137 nDayDiff += 7;
2138
2139 if( nFirstWeekMinDays )
2140 {
2141 sal_Int16 nThisWeeksDaysInYearCount = 7 - nDayDiff;
2142 if( nThisWeeksDaysInYearCount < nFirstWeekMinDays )
2143 nDayDiff -= 7;
2144 }
2145 double dRetDate = dBaseDate - nDayDiff;
2146 return dRetDate;
2147}
2148
2149void SbRtl_DatePart(StarBASIC *, SbxArray & rPar, bool)
2150{
2151 // DatePart(interval, date[,firstdayofweek[, firstweekofyear]])
2152
2153 sal_uInt32 nParCount = rPar.Count32();
2154 if( nParCount < 3 || nParCount > 5 )
2155 {
2156 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2157 return;
2158 }
2159
2160 OUString aStringCode = rPar.Get32(1)->GetOUString();
2161 IntervalInfo const * pInfo = getIntervalInfo( aStringCode );
2162 if( !pInfo )
2163 {
2164 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2165 return;
2166 }
2167
2168 double dDate = rPar.Get32(2)->GetDate();
2169
2170 sal_Int32 nRet = 0;
2171 switch( pInfo->meInterval )
2172 {
2173 case INTERVAL_YYYY:
2174 {
2175 nRet = implGetDateYear( dDate );
2176 break;
2177 }
2178 case INTERVAL_Q:
2179 {
2180 nRet = 1 + (implGetDateMonth( dDate ) - 1) / 3;
2181 break;
2182 }
2183 case INTERVAL_M:
2184 {
2185 nRet = implGetDateMonth( dDate );
2186 break;
2187 }
2188 case INTERVAL_Y:
2189 {
2190 sal_Int16 nYear = implGetDateYear( dDate );
2191 double dBaseDate;
2192 implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate );
2193 nRet = 1 + sal_Int32( dDate - dBaseDate );
2194 break;
2195 }
2196 case INTERVAL_D:
2197 {
2198 nRet = implGetDateDay( dDate );
2199 break;
2200 }
2201 case INTERVAL_W:
2202 {
2203 bool bFirstDay = false;
2204 sal_Int16 nFirstDay = 1; // Default
2205 if( nParCount >= 4 )
2206 {
2207 nFirstDay = rPar.Get32(3)->GetInteger();
2208 bFirstDay = true;
2209 }
2210 nRet = implGetWeekDay( dDate, bFirstDay, nFirstDay );
2211 break;
2212 }
2213 case INTERVAL_WW:
2214 {
2215 sal_Int16 nFirstDay = 1; // Default
2216 if( nParCount >= 4 )
2217 nFirstDay = rPar.Get32(3)->GetInteger();
2218
2219 sal_Int16 nFirstWeek = 1; // Default
2220 if( nParCount == 5 )
2221 nFirstWeek = rPar.Get32(4)->GetInteger();
2222
2223 sal_Int16 nYear = implGetDateYear( dDate );
2224 bool bError = false;
2225 double dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear, nFirstDay, nFirstWeek, &bError );
2226 if( !bError )
2227 {
2228 if( dYearFirstDay > dDate )
2229 {
2230 // Date belongs to last year's week
2231 dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear - 1, nFirstDay, nFirstWeek );
2232 }
2233 else if( nFirstWeek != 1 )
2234 {
2235 // Check if date belongs to next year
2236 double dNextYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear + 1, nFirstDay, nFirstWeek );
2237 if( dDate >= dNextYearFirstDay )
2238 dYearFirstDay = dNextYearFirstDay;
2239 }
2240
2241 // Calculate week
2242 double dDiff = dDate - dYearFirstDay;
2243 nRet = 1 + sal_Int32( dDiff / 7 );
2244 }
2245 break;
2246 }
2247 case INTERVAL_H:
2248 {
2249 nRet = implGetHour( dDate );
2250 break;
2251 }
2252 case INTERVAL_N:
2253 {
2254 nRet = implGetMinute( dDate );
2255 break;
2256 }
2257 case INTERVAL_S:
2258 {
2259 nRet = implGetSecond( dDate );
2260 break;
2261 }
2262 }
2263 rPar.Get32(0)->PutLong( nRet );
2264}
2265
2266// FormatDateTime(Date[,NamedFormat])
2267void SbRtl_FormatDateTime(StarBASIC *, SbxArray & rPar, bool)
2268{
2269 sal_uInt32 nParCount = rPar.Count32();
2270 if( nParCount < 2 || nParCount > 3 )
1
Assuming 'nParCount' is >= 2
2
Assuming 'nParCount' is <= 3
3
Taking false branch
2271 {
2272 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2273 return;
2274 }
2275
2276 double dDate = rPar.Get32(1)->GetDate();
2277 sal_Int16 nNamedFormat = 0;
2278 if( nParCount > 2 )
4
Assuming 'nParCount' is > 2
5
Taking true branch
2279 {
2280 nNamedFormat = rPar.Get32(2)->GetInteger();
2281 if( nNamedFormat < 0 || nNamedFormat > 4 )
6
Assuming 'nNamedFormat' is >= 0
7
Assuming 'nNamedFormat' is <= 4
8
Taking false branch
2282 {
2283 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2284 return;
2285 }
2286 }
2287
2288 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
2289 if( !xCalendar.is() )
9
Taking false branch
2290 {
2291 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERRORErrCode( ErrCodeArea::Sbx, ErrCodeClass::Unknown, 9) );
2292 return;
2293 }
2294
2295 OUString aRetStr;
2296 SbxVariableRef pSbxVar = new SbxVariable( SbxSTRING );
10
Memory is allocated
2297 switch( nNamedFormat )
11
Control jumps to 'case 1:' at line 2315
2298 {
2299 // GeneralDate:
2300 // Display a date and/or time. If there is a date part,
2301 // display it as a short date. If there is a time part,
2302 // display it as a long time. If present, both parts are displayed.
2303
2304 // 12/21/2004 11:24:50 AM
2305 // 21.12.2004 12:13:51
2306 case 0:
2307 pSbxVar->PutDate( dDate );
2308 aRetStr = pSbxVar->GetOUString();
2309 break;
2310
2311 // LongDate: Display a date using the long date format specified
2312 // in your computer's regional settings.
2313 // Tuesday, December 21, 2004
2314 // Dienstag, 21. December 2004
2315 case 1:
2316 {
2317 std::shared_ptr<SvNumberFormatter> pFormatter;
2318 if( GetSbData()->pInst )
12
Assuming field 'pInst' is non-null
13
Taking true branch
2319 {
2320 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2321 }
2322 else
2323 {
2324 sal_uInt32 n; // Dummy
2325 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
2326 }
2327
2328 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
2329 const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, eLangType );
2330 const Color* pCol;
2331 pFormatter->GetOutputString( dDate, nIndex, aRetStr, &pCol );
2332 break;
14
Execution continues on line 2364
2333 }
2334
2335 // ShortDate: Display a date using the short date format specified
2336 // in your computer's regional settings.
2337 // 21.12.2004
2338 case 2:
2339 pSbxVar->PutDate( floor(dDate) );
2340 aRetStr = pSbxVar->GetOUString();
2341 break;
2342
2343 // LongTime: Display a time using the time format specified
2344 // in your computer's regional settings.
2345 // 11:24:50 AM
2346 // 12:13:51
2347 case 3:
2348 // ShortTime: Display a time using the 24-hour format (hh:mm).
2349 // 11:24
2350 case 4:
2351 double dTime = modf( dDate, &o3tl::temporary(double()) );
2352 pSbxVar->PutDate( dTime );
2353 if( nNamedFormat == 3 )
2354 {
2355 aRetStr = pSbxVar->GetOUString();
2356 }
2357 else
2358 {
2359 aRetStr = pSbxVar->GetOUString().copy( 0, 5 );
2360 }
2361 break;
2362 }
2363
2364 rPar.Get32(0)->PutString( aRetStr );
2365}
15
Potential leak of memory pointed to by 'pSbxVar.pObj'
2366
2367void SbRtl_Frac(StarBASIC *, SbxArray & rPar, bool)
2368{
2369 sal_uInt32 nParCount = rPar.Count32();
2370 if( nParCount != 2)
2371 {
2372 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2373 return;
2374 }
2375
2376 SbxVariable *pSbxVariable = rPar.Get32(1);
2377 double dVal = pSbxVariable->GetDouble();
2378 if(dVal >= 0)
2379 rPar.Get32(0)->PutDouble(dVal - ::rtl::math::approxFloor(dVal));
2380 else
2381 rPar.Get32(0)->PutDouble(dVal - ::rtl::math::approxCeil(dVal));
2382}
2383
2384void SbRtl_Round(StarBASIC *, SbxArray & rPar, bool)
2385{
2386 sal_uInt32 nParCount = rPar.Count32();
2387 if( nParCount != 2 && nParCount != 3 )
2388 {
2389 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2390 return;
2391 }
2392
2393 SbxVariable *pSbxVariable = rPar.Get32(1);
2394 double dVal = pSbxVariable->GetDouble();
2395 double dRes = 0.0;
2396 if( dVal != 0.0 )
2397 {
2398 bool bNeg = false;
2399 if( dVal < 0.0 )
2400 {
2401 bNeg = true;
2402 dVal = -dVal;
2403 }
2404
2405 sal_Int16 numdecimalplaces = 0;
2406 if( nParCount == 3 )
2407 {
2408 numdecimalplaces = rPar.Get32(2)->GetInteger();
2409 if( numdecimalplaces < 0 || numdecimalplaces > 22 )
2410 {
2411 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2412 return;
2413 }
2414 }
2415
2416 if( numdecimalplaces == 0 )
2417 {
2418 dRes = floor( dVal + 0.5 );
2419 }
2420 else
2421 {
2422 double dFactor = pow( 10.0, numdecimalplaces );
2423 dVal *= dFactor;
2424 dRes = floor( dVal + 0.5 );
2425 dRes /= dFactor;
2426 }
2427
2428 if( bNeg )
2429 dRes = -dRes;
2430 }
2431 rPar.Get32(0)->PutDouble( dRes );
2432}
2433
2434static void CallFunctionAccessFunction( const Sequence< Any >& aArgs, const OUString& sFuncName, SbxVariable* pRet )
2435{
2436 static Reference< XFunctionAccess > xFunc;
2437 try
2438 {
2439 if ( !xFunc.is() )
2440 {
2441 Reference< XMultiServiceFactory > xFactory( getProcessServiceFactory() );
2442 if( xFactory.is() )
2443 {
2444 xFunc.set( xFactory->createInstance("com.sun.star.sheet.FunctionAccess"), UNO_QUERY_THROW);
2445 }
2446 }
2447 Any aRet = xFunc->callFunction( sFuncName, aArgs );
2448
2449 unoToSbxValue( pRet, aRet );
2450
2451 }
2452 catch(const Exception& )
2453 {
2454 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2455 }
2456}
2457
2458void SbRtl_SYD(StarBASIC *, SbxArray & rPar, bool)
2459{
2460 sal_uInt32 nArgCount = rPar.Count32()-1;
2461
2462 if ( nArgCount < 4 )
2463 {
2464 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2465 return;
2466 }
2467
2468 // retrieve non-optional params
2469
2470 Sequence< Any > aParams( 4 );
2471 aParams[ 0 ] <<= rPar.Get32(1)->GetDouble();
2472 aParams[ 1 ] <<= rPar.Get32(2)->GetDouble();
2473 aParams[ 2 ] <<= rPar.Get32(3)->GetDouble();
2474 aParams[ 3 ] <<= rPar.Get32(4)->GetDouble();
2475
2476 CallFunctionAccessFunction( aParams, "SYD", rPar.Get32( 0 ) );
2477}
2478
2479void SbRtl_SLN(StarBASIC *, SbxArray & rPar, bool)
2480{
2481 sal_uInt32 nArgCount = rPar.Count32()-1;
2482
2483 if ( nArgCount < 3 )
2484 {
2485 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2486 return;
2487 }
2488
2489 // retrieve non-optional params
2490
2491 Sequence< Any > aParams( 3 );
2492 aParams[ 0 ] <<= rPar.Get32(1)->GetDouble();
2493 aParams[ 1 ] <<= rPar.Get32(2)->GetDouble();
2494 aParams[ 2 ] <<= rPar.Get32(3)->GetDouble();
2495
2496 CallFunctionAccessFunction( aParams, "SLN", rPar.Get32( 0 ) );
2497}
2498
2499void SbRtl_Pmt(StarBASIC *, SbxArray & rPar, bool)
2500{
2501 sal_uInt32 nArgCount = rPar.Count32()-1;
2502
2503 if ( nArgCount < 3 || nArgCount > 5 )
2504 {
2505 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2506 return;
2507 }
2508 // retrieve non-optional params
2509
2510 double rate = rPar.Get32(1)->GetDouble();
2511 double nper = rPar.Get32(2)->GetDouble();
2512 double pmt = rPar.Get32(3)->GetDouble();
2513
2514 // set default values for Optional args
2515 double fv = 0;
2516 double type = 0;
2517
2518 // fv
2519 if ( nArgCount >= 4 )
2520 {
2521 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2522 fv = rPar.Get32(4)->GetDouble();
2523 }
2524 // type
2525 if ( nArgCount >= 5 )
2526 {
2527 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2528 type = rPar.Get32(5)->GetDouble();
2529 }
2530
2531 Sequence< Any > aParams( 5 );
2532 aParams[ 0 ] <<= rate;
2533 aParams[ 1 ] <<= nper;
2534 aParams[ 2 ] <<= pmt;
2535 aParams[ 3 ] <<= fv;
2536 aParams[ 4 ] <<= type;
2537
2538 CallFunctionAccessFunction( aParams, "Pmt", rPar.Get32( 0 ) );
2539}
2540
2541void SbRtl_PPmt(StarBASIC *, SbxArray & rPar, bool)
2542{
2543 sal_uInt32 nArgCount = rPar.Count32()-1;
2544
2545 if ( nArgCount < 4 || nArgCount > 6 )
2546 {
2547 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2548 return;
2549 }
2550 // retrieve non-optional params
2551
2552 double rate = rPar.Get32(1)->GetDouble();
2553 double per = rPar.Get32(2)->GetDouble();
2554 double nper = rPar.Get32(3)->GetDouble();
2555 double pv = rPar.Get32(4)->GetDouble();
2556
2557 // set default values for Optional args
2558 double fv = 0;
2559 double type = 0;
2560
2561 // fv
2562 if ( nArgCount >= 5 )
2563 {
2564 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2565 fv = rPar.Get32(5)->GetDouble();
2566 }
2567 // type
2568 if ( nArgCount >= 6 )
2569 {
2570 if( rPar.Get32(6)->GetType() != SbxEMPTY )
2571 type = rPar.Get32(6)->GetDouble();
2572 }
2573
2574 Sequence< Any > aParams( 6 );
2575 aParams[ 0 ] <<= rate;
2576 aParams[ 1 ] <<= per;
2577 aParams[ 2 ] <<= nper;
2578 aParams[ 3 ] <<= pv;
2579 aParams[ 4 ] <<= fv;
2580 aParams[ 5 ] <<= type;
2581
2582 CallFunctionAccessFunction( aParams, "PPmt", rPar.Get32( 0 ) );
2583}
2584
2585void SbRtl_PV(StarBASIC *, SbxArray & rPar, bool)
2586{
2587 sal_uInt32 nArgCount = rPar.Count32()-1;
2588
2589 if ( nArgCount < 3 || nArgCount > 5 )
2590 {
2591 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2592 return;
2593 }
2594 // retrieve non-optional params
2595
2596 double rate = rPar.Get32(1)->GetDouble();
2597 double nper = rPar.Get32(2)->GetDouble();
2598 double pmt = rPar.Get32(3)->GetDouble();
2599
2600 // set default values for Optional args
2601 double fv = 0;
2602 double type = 0;
2603
2604 // fv
2605 if ( nArgCount >= 4 )
2606 {
2607 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2608 fv = rPar.Get32(4)->GetDouble();
2609 }
2610 // type
2611 if ( nArgCount >= 5 )
2612 {
2613 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2614 type = rPar.Get32(5)->GetDouble();
2615 }
2616
2617 Sequence< Any > aParams( 5 );
2618 aParams[ 0 ] <<= rate;
2619 aParams[ 1 ] <<= nper;
2620 aParams[ 2 ] <<= pmt;
2621 aParams[ 3 ] <<= fv;
2622 aParams[ 4 ] <<= type;
2623
2624 CallFunctionAccessFunction( aParams, "PV", rPar.Get32( 0 ) );
2625}
2626
2627void SbRtl_NPV(StarBASIC *, SbxArray & rPar, bool)
2628{
2629 sal_uInt32 nArgCount = rPar.Count32()-1;
2630
2631 if ( nArgCount < 1 || nArgCount > 2 )
2632 {
2633 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2634 return;
2635 }
2636
2637 Sequence< Any > aParams( 2 );
2638 aParams[ 0 ] <<= rPar.Get32(1)->GetDouble();
2639 Any aValues = sbxToUnoValue( rPar.Get32(2),
2640 cppu::UnoType<Sequence<double>>::get() );
2641
2642 // convert for calc functions
2643 Sequence< Sequence< double > > sValues(1);
2644 aValues >>= sValues[ 0 ];
2645 aValues <<= sValues;
2646
2647 aParams[ 1 ] = aValues;
2648
2649 CallFunctionAccessFunction( aParams, "NPV", rPar.Get32( 0 ) );
2650}
2651
2652void SbRtl_NPer(StarBASIC *, SbxArray & rPar, bool)
2653{
2654 sal_uInt32 nArgCount = rPar.Count32()-1;
2655
2656 if ( nArgCount < 3 || nArgCount > 5 )
2657 {
2658 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2659 return;
2660 }
2661 // retrieve non-optional params
2662
2663 double rate = rPar.Get32(1)->GetDouble();
2664 double pmt = rPar.Get32(2)->GetDouble();
2665 double pv = rPar.Get32(3)->GetDouble();
2666
2667 // set default values for Optional args
2668 double fv = 0;
2669 double type = 0;
2670
2671 // fv
2672 if ( nArgCount >= 4 )
2673 {
2674 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2675 fv = rPar.Get32(4)->GetDouble();
2676 }
2677 // type
2678 if ( nArgCount >= 5 )
2679 {
2680 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2681 type = rPar.Get32(5)->GetDouble();
2682 }
2683
2684 Sequence< Any > aParams( 5 );
2685 aParams[ 0 ] <<= rate;
2686 aParams[ 1 ] <<= pmt;
2687 aParams[ 2 ] <<= pv;
2688 aParams[ 3 ] <<= fv;
2689 aParams[ 4 ] <<= type;
2690
2691 CallFunctionAccessFunction( aParams, "NPer", rPar.Get32( 0 ) );
2692}
2693
2694void SbRtl_MIRR(StarBASIC *, SbxArray & rPar, bool)
2695{
2696 sal_uInt32 nArgCount = rPar.Count32()-1;
2697
2698 if ( nArgCount < 3 )
2699 {
2700 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2701 return;
2702 }
2703
2704 // retrieve non-optional params
2705
2706 Sequence< Any > aParams( 3 );
2707 Any aValues = sbxToUnoValue( rPar.Get32(1),
2708 cppu::UnoType<Sequence<double>>::get() );
2709
2710 // convert for calc functions
2711 Sequence< Sequence< double > > sValues(1);
2712 aValues >>= sValues[ 0 ];
2713 aValues <<= sValues;
2714
2715 aParams[ 0 ] = aValues;
2716 aParams[ 1 ] <<= rPar.Get32(2)->GetDouble();
2717 aParams[ 2 ] <<= rPar.Get32(3)->GetDouble();
2718
2719 CallFunctionAccessFunction( aParams, "MIRR", rPar.Get32( 0 ) );
2720}
2721
2722void SbRtl_IRR(StarBASIC *, SbxArray & rPar, bool)
2723{
2724 sal_uInt32 nArgCount = rPar.Count32()-1;
2725
2726 if ( nArgCount < 1 || nArgCount > 2 )
2727 {
2728 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2729 return;
2730 }
2731 // retrieve non-optional params
2732 Any aValues = sbxToUnoValue( rPar.Get32(1),
2733 cppu::UnoType<Sequence<double>>::get() );
2734
2735 // convert for calc functions
2736 Sequence< Sequence< double > > sValues(1);
2737 aValues >>= sValues[ 0 ];
2738 aValues <<= sValues;
2739
2740 // set default values for Optional args
2741 double guess = 0.1;
2742 // guess
2743 if ( nArgCount >= 2 )
2744 {
2745 if( rPar.Get32(2)->GetType() != SbxEMPTY )
2746 guess = rPar.Get32(2)->GetDouble();
2747 }
2748
2749 Sequence< Any > aParams( 2 );
2750 aParams[ 0 ] = aValues;
2751 aParams[ 1 ] <<= guess;
2752
2753 CallFunctionAccessFunction( aParams, "IRR", rPar.Get32( 0 ) );
2754}
2755
2756void SbRtl_IPmt(StarBASIC *, SbxArray & rPar, bool)
2757{
2758 sal_uInt32 nArgCount = rPar.Count32()-1;
2759
2760 if ( nArgCount < 4 || nArgCount > 6 )
2761 {
2762 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2763 return;
2764 }
2765 // retrieve non-optional params
2766
2767 double rate = rPar.Get32(1)->GetDouble();
2768 double per = rPar.Get32(2)->GetInteger();
2769 double nper = rPar.Get32(3)->GetDouble();
2770 double pv = rPar.Get32(4)->GetDouble();
2771
2772 // set default values for Optional args
2773 double fv = 0;
2774 double type = 0;
2775
2776 // fv
2777 if ( nArgCount >= 5 )
2778 {
2779 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2780 fv = rPar.Get32(5)->GetDouble();
2781 }
2782 // type
2783 if ( nArgCount >= 6 )
2784 {
2785 if( rPar.Get32(6)->GetType() != SbxEMPTY )
2786 type = rPar.Get32(6)->GetDouble();
2787 }
2788
2789 Sequence< Any > aParams( 6 );
2790 aParams[ 0 ] <<= rate;
2791 aParams[ 1 ] <<= per;
2792 aParams[ 2 ] <<= nper;
2793 aParams[ 3 ] <<= pv;
2794 aParams[ 4 ] <<= fv;
2795 aParams[ 5 ] <<= type;
2796
2797 CallFunctionAccessFunction( aParams, "IPmt", rPar.Get32( 0 ) );
2798}
2799
2800void SbRtl_FV(StarBASIC *, SbxArray & rPar, bool)
2801{
2802 sal_uInt32 nArgCount = rPar.Count32()-1;
2803
2804 if ( nArgCount < 3 || nArgCount > 5 )
2805 {
2806 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2807 return;
2808 }
2809 // retrieve non-optional params
2810
2811 double rate = rPar.Get32(1)->GetDouble();
2812 double nper = rPar.Get32(2)->GetDouble();
2813 double pmt = rPar.Get32(3)->GetDouble();
2814
2815 // set default values for Optional args
2816 double pv = 0;
2817 double type = 0;
2818
2819 // pv
2820 if ( nArgCount >= 4 )
2821 {
2822 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2823 pv = rPar.Get32(4)->GetDouble();
2824 }
2825 // type
2826 if ( nArgCount >= 5 )
2827 {
2828 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2829 type = rPar.Get32(5)->GetDouble();
2830 }
2831
2832 Sequence< Any > aParams( 5 );
2833 aParams[ 0 ] <<= rate;
2834 aParams[ 1 ] <<= nper;
2835 aParams[ 2 ] <<= pmt;
2836 aParams[ 3 ] <<= pv;
2837 aParams[ 4 ] <<= type;
2838
2839 CallFunctionAccessFunction( aParams, "FV", rPar.Get32( 0 ) );
2840}
2841
2842void SbRtl_DDB(StarBASIC *, SbxArray & rPar, bool)
2843{
2844 sal_uInt32 nArgCount = rPar.Count32()-1;
2845
2846 if ( nArgCount < 4 || nArgCount > 5 )
2847 {
2848 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2849 return;
2850 }
2851 // retrieve non-optional params
2852
2853 double cost = rPar.Get32(1)->GetDouble();
2854 double salvage = rPar.Get32(2)->GetDouble();
2855 double life = rPar.Get32(3)->GetDouble();
2856 double period = rPar.Get32(4)->GetDouble();
2857
2858 // set default values for Optional args
2859 double factor = 2;
2860
2861 // factor
2862 if ( nArgCount >= 5 )
2863 {
2864 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2865 factor = rPar.Get32(5)->GetDouble();
2866 }
2867
2868 Sequence< Any > aParams( 5 );
2869 aParams[ 0 ] <<= cost;
2870 aParams[ 1 ] <<= salvage;
2871 aParams[ 2 ] <<= life;
2872 aParams[ 3 ] <<= period;
2873 aParams[ 4 ] <<= factor;
2874
2875 CallFunctionAccessFunction( aParams, "DDB", rPar.Get32( 0 ) );
2876}
2877
2878void SbRtl_Rate(StarBASIC *, SbxArray & rPar, bool)
2879{
2880 sal_uInt32 nArgCount = rPar.Count32()-1;
2881
2882 if ( nArgCount < 3 || nArgCount > 6 )
2883 {
2884 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2885 return;
2886 }
2887 // retrieve non-optional params
2888
2889 double nper = 0;
2890 double pmt = 0;
2891 double pv = 0;
2892
2893 nper = rPar.Get32(1)->GetDouble();
2894 pmt = rPar.Get32(2)->GetDouble();
2895 pv = rPar.Get32(3)->GetDouble();
2896
2897 // set default values for Optional args
2898 double fv = 0;
2899 double type = 0;
2900 double guess = 0.1;
2901
2902 // fv
2903 if ( nArgCount >= 4 )
2904 {
2905 if( rPar.Get32(4)->GetType() != SbxEMPTY )
2906 fv = rPar.Get32(4)->GetDouble();
2907 }
2908
2909 // type
2910 if ( nArgCount >= 5 )
2911 {
2912 if( rPar.Get32(5)->GetType() != SbxEMPTY )
2913 type = rPar.Get32(5)->GetDouble();
2914 }
2915
2916 // guess
2917 if ( nArgCount >= 6 )
2918 {
2919 if( rPar.Get32(6)->GetType() != SbxEMPTY )
2920 guess = rPar.Get32(6)->GetDouble();
2921 }
2922
2923 Sequence< Any > aParams( 6 );
2924 aParams[ 0 ] <<= nper;
2925 aParams[ 1 ] <<= pmt;
2926 aParams[ 2 ] <<= pv;
2927 aParams[ 3 ] <<= fv;
2928 aParams[ 4 ] <<= type;
2929 aParams[ 5 ] <<= guess;
2930
2931 CallFunctionAccessFunction( aParams, "Rate", rPar.Get32( 0 ) );
2932}
2933
2934void SbRtl_StrReverse(StarBASIC *, SbxArray & rPar, bool)
2935{
2936 if ( rPar.Count32() != 2 )
2937 {
2938 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2939 return;
2940 }
2941
2942 SbxVariable *pSbxVariable = rPar.Get32(1);
2943 if( pSbxVariable->IsNull() )
2944 {
2945 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2946 return;
2947 }
2948
2949 OUString aStr = comphelper::string::reverseString(pSbxVariable->GetOUString());
2950 rPar.Get32(0)->PutString( aStr );
2951}
2952
2953void SbRtl_CompatibilityMode(StarBASIC *, SbxArray & rPar, bool)
2954{
2955 bool bEnabled = false;
2956 sal_uInt32 nCount = rPar.Count32();
2957 if ( nCount != 1 && nCount != 2 )
2958 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2959
2960 SbiInstance* pInst = GetSbData()->pInst;
2961 if( pInst )
2962 {
2963 if ( nCount == 2 )
2964 {
2965 pInst->EnableCompatibility( rPar.Get32(1)->GetBool() );
2966 }
2967 bEnabled = pInst->IsCompatibility();
2968 }
2969 rPar.Get32(0)->PutBool( bEnabled );
2970}
2971
2972void SbRtl_Input(StarBASIC *, SbxArray & rPar, bool)
2973{
2974 // 2 parameters needed
2975 if ( rPar.Count32() < 3 )
2976 {
2977 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
2978 return;
2979 }
2980
2981 sal_uInt16 nByteCount = rPar.Get32(1)->GetUShort();
2982 sal_Int16 nFileNumber = rPar.Get32(2)->GetInteger();
2983
2984 SbiIoSystem* pIosys = GetSbData()->pInst->GetIoSystem();
2985 SbiStream* pSbStrm = pIosys->GetStream( nFileNumber );
2986 if ( !pSbStrm || !(pSbStrm->GetMode() & (SbiStreamFlags::Binary | SbiStreamFlags::Input)) )
2987 {
2988 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNELErrCode( ErrCodeArea::Sbx, ErrCodeClass::Runtime, 41 ) );
2989 return;
2990 }
2991
2992 OString aByteBuffer;
2993 ErrCode err = pSbStrm->Read( aByteBuffer, nByteCount, true );
2994 if( !err )
2995 err = pIosys->GetError();
2996
2997 if( err )
2998 {
2999 StarBASIC::Error( err );
3000 return;
3001 }
3002 rPar.Get32(0)->PutString(OStringToOUString(aByteBuffer, osl_getThreadTextEncoding()));
3003}
3004
3005void SbRtl_Me(StarBASIC *, SbxArray & rPar, bool)
3006{
3007 SbModule* pActiveModule = GetSbData()->pInst->GetActiveModule();
3008 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pActiveModule );
3009 SbxVariableRef refVar = rPar.Get32(0);
3010 if( pClassModuleObject == nullptr )
3011 {
3012 SbObjModule* pMod = dynamic_cast<SbObjModule*>( pActiveModule );
3013 if ( pMod )
3014 refVar->PutObject( pMod );
3015 else
3016 StarBASIC::Error( ERRCODE_BASIC_INVALID_USAGE_OBJECTErrCode( ErrCodeArea::Sbx, ErrCodeClass::Access, 19) );
3017 }
3018 else
3019 refVar->PutObject( pClassModuleObject );
3020}
3021
3022#endif
3023
3024sal_Int16 implGetWeekDay( double aDate, bool bFirstDayParam, sal_Int16 nFirstDay )
3025{
3026 Date aRefDate( 1,1,1900 );
3027 sal_Int32 nDays = static_cast<sal_Int32>(aDate);
3028 nDays -= 2; // normalize: 1.1.1900 => 0
3029 aRefDate.AddDays( nDays);
3030 DayOfWeek aDay = aRefDate.GetDayOfWeek();
3031 sal_Int16 nDay;
3032 if ( aDay != SUNDAY )
3033 nDay = static_cast<sal_Int16>(aDay) + 2;
3034 else
3035 nDay = 1; // 1 == Sunday
3036
3037 // #117253 optional 2nd parameter "firstdayofweek"
3038 if( bFirstDayParam )
3039 {
3040 if( nFirstDay < 0 || nFirstDay > 7 )
3041 {
3042#if HAVE_FEATURE_SCRIPTING1
3043 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENTErrCode( ErrCodeArea::Sbx, ErrCodeClass::NotSupported, 2) );
3044#endif
3045 return 0;
3046 }
3047 if( nFirstDay == 0 )
3048 {
3049 const Reference< XCalendar4 >& xCalendar = getLocaleCalendar();
3050 if( !xCalendar.is() )
3051 {
3052#if HAVE_FEATURE_SCRIPTING1
3053 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERRORErrCode( ErrCodeArea::Sbx, ErrCodeClass::Unknown, 9) );
3054#endif
3055 return 0;
3056 }
3057 nFirstDay = sal_Int16( xCalendar->getFirstDayOfWeek() + 1 );
3058 }
3059 nDay = 1 + (nDay + 7 - nFirstDay) % 7;
3060 }
3061 return nDay;
3062}
3063
3064/* vim:set shiftwidth=4 softtabstop=4 expandtab: */