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