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