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