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 <tools/date.hxx> 23 #include <basic/sbxvar.hxx> 24 #include <basic/sbuno.hxx> 25 #include <osl/process.h> 26 #include <vcl/dibtools.hxx> 27 #include <vcl/svapp.hxx> 28 #include <vcl/settings.hxx> 29 #include <vcl/sound.hxx> 30 #include <tools/wintypes.hxx> 31 #include <vcl/button.hxx> 32 #include <vcl/weld.hxx> 33 #include <basic/sbx.hxx> 34 #include <svl/zforlist.hxx> 35 #include <rtl/character.hxx> 36 #include <rtl/math.hxx> 37 #include <tools/urlobj.hxx> 38 #include <osl/time.h> 39 #include <unotools/charclass.hxx> 40 #include <unotools/ucbstreamhelper.hxx> 41 #include <tools/wldcrd.hxx> 42 #include <i18nlangtag/lang.h> 43 #include <rtl/string.hxx> 44 #include <rtl/strbuf.hxx> 45 46 #include <runtime.hxx> 47 #include <sbunoobj.hxx> 48 #include <osl/file.hxx> 49 #include <errobject.hxx> 50 51 #include <comphelper/processfactory.hxx> 52 #include <comphelper/string.hxx> 53 54 #include <com/sun/star/uno/Sequence.hxx> 55 #include <com/sun/star/util/DateTime.hpp> 56 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 57 #include <com/sun/star/lang/Locale.hpp> 58 #include <com/sun/star/lang/XServiceInfo.hpp> 59 #include <com/sun/star/ucb/SimpleFileAccess.hpp> 60 #include <com/sun/star/script/XErrorQuery.hpp> 61 #include <ooo/vba/XHelperInterface.hpp> 62 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp> 63 #include <memory> 64 #include <random> 65 #include <o3tl/make_unique.hxx> 66 #include <o3tl/char16_t2wchar_t.hxx> 67 68 using namespace comphelper; 69 using namespace osl; 70 using namespace com::sun::star; 71 using namespace com::sun::star::lang; 72 using namespace com::sun::star::uno; 73 74 #include <date.hxx> 75 #include <stdobj.hxx> 76 #include <sbstdobj.hxx> 77 #include <rtlproto.hxx> 78 #include <image.hxx> 79 #include <iosys.hxx> 80 #include "ddectrl.hxx" 81 #include <sbintern.hxx> 82 #include <basic/vbahelper.hxx> 83 84 #include <vector> 85 #include <math.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <errno.h> 89 90 #include <sbobjmod.hxx> 91 #include <sbxmod.hxx> 92 93 #ifdef _WIN32 94 #include <prewin.h> 95 #include <direct.h> 96 #include <io.h> 97 #include <postwin.h> 98 #else 99 #include <unistd.h> 100 #endif 101 102 #if HAVE_FEATURE_SCRIPTING 103 104 static void FilterWhiteSpace( OUString& rStr ) 105 { 106 if (rStr.isEmpty()) 107 { 108 return; 109 } 110 OUStringBuffer aRet; 111 112 for (sal_Int32 i = 0; i < rStr.getLength(); ++i) 113 { 114 sal_Unicode cChar = rStr[i]; 115 if ((cChar != ' ') && (cChar != '\t') && 116 (cChar != '\n') && (cChar != '\r')) 117 { 118 aRet.append(cChar); 119 } 120 } 121 122 rStr = aRet.makeStringAndClear(); 123 } 124 125 static long GetDayDiff( const Date& rDate ); 126 127 static const CharClass& GetCharClass() 128 { 129 static bool bNeedsInit = true; 130 static LanguageTag aLanguageTag( LANGUAGE_SYSTEM); 131 if( bNeedsInit ) 132 { 133 bNeedsInit = false; 134 aLanguageTag = Application::GetSettings().GetLanguageTag(); 135 } 136 static CharClass aCharClass( aLanguageTag ); 137 return aCharClass; 138 } 139 140 static inline bool isFolder( FileStatus::Type aType ) 141 { 142 return ( aType == FileStatus::Directory || aType == FileStatus::Volume ); 143 } 144 145 146 //*** UCB file access *** 147 148 // Converts possibly relative paths to absolute paths 149 // according to the setting done by ChDir/ChDrive 150 OUString getFullPath( const OUString& aRelPath ) 151 { 152 OUString aFileURL; 153 154 // #80204 Try first if it already is a valid URL 155 INetURLObject aURLObj( aRelPath ); 156 aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 157 158 if( aFileURL.isEmpty() ) 159 { 160 File::getFileURLFromSystemPath( aRelPath, aFileURL ); 161 } 162 163 return aFileURL; 164 } 165 166 // TODO: -> SbiGlobals 167 static uno::Reference< ucb::XSimpleFileAccess3 > const & getFileAccess() 168 { 169 static uno::Reference< ucb::XSimpleFileAccess3 > xSFI; 170 if( !xSFI.is() ) 171 { 172 xSFI = ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ); 173 } 174 return xSFI; 175 } 176 177 178 // Properties and methods lie down the return value at the Get (bPut = sal_False) in the 179 // element 0 of the Argv; the value of element 0 is saved at Put (bPut = sal_True) 180 181 // CreateObject( class ) 182 183 void SbRtl_CreateObject(StarBASIC * pBasic, SbxArray & rPar, bool) 184 { 185 OUString aClass( rPar.Get( 1 )->GetOUString() ); 186 SbxObjectRef p = SbxBase::CreateObject( aClass ); 187 if( !p.is() ) 188 StarBASIC::Error( ERRCODE_BASIC_CANNOT_LOAD ); 189 else 190 { 191 // Convenience: enter BASIC as parent 192 p->SetParent( pBasic ); 193 rPar.Get( 0 )->PutObject( p.get() ); 194 } 195 } 196 197 // Error( n ) 198 199 void SbRtl_Error(StarBASIC * pBasic, SbxArray & rPar, bool) 200 { 201 if( !pBasic ) 202 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR ); 203 else 204 { 205 OUString aErrorMsg; 206 ErrCode nErr = ERRCODE_NONE; 207 sal_Int32 nCode = 0; 208 if( rPar.Count() == 1 ) 209 { 210 nErr = StarBASIC::GetErrBasic(); 211 aErrorMsg = StarBASIC::GetErrorMsg(); 212 } 213 else 214 { 215 nCode = rPar.Get( 1 )->GetLong(); 216 if( nCode > 65535 ) 217 { 218 StarBASIC::Error( ERRCODE_BASIC_CONVERSION ); 219 } 220 else 221 { 222 nErr = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(nCode) ); 223 } 224 } 225 226 bool bVBA = SbiRuntime::isVBAEnabled(); 227 OUString tmpErrMsg; 228 if( bVBA && !aErrorMsg.isEmpty()) 229 { 230 tmpErrMsg = aErrorMsg; 231 } 232 else 233 { 234 StarBASIC::MakeErrorText( nErr, aErrorMsg ); 235 tmpErrMsg = StarBASIC::GetErrorText(); 236 } 237 // If this rtlfunc 'Error' passed a errcode the same as the active Err Objects's 238 // current err then return the description for the error message if it is set 239 // ( complicated isn't it ? ) 240 if ( bVBA && rPar.Count() > 1 ) 241 { 242 uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() ); 243 if ( xErrObj.is() && xErrObj->getNumber() == nCode && !xErrObj->getDescription().isEmpty() ) 244 { 245 tmpErrMsg = xErrObj->getDescription(); 246 } 247 } 248 rPar.Get( 0 )->PutString( tmpErrMsg ); 249 } 250 } 251 252 // Sinus 253 254 void SbRtl_Sin(StarBASIC *, SbxArray & rPar, bool) 255 { 256 if ( rPar.Count() < 2 ) 257 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 258 else 259 { 260 SbxVariableRef pArg = rPar.Get( 1 ); 261 rPar.Get( 0 )->PutDouble( sin( pArg->GetDouble() ) ); 262 } 263 } 264 265 266 void SbRtl_Cos(StarBASIC *, SbxArray & rPar, bool) 267 { 268 if ( rPar.Count() < 2 ) 269 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 270 else 271 { 272 SbxVariableRef pArg = rPar.Get( 1 ); 273 rPar.Get( 0 )->PutDouble( cos( pArg->GetDouble() ) ); 274 } 275 } 276 277 278 void SbRtl_Atn(StarBASIC *, SbxArray & rPar, bool) 279 { 280 if ( rPar.Count() < 2 ) 281 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 282 else 283 { 284 SbxVariableRef pArg = rPar.Get( 1 ); 285 rPar.Get( 0 )->PutDouble( atan( pArg->GetDouble() ) ); 286 } 287 } 288 289 290 void SbRtl_Abs(StarBASIC *, SbxArray & rPar, bool) 291 { 292 if ( rPar.Count() < 2 ) 293 { 294 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 295 } 296 else 297 { 298 SbxVariableRef pArg = rPar.Get( 1 ); 299 rPar.Get( 0 )->PutDouble( fabs( pArg->GetDouble() ) ); 300 } 301 } 302 303 304 void SbRtl_Asc(StarBASIC *, SbxArray & rPar, bool) 305 { 306 if ( rPar.Count() < 2 ) 307 { 308 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 309 } 310 else 311 { 312 SbxVariableRef pArg = rPar.Get( 1 ); 313 OUString aStr( pArg->GetOUString() ); 314 if ( aStr.isEmpty()) 315 { 316 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 317 rPar.Get(0)->PutEmpty(); 318 } 319 else 320 { 321 sal_Unicode aCh = aStr[0]; 322 rPar.Get(0)->PutLong( aCh ); 323 } 324 } 325 } 326 327 void implChr( SbxArray& rPar, bool bChrW ) 328 { 329 if ( rPar.Count() < 2 ) 330 { 331 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 332 } 333 else 334 { 335 SbxVariableRef pArg = rPar.Get( 1 ); 336 337 OUString aStr; 338 if( !bChrW && SbiRuntime::isVBAEnabled() ) 339 { 340 sal_Char c = static_cast<sal_Char>(pArg->GetByte()); 341 aStr = OUString(&c, 1, osl_getThreadTextEncoding()); 342 } 343 else 344 { 345 sal_Unicode aCh = static_cast<sal_Unicode>(pArg->GetUShort()); 346 aStr = OUString(aCh); 347 } 348 rPar.Get(0)->PutString( aStr ); 349 } 350 } 351 352 void SbRtl_Chr(StarBASIC *, SbxArray & rPar, bool) 353 { 354 implChr( rPar, false/*bChrW*/ ); 355 } 356 357 void SbRtl_ChrW(StarBASIC *, SbxArray & rPar, bool) 358 { 359 implChr( rPar, true/*bChrW*/ ); 360 } 361 362 void SbRtl_CurDir(StarBASIC * pBasic, SbxArray & rPar, bool bWrite) 363 { 364 (void)pBasic; 365 (void)bWrite; 366 367 // #57064 Although this function doesn't work with DirEntry, it isn't touched 368 // by the adjustment to virtual URLs, as, using the DirEntry-functionality, 369 // there's no possibility to detect the current one in a way that a virtual URL 370 // could be delivered. 371 372 #if defined(_WIN32) 373 int nCurDir = 0; // Current dir // JSM 374 if ( rPar.Count() == 2 ) 375 { 376 OUString aDrive = rPar.Get(1)->GetOUString(); 377 if ( aDrive.getLength() != 1 ) 378 { 379 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 380 return; 381 } 382 auto c = rtl::toAsciiUpperCase(aDrive[0]); 383 if ( !rtl::isAsciiUpperCase( c ) ) 384 { 385 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 386 return; 387 } 388 nCurDir = c - 'A' + 1; 389 } 390 wchar_t pBuffer[ _MAX_PATH ]; 391 if ( _wgetdcwd( nCurDir, pBuffer, _MAX_PATH ) != nullptr ) 392 { 393 rPar.Get(0)->PutString( o3tl::toU(pBuffer) ); 394 } 395 else 396 { 397 StarBASIC::Error( ERRCODE_BASIC_NO_DEVICE ); 398 } 399 400 #else 401 402 const int PATH_INCR = 250; 403 404 int nSize = PATH_INCR; 405 std::unique_ptr<char[]> pMem; 406 while( true ) 407 { 408 pMem.reset(new char[nSize]); 409 if( !pMem ) 410 { 411 StarBASIC::Error( ERRCODE_BASIC_NO_MEMORY ); 412 return; 413 } 414 if( getcwd( pMem.get(), nSize-1 ) != nullptr ) 415 { 416 rPar.Get(0)->PutString( OUString::createFromAscii(pMem.get()) ); 417 return; 418 } 419 if( errno != ERANGE ) 420 { 421 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR ); 422 return; 423 } 424 nSize += PATH_INCR; 425 }; 426 427 #endif 428 } 429 430 void SbRtl_ChDir(StarBASIC * pBasic, SbxArray & rPar, bool) 431 { 432 rPar.Get(0)->PutEmpty(); 433 if (rPar.Count() == 2) 434 { 435 // VBA: track current directory per document type (separately for Writer, Calc, Impress, etc.) 436 if( SbiRuntime::isVBAEnabled() ) 437 { 438 ::basic::vba::registerCurrentDirectory( getDocumentModel( pBasic ), rPar.Get(1)->GetOUString() ); 439 } 440 } 441 else 442 { 443 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 444 } 445 } 446 447 void SbRtl_ChDrive(StarBASIC *, SbxArray & rPar, bool) 448 { 449 rPar.Get(0)->PutEmpty(); 450 if (rPar.Count() != 2) 451 { 452 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 453 } 454 } 455 456 457 // Implementation of StepRENAME with UCB 458 void implStepRenameUCB( const OUString& aSource, const OUString& aDest ) 459 { 460 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 461 if( xSFI.is() ) 462 { 463 try 464 { 465 OUString aSourceFullPath = getFullPath( aSource ); 466 if( !xSFI->exists( aSourceFullPath ) ) 467 { 468 StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND ); 469 return; 470 } 471 472 OUString aDestFullPath = getFullPath( aDest ); 473 if( xSFI->exists( aDestFullPath ) ) 474 { 475 StarBASIC::Error( ERRCODE_BASIC_FILE_EXISTS ); 476 } 477 else 478 { 479 xSFI->move( aSourceFullPath, aDestFullPath ); 480 } 481 } 482 catch(const Exception & ) 483 { 484 StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND ); 485 } 486 } 487 } 488 489 // Implementation of StepRENAME with OSL 490 void implStepRenameOSL( const OUString& aSource, const OUString& aDest ) 491 { 492 FileBase::RC nRet = File::move( getFullPath( aSource ), getFullPath( aDest ) ); 493 if( nRet != FileBase::E_None ) 494 { 495 StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND ); 496 } 497 } 498 499 void SbRtl_FileCopy(StarBASIC *, SbxArray & rPar, bool) 500 { 501 rPar.Get(0)->PutEmpty(); 502 if (rPar.Count() == 3) 503 { 504 OUString aSource = rPar.Get(1)->GetOUString(); 505 OUString aDest = rPar.Get(2)->GetOUString(); 506 if( hasUno() ) 507 { 508 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 509 if( xSFI.is() ) 510 { 511 try 512 { 513 xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) ); 514 } 515 catch(const Exception & ) 516 { 517 StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND ); 518 } 519 } 520 } 521 else 522 { 523 FileBase::RC nRet = File::copy( getFullPath( aSource ), getFullPath( aDest ) ); 524 if( nRet != FileBase::E_None ) 525 { 526 StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND ); 527 } 528 } 529 } 530 else 531 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 532 } 533 534 void SbRtl_Kill(StarBASIC *, SbxArray & rPar, bool) 535 { 536 rPar.Get(0)->PutEmpty(); 537 if (rPar.Count() == 2) 538 { 539 OUString aFileSpec = rPar.Get(1)->GetOUString(); 540 541 if( hasUno() ) 542 { 543 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 544 if( xSFI.is() ) 545 { 546 OUString aFullPath = getFullPath( aFileSpec ); 547 if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) ) 548 { 549 StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND ); 550 return; 551 } 552 try 553 { 554 xSFI->kill( aFullPath ); 555 } 556 catch(const Exception & ) 557 { 558 StarBASIC::Error( ERRCODE_IO_GENERAL ); 559 } 560 } 561 } 562 else 563 { 564 File::remove( getFullPath( aFileSpec ) ); 565 } 566 } 567 else 568 { 569 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 570 } 571 } 572 573 void SbRtl_MkDir(StarBASIC * pBasic, SbxArray & rPar, bool bWrite) 574 { 575 rPar.Get(0)->PutEmpty(); 576 if (rPar.Count() == 2) 577 { 578 OUString aPath = rPar.Get(1)->GetOUString(); 579 if ( SbiRuntime::isVBAEnabled() ) 580 { 581 // In vba if the full path is not specified then 582 // folder is created relative to the curdir 583 INetURLObject aURLObj( getFullPath( aPath ) ); 584 if ( aURLObj.GetProtocol() != INetProtocol::File ) 585 { 586 SbxArrayRef pPar = new SbxArray(); 587 SbxVariableRef pResult = new SbxVariable(); 588 SbxVariableRef pParam = new SbxVariable(); 589 pPar->Insert( pResult.get(), pPar->Count() ); 590 pPar->Insert( pParam.get(), pPar->Count() ); 591 SbRtl_CurDir( pBasic, *pPar, bWrite ); 592 593 rtl::OUString sCurPathURL; 594 File::getFileURLFromSystemPath( pPar->Get(0)->GetOUString(), sCurPathURL ); 595 596 aURLObj.SetURL( sCurPathURL ); 597 aURLObj.Append( aPath ); 598 File::getSystemPathFromFileURL(aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ),aPath ) ; 599 } 600 } 601 602 if( hasUno() ) 603 { 604 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 605 if( xSFI.is() ) 606 { 607 try 608 { 609 xSFI->createFolder( getFullPath( aPath ) ); 610 } 611 catch(const Exception & ) 612 { 613 StarBASIC::Error( ERRCODE_IO_GENERAL ); 614 } 615 } 616 } 617 else 618 { 619 Directory::create( getFullPath( aPath ) ); 620 } 621 } 622 else 623 { 624 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 625 } 626 } 627 628 629 // In OSL only empty directories can be deleted 630 // so we have to delete all files recursively 631 void implRemoveDirRecursive( const OUString& aDirPath ) 632 { 633 DirectoryItem aItem; 634 FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem ); 635 bool bExists = (nRet == FileBase::E_None); 636 637 FileStatus aFileStatus( osl_FileStatus_Mask_Type ); 638 nRet = aItem.getFileStatus( aFileStatus ); 639 bool bFolder = nRet == FileBase::E_None 640 && isFolder( aFileStatus.getFileType() ); 641 642 if( !bExists || !bFolder ) 643 { 644 StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND ); 645 return; 646 } 647 648 Directory aDir( aDirPath ); 649 nRet = aDir.open(); 650 if( nRet != FileBase::E_None ) 651 { 652 StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND ); 653 return; 654 } 655 656 for( ;; ) 657 { 658 DirectoryItem aItem2; 659 nRet = aDir.getNextItem( aItem2 ); 660 if( nRet != FileBase::E_None ) 661 { 662 break; 663 } 664 // Handle flags 665 FileStatus aFileStatus2( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL ); 666 nRet = aItem2.getFileStatus( aFileStatus2 ); 667 if( nRet != FileBase::E_None ) 668 { 669 SAL_WARN("basic", "getFileStatus failed"); 670 continue; 671 } 672 OUString aPath = aFileStatus2.getFileURL(); 673 674 // Directory? 675 FileStatus::Type aType2 = aFileStatus2.getFileType(); 676 bool bFolder2 = isFolder( aType2 ); 677 if( bFolder2 ) 678 { 679 implRemoveDirRecursive( aPath ); 680 } 681 else 682 { 683 File::remove( aPath ); 684 } 685 } 686 aDir.close(); 687 688 Directory::remove( aDirPath ); 689 } 690 691 692 void SbRtl_RmDir(StarBASIC *, SbxArray & rPar, bool) 693 { 694 rPar.Get(0)->PutEmpty(); 695 if (rPar.Count() == 2) 696 { 697 OUString aPath = rPar.Get(1)->GetOUString(); 698 if( hasUno() ) 699 { 700 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 701 if( xSFI.is() ) 702 { 703 try 704 { 705 if( !xSFI->isFolder( aPath ) ) 706 { 707 StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND ); 708 return; 709 } 710 SbiInstance* pInst = GetSbData()->pInst; 711 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 712 if( bCompatibility ) 713 { 714 Sequence< OUString > aContent = xSFI->getFolderContents( aPath, true ); 715 sal_Int32 nCount = aContent.getLength(); 716 if( nCount > 0 ) 717 { 718 StarBASIC::Error( ERRCODE_BASIC_ACCESS_ERROR ); 719 return; 720 } 721 } 722 723 xSFI->kill( getFullPath( aPath ) ); 724 } 725 catch(const Exception & ) 726 { 727 StarBASIC::Error( ERRCODE_IO_GENERAL ); 728 } 729 } 730 } 731 else 732 { 733 implRemoveDirRecursive( getFullPath( aPath ) ); 734 } 735 } 736 else 737 { 738 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 739 } 740 } 741 742 void SbRtl_SendKeys(StarBASIC *, SbxArray & rPar, bool) 743 { 744 rPar.Get(0)->PutEmpty(); 745 StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTED); 746 } 747 748 void SbRtl_Exp(StarBASIC *, SbxArray & rPar, bool) 749 { 750 if( rPar.Count() < 2 ) 751 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 752 else 753 { 754 double aDouble = rPar.Get( 1 )->GetDouble(); 755 aDouble = exp( aDouble ); 756 checkArithmeticOverflow( aDouble ); 757 rPar.Get( 0 )->PutDouble( aDouble ); 758 } 759 } 760 761 void SbRtl_FileLen(StarBASIC *, SbxArray & rPar, bool) 762 { 763 if ( rPar.Count() < 2 ) 764 { 765 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 766 } 767 else 768 { 769 SbxVariableRef pArg = rPar.Get( 1 ); 770 OUString aStr( pArg->GetOUString() ); 771 sal_Int32 nLen = 0; 772 if( hasUno() ) 773 { 774 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 775 if( xSFI.is() ) 776 { 777 try 778 { 779 nLen = xSFI->getSize( getFullPath( aStr ) ); 780 } 781 catch(const Exception & ) 782 { 783 StarBASIC::Error( ERRCODE_IO_GENERAL ); 784 } 785 } 786 } 787 else 788 { 789 DirectoryItem aItem; 790 DirectoryItem::get( getFullPath( aStr ), aItem ); 791 FileStatus aFileStatus( osl_FileStatus_Mask_FileSize ); 792 aItem.getFileStatus( aFileStatus ); 793 nLen = static_cast<sal_Int32>(aFileStatus.getFileSize()); 794 } 795 rPar.Get(0)->PutLong( static_cast<long>(nLen) ); 796 } 797 } 798 799 800 void SbRtl_Hex(StarBASIC *, SbxArray & rPar, bool) 801 { 802 if ( rPar.Count() < 2 ) 803 { 804 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 805 } 806 else 807 { 808 SbxVariableRef pArg = rPar.Get( 1 ); 809 // converting value to unsigned and limit to 2 or 4 byte representation 810 sal_uInt32 nVal = pArg->IsInteger() ? 811 static_cast<sal_uInt16>(pArg->GetInteger()) : 812 static_cast<sal_uInt32>(pArg->GetLong()); 813 OUString aStr(OUString::number( nVal, 16 )); 814 aStr = aStr.toAsciiUpperCase(); 815 rPar.Get(0)->PutString( aStr ); 816 } 817 } 818 819 void SbRtl_FuncCaller(StarBASIC *, SbxArray & rPar, bool) 820 { 821 if ( SbiRuntime::isVBAEnabled() && GetSbData()->pInst && GetSbData()->pInst->pRun ) 822 { 823 if ( GetSbData()->pInst->pRun->GetExternalCaller() ) 824 *rPar.Get(0) = *GetSbData()->pInst->pRun->GetExternalCaller(); 825 else 826 { 827 SbxVariableRef pVar = new SbxVariable(SbxVARIANT); 828 *rPar.Get(0) = *pVar; 829 } 830 } 831 else 832 { 833 StarBASIC::Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); 834 } 835 836 } 837 // InStr( [start],string,string,[compare] ) 838 839 void SbRtl_InStr(StarBASIC *, SbxArray & rPar, bool) 840 { 841 std::size_t nArgCount = rPar.Count()-1; 842 if ( nArgCount < 2 ) 843 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 844 else 845 { 846 sal_Int32 nStartPos = 1; 847 sal_Int32 nFirstStringPos = 1; 848 849 if ( nArgCount >= 3 ) 850 { 851 nStartPos = rPar.Get(1)->GetLong(); 852 if( nStartPos <= 0 ) 853 { 854 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 855 nStartPos = 1; 856 } 857 nFirstStringPos++; 858 } 859 860 SbiInstance* pInst = GetSbData()->pInst; 861 bool bTextMode; 862 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 863 if( bCompatibility ) 864 { 865 SbiRuntime* pRT = pInst->pRun; 866 bTextMode = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ); 867 } 868 else 869 { 870 bTextMode = true; 871 } 872 if ( nArgCount == 4 ) 873 { 874 bTextMode = rPar.Get(4)->GetInteger(); 875 } 876 sal_Int32 nPos; 877 const OUString& rToken = rPar.Get(nFirstStringPos+1)->GetOUString(); 878 879 // #97545 Always find empty string 880 if( rToken.isEmpty() ) 881 { 882 nPos = nStartPos; 883 } 884 else 885 { 886 if( !bTextMode ) 887 { 888 const OUString& rStr1 = rPar.Get(nFirstStringPos)->GetOUString(); 889 nPos = rStr1.indexOf( rToken, nStartPos - 1 ) + 1; 890 } 891 else 892 { 893 OUString aStr1 = rPar.Get(nFirstStringPos)->GetOUString(); 894 OUString aToken = rToken; 895 896 aStr1 = aStr1.toAsciiUpperCase(); 897 aToken = aToken.toAsciiUpperCase(); 898 899 nPos = aStr1.indexOf( aToken, nStartPos-1 ) + 1; 900 } 901 } 902 rPar.Get(0)->PutLong( nPos ); 903 } 904 } 905 906 907 // InstrRev(string1, string2[, start[, compare]]) 908 909 void SbRtl_InStrRev(StarBASIC *, SbxArray & rPar, bool) 910 { 911 std::size_t nArgCount = rPar.Count()-1; 912 if ( nArgCount < 2 ) 913 { 914 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 915 } 916 else 917 { 918 OUString aStr1 = rPar.Get(1)->GetOUString(); 919 OUString aToken = rPar.Get(2)->GetOUString(); 920 921 sal_Int32 nStartPos = -1; 922 if ( nArgCount >= 3 ) 923 { 924 nStartPos = rPar.Get(3)->GetLong(); 925 if( nStartPos <= 0 && nStartPos != -1 ) 926 { 927 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 928 nStartPos = -1; 929 } 930 } 931 932 SbiInstance* pInst = GetSbData()->pInst; 933 bool bTextMode; 934 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 935 if( bCompatibility ) 936 { 937 SbiRuntime* pRT = pInst->pRun; 938 bTextMode = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ); 939 } 940 else 941 { 942 bTextMode = true; 943 } 944 if ( nArgCount == 4 ) 945 { 946 bTextMode = rPar.Get(4)->GetInteger(); 947 } 948 sal_Int32 nStrLen = aStr1.getLength(); 949 if( nStartPos == -1 ) 950 { 951 nStartPos = nStrLen; 952 } 953 954 sal_Int32 nPos = 0; 955 if( nStartPos <= nStrLen ) 956 { 957 sal_Int32 nTokenLen = aToken.getLength(); 958 if( !nTokenLen ) 959 { 960 // Always find empty string 961 nPos = nStartPos; 962 } 963 else if( nStrLen > 0 ) 964 { 965 if( !bTextMode ) 966 { 967 nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1; 968 } 969 else 970 { 971 aStr1 = aStr1.toAsciiUpperCase(); 972 aToken = aToken.toAsciiUpperCase(); 973 974 nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1; 975 } 976 } 977 } 978 rPar.Get(0)->PutLong( nPos ); 979 } 980 } 981 982 983 /* 984 Int( 2.8 ) = 2.0 985 Int( -2.8 ) = -3.0 986 Fix( 2.8 ) = 2.0 987 Fix( -2.8 ) = -2.0 <- !! 988 */ 989 990 void SbRtl_Int(StarBASIC *, SbxArray & rPar, bool) 991 { 992 if ( rPar.Count() < 2 ) 993 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 994 else 995 { 996 SbxVariableRef pArg = rPar.Get( 1 ); 997 double aDouble= pArg->GetDouble(); 998 /* 999 floor( 2.8 ) = 2.0 1000 floor( -2.8 ) = -3.0 1001 */ 1002 aDouble = floor( aDouble ); 1003 rPar.Get(0)->PutDouble( aDouble ); 1004 } 1005 } 1006 1007 1008 void SbRtl_Fix(StarBASIC *, SbxArray & rPar, bool) 1009 { 1010 if ( rPar.Count() < 2 ) 1011 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1012 else 1013 { 1014 SbxVariableRef pArg = rPar.Get( 1 ); 1015 double aDouble = pArg->GetDouble(); 1016 if ( aDouble >= 0.0 ) 1017 aDouble = floor( aDouble ); 1018 else 1019 aDouble = ceil( aDouble ); 1020 rPar.Get(0)->PutDouble( aDouble ); 1021 } 1022 } 1023 1024 1025 void SbRtl_LCase(StarBASIC *, SbxArray & rPar, bool) 1026 { 1027 if ( rPar.Count() < 2 ) 1028 { 1029 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1030 } 1031 else 1032 { 1033 const CharClass& rCharClass = GetCharClass(); 1034 OUString aStr( rPar.Get(1)->GetOUString() ); 1035 aStr = rCharClass.lowercase(aStr); 1036 rPar.Get(0)->PutString( aStr ); 1037 } 1038 } 1039 1040 void SbRtl_Left(StarBASIC *, SbxArray & rPar, bool) 1041 { 1042 if ( rPar.Count() < 3 ) 1043 { 1044 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1045 } 1046 else 1047 { 1048 OUString aStr( rPar.Get(1)->GetOUString() ); 1049 sal_Int32 nResultLen = rPar.Get(2)->GetLong(); 1050 if( nResultLen < 0 ) 1051 { 1052 nResultLen = 0; 1053 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1054 } 1055 else if(nResultLen > aStr.getLength()) 1056 { 1057 nResultLen = aStr.getLength(); 1058 } 1059 aStr = aStr.copy(0, nResultLen ); 1060 rPar.Get(0)->PutString( aStr ); 1061 } 1062 } 1063 1064 void SbRtl_Log(StarBASIC *, SbxArray & rPar, bool) 1065 { 1066 if ( rPar.Count() < 2 ) 1067 { 1068 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1069 } 1070 else 1071 { 1072 double aArg = rPar.Get(1)->GetDouble(); 1073 if ( aArg > 0 ) 1074 { 1075 double d = log( aArg ); 1076 checkArithmeticOverflow( d ); 1077 rPar.Get( 0 )->PutDouble( d ); 1078 } 1079 else 1080 { 1081 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1082 } 1083 } 1084 } 1085 1086 void SbRtl_LTrim(StarBASIC *, SbxArray & rPar, bool) 1087 { 1088 if ( rPar.Count() < 2 ) 1089 { 1090 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1091 } 1092 else 1093 { 1094 OUString aStr(comphelper::string::stripStart(rPar.Get(1)->GetOUString(), ' ')); 1095 rPar.Get(0)->PutString(aStr); 1096 } 1097 } 1098 1099 1100 // Mid( String, nStart, nLength ) 1101 1102 void SbRtl_Mid(StarBASIC *, SbxArray & rPar, bool bWrite) 1103 { 1104 int nArgCount = rPar.Count()-1; 1105 if ( nArgCount < 2 ) 1106 { 1107 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1108 } 1109 else 1110 { 1111 // #23178: replicate the functionality of Mid$ as a command 1112 // by adding a replacement-string as a fourth parameter. 1113 // In contrast to the original the third parameter (nLength) 1114 // can't be left out here. That's considered in bWrite already. 1115 if( nArgCount == 4 ) 1116 { 1117 bWrite = true; 1118 } 1119 OUString aArgStr = rPar.Get(1)->GetOUString(); 1120 sal_Int32 nStartPos = rPar.Get(2)->GetLong(); 1121 if ( nStartPos < 1 ) 1122 { 1123 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1124 } 1125 else 1126 { 1127 nStartPos--; 1128 sal_Int32 nLen = -1; 1129 bool bWriteNoLenParam = false; 1130 if ( nArgCount == 3 || bWrite ) 1131 { 1132 sal_Int32 n = rPar.Get(3)->GetLong(); 1133 if( bWrite && n == -1 ) 1134 { 1135 bWriteNoLenParam = true; 1136 } 1137 nLen = n; 1138 } 1139 if ( bWrite ) 1140 { 1141 sal_Int32 nArgLen = aArgStr.getLength(); 1142 if( nStartPos > nArgLen ) 1143 { 1144 SbiInstance* pInst = GetSbData()->pInst; 1145 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 1146 if( bCompatibility ) 1147 { 1148 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1149 return; 1150 } 1151 nStartPos = nArgLen; 1152 } 1153 1154 OUString aReplaceStr = rPar.Get(4)->GetOUString(); 1155 sal_Int32 nReplaceStrLen = aReplaceStr.getLength(); 1156 sal_Int32 nReplaceLen; 1157 if( bWriteNoLenParam ) 1158 { 1159 nReplaceLen = nReplaceStrLen; 1160 } 1161 else 1162 { 1163 nReplaceLen = nLen; 1164 if( nReplaceLen < 0 || nReplaceLen > nReplaceStrLen ) 1165 { 1166 nReplaceLen = nReplaceStrLen; 1167 } 1168 } 1169 1170 sal_Int32 nReplaceEndPos = nStartPos + nReplaceLen; 1171 if( nReplaceEndPos > nArgLen ) 1172 { 1173 nReplaceLen -= (nReplaceEndPos - nArgLen); 1174 } 1175 OUStringBuffer aResultStr = aArgStr; 1176 sal_Int32 nErase = nReplaceLen; 1177 aResultStr.remove( nStartPos, nErase ); 1178 aResultStr.insert( nStartPos, aReplaceStr.getStr(), nReplaceLen); 1179 1180 rPar.Get(1)->PutString( aResultStr.makeStringAndClear() ); 1181 } 1182 else 1183 { 1184 OUString aResultStr; 1185 if (nStartPos > aArgStr.getLength()) 1186 { 1187 // do nothing 1188 } 1189 else if(nArgCount == 2) 1190 { 1191 aResultStr = aArgStr.copy( nStartPos); 1192 } 1193 else 1194 { 1195 if (nLen < 0) 1196 nLen = 0; 1197 if(nStartPos + nLen > aArgStr.getLength()) 1198 { 1199 nLen = aArgStr.getLength() - nStartPos; 1200 } 1201 if (nLen > 0) 1202 aResultStr = aArgStr.copy( nStartPos, nLen ); 1203 } 1204 rPar.Get(0)->PutString( aResultStr ); 1205 } 1206 } 1207 } 1208 } 1209 1210 void SbRtl_Oct(StarBASIC *, SbxArray & rPar, bool) 1211 { 1212 if ( rPar.Count() < 2 ) 1213 { 1214 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1215 } 1216 else 1217 { 1218 char aBuffer[16]; 1219 SbxVariableRef pArg = rPar.Get( 1 ); 1220 if ( pArg->IsInteger() ) 1221 { 1222 snprintf( aBuffer, sizeof(aBuffer), "%o", pArg->GetInteger() ); 1223 } 1224 else 1225 { 1226 snprintf( aBuffer, sizeof(aBuffer), "%lo", static_cast<long unsigned int>(pArg->GetLong()) ); 1227 } 1228 rPar.Get(0)->PutString( OUString::createFromAscii( aBuffer ) ); 1229 } 1230 } 1231 1232 // Replace(expression, find, replace[, start[, count[, compare]]]) 1233 1234 void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool) 1235 { 1236 std::size_t nArgCount = rPar.Count()-1; 1237 if ( nArgCount < 3 || nArgCount > 6 ) 1238 { 1239 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1240 } 1241 else 1242 { 1243 OUString aExpStr = rPar.Get(1)->GetOUString(); 1244 OUString aFindStr = rPar.Get(2)->GetOUString(); 1245 OUString aReplaceStr = rPar.Get(3)->GetOUString(); 1246 1247 sal_Int32 lStartPos = 1; 1248 if ( nArgCount >= 4 ) 1249 { 1250 if( rPar.Get(4)->GetType() != SbxEMPTY ) 1251 { 1252 lStartPos = rPar.Get(4)->GetLong(); 1253 } 1254 if( lStartPos < 1) 1255 { 1256 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1257 lStartPos = 1; 1258 } 1259 } 1260 1261 sal_Int32 lCount = -1; 1262 if( nArgCount >=5 ) 1263 { 1264 if( rPar.Get(5)->GetType() != SbxEMPTY ) 1265 { 1266 lCount = rPar.Get(5)->GetLong(); 1267 } 1268 if( lCount < -1) 1269 { 1270 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1271 lCount = -1; 1272 } 1273 } 1274 1275 SbiInstance* pInst = GetSbData()->pInst; 1276 bool bTextMode; 1277 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 1278 if( bCompatibility ) 1279 { 1280 SbiRuntime* pRT = pInst->pRun; 1281 bTextMode = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ); 1282 } 1283 else 1284 { 1285 bTextMode = true; 1286 } 1287 if ( nArgCount == 6 ) 1288 { 1289 bTextMode = rPar.Get(6)->GetInteger(); 1290 } 1291 sal_Int32 nExpStrLen = aExpStr.getLength(); 1292 sal_Int32 nFindStrLen = aFindStr.getLength(); 1293 sal_Int32 nReplaceStrLen = aReplaceStr.getLength(); 1294 1295 if( lStartPos <= nExpStrLen ) 1296 { 1297 sal_Int32 nPos = lStartPos - 1; 1298 sal_Int32 nCounts = 0; 1299 while( lCount == -1 || lCount > nCounts ) 1300 { 1301 OUString aSrcStr( aExpStr ); 1302 if( bTextMode ) 1303 { 1304 aSrcStr = aSrcStr.toAsciiUpperCase(); 1305 aFindStr = aFindStr.toAsciiUpperCase(); 1306 } 1307 nPos = aSrcStr.indexOf( aFindStr, nPos ); 1308 if( nPos >= 0 ) 1309 { 1310 aExpStr = aExpStr.replaceAt( nPos, nFindStrLen, aReplaceStr ); 1311 nPos = nPos + nReplaceStrLen; 1312 nCounts++; 1313 } 1314 else 1315 { 1316 break; 1317 } 1318 } 1319 } 1320 rPar.Get(0)->PutString( aExpStr.copy( lStartPos - 1 ) ); 1321 } 1322 } 1323 1324 void SbRtl_Right(StarBASIC *, SbxArray & rPar, bool) 1325 { 1326 if ( rPar.Count() < 3 ) 1327 { 1328 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1329 } 1330 else 1331 { 1332 const OUString& rStr = rPar.Get(1)->GetOUString(); 1333 int nResultLen = rPar.Get(2)->GetLong(); 1334 if( nResultLen < 0 ) 1335 { 1336 nResultLen = 0; 1337 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1338 } 1339 int nStrLen = rStr.getLength(); 1340 if ( nResultLen > nStrLen ) 1341 { 1342 nResultLen = nStrLen; 1343 } 1344 OUString aResultStr = rStr.copy( nStrLen - nResultLen ); 1345 rPar.Get(0)->PutString( aResultStr ); 1346 } 1347 } 1348 1349 void SbRtl_RTL(StarBASIC * pBasic, SbxArray & rPar, bool) 1350 { 1351 rPar.Get( 0 )->PutObject( pBasic->getRTL().get() ); 1352 } 1353 1354 void SbRtl_RTrim(StarBASIC *, SbxArray & rPar, bool) 1355 { 1356 if ( rPar.Count() < 2 ) 1357 { 1358 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1359 } 1360 else 1361 { 1362 OUString aStr(comphelper::string::stripEnd(rPar.Get(1)->GetOUString(), ' ')); 1363 rPar.Get(0)->PutString(aStr); 1364 } 1365 } 1366 1367 void SbRtl_Sgn(StarBASIC *, SbxArray & rPar, bool) 1368 { 1369 if ( rPar.Count() < 2 ) 1370 { 1371 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1372 } 1373 else 1374 { 1375 double aDouble = rPar.Get(1)->GetDouble(); 1376 sal_Int16 nResult = 0; 1377 if ( aDouble > 0 ) 1378 { 1379 nResult = 1; 1380 } 1381 else if ( aDouble < 0 ) 1382 { 1383 nResult = -1; 1384 } 1385 rPar.Get(0)->PutInteger( nResult ); 1386 } 1387 } 1388 1389 void SbRtl_Space(StarBASIC *, SbxArray & rPar, bool) 1390 { 1391 if ( rPar.Count() < 2 ) 1392 { 1393 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1394 } 1395 else 1396 { 1397 OUStringBuffer aBuf; 1398 string::padToLength(aBuf, rPar.Get(1)->GetLong(), ' '); 1399 rPar.Get(0)->PutString(aBuf.makeStringAndClear()); 1400 } 1401 } 1402 1403 void SbRtl_Spc(StarBASIC *, SbxArray & rPar, bool) 1404 { 1405 if ( rPar.Count() < 2 ) 1406 { 1407 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1408 } 1409 else 1410 { 1411 OUStringBuffer aBuf; 1412 string::padToLength(aBuf, rPar.Get(1)->GetLong(), ' '); 1413 rPar.Get(0)->PutString(aBuf.makeStringAndClear()); 1414 } 1415 } 1416 1417 void SbRtl_Sqr(StarBASIC *, SbxArray & rPar, bool) 1418 { 1419 if ( rPar.Count() < 2 ) 1420 { 1421 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1422 } 1423 else 1424 { 1425 double aDouble = rPar.Get(1)->GetDouble(); 1426 if ( aDouble >= 0 ) 1427 { 1428 rPar.Get(0)->PutDouble( sqrt( aDouble )); 1429 } 1430 else 1431 { 1432 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1433 } 1434 } 1435 } 1436 1437 void SbRtl_Str(StarBASIC *, SbxArray & rPar, bool) 1438 { 1439 if ( rPar.Count() < 2 ) 1440 { 1441 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1442 } 1443 else 1444 { 1445 OUString aStr; 1446 OUString aStrNew(""); 1447 SbxVariableRef pArg = rPar.Get( 1 ); 1448 pArg->Format( aStr ); 1449 1450 // Numbers start with a space 1451 if( pArg->IsNumericRTL() ) 1452 { 1453 // replace commas by points so that it's symmetric to Val! 1454 aStr = aStr.replaceFirst( ",", "." ); 1455 1456 SbiInstance* pInst = GetSbData()->pInst; 1457 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 1458 if( bCompatibility ) 1459 { 1460 sal_Int32 nLen = aStr.getLength(); 1461 1462 const sal_Unicode* pBuf = aStr.getStr(); 1463 1464 bool bNeg = ( pBuf[0] == '-' ); 1465 sal_Int32 iZeroSearch = 0; 1466 if( bNeg ) 1467 { 1468 aStrNew += "-"; 1469 iZeroSearch++; 1470 } 1471 else 1472 { 1473 if( pBuf[0] != ' ' ) 1474 { 1475 aStrNew += " "; 1476 } 1477 } 1478 sal_Int32 iNext = iZeroSearch + 1; 1479 if( pBuf[iZeroSearch] == '0' && nLen > iNext && pBuf[iNext] == '.' ) 1480 { 1481 iZeroSearch += 1; 1482 } 1483 aStrNew += aStr.copy(iZeroSearch); 1484 } 1485 else 1486 { 1487 aStrNew = " " + aStr; 1488 } 1489 } 1490 else 1491 { 1492 aStrNew = aStr; 1493 } 1494 rPar.Get(0)->PutString( aStrNew ); 1495 } 1496 } 1497 1498 void SbRtl_StrComp(StarBASIC *, SbxArray & rPar, bool) 1499 { 1500 if ( rPar.Count() < 3 ) 1501 { 1502 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1503 rPar.Get(0)->PutEmpty(); 1504 return; 1505 } 1506 const OUString& rStr1 = rPar.Get(1)->GetOUString(); 1507 const OUString& rStr2 = rPar.Get(2)->GetOUString(); 1508 1509 SbiInstance* pInst = GetSbData()->pInst; 1510 bool bTextCompare; 1511 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 1512 if( bCompatibility ) 1513 { 1514 SbiRuntime* pRT = pInst->pRun; 1515 bTextCompare = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ); 1516 } 1517 else 1518 { 1519 bTextCompare = true; 1520 } 1521 if ( rPar.Count() == 4 ) 1522 bTextCompare = rPar.Get(3)->GetInteger(); 1523 1524 if( !bCompatibility ) 1525 { 1526 bTextCompare = !bTextCompare; 1527 } 1528 sal_Int32 nRetValue = 0; 1529 if( bTextCompare ) 1530 { 1531 ::utl::TransliterationWrapper* pTransliterationWrapper = GetSbData()->pTransliterationWrapper.get(); 1532 if( !pTransliterationWrapper ) 1533 { 1534 uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext(); 1535 GetSbData()->pTransliterationWrapper.reset( 1536 new ::utl::TransliterationWrapper( xContext, 1537 TransliterationFlags::IGNORE_CASE | 1538 TransliterationFlags::IGNORE_KANA | 1539 TransliterationFlags::IGNORE_WIDTH ) ); 1540 pTransliterationWrapper = GetSbData()->pTransliterationWrapper.get(); 1541 } 1542 1543 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType(); 1544 pTransliterationWrapper->loadModuleIfNeeded( eLangType ); 1545 nRetValue = pTransliterationWrapper->compareString( rStr1, rStr2 ); 1546 } 1547 else 1548 { 1549 sal_Int32 aResult; 1550 aResult = rStr1.compareTo( rStr2 ); 1551 if ( aResult < 0 ) 1552 { 1553 nRetValue = -1; 1554 } 1555 else if ( aResult > 0) 1556 { 1557 nRetValue = 1; 1558 } 1559 } 1560 rPar.Get(0)->PutInteger( sal::static_int_cast< sal_Int16 >( nRetValue ) ); 1561 } 1562 1563 void SbRtl_String(StarBASIC *, SbxArray & rPar, bool) 1564 { 1565 if ( rPar.Count() < 2 ) 1566 { 1567 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1568 } 1569 else 1570 { 1571 sal_Unicode aFiller; 1572 sal_Int32 lCount = rPar.Get(1)->GetLong(); 1573 if( lCount < 0 || lCount > 0xffff ) 1574 { 1575 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1576 } 1577 if( rPar.Get(2)->GetType() == SbxINTEGER ) 1578 { 1579 aFiller = static_cast<sal_Unicode>(rPar.Get(2)->GetInteger()); 1580 } 1581 else 1582 { 1583 const OUString& rStr = rPar.Get(2)->GetOUString(); 1584 aFiller = rStr[0]; 1585 } 1586 OUStringBuffer aBuf(lCount); 1587 string::padToLength(aBuf, lCount, aFiller); 1588 rPar.Get(0)->PutString(aBuf.makeStringAndClear()); 1589 } 1590 } 1591 1592 void SbRtl_Tab(StarBASIC *, SbxArray & rPar, bool) 1593 { 1594 if ( rPar.Count() < 2 ) 1595 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1596 else 1597 { 1598 OUStringBuffer aStr; 1599 comphelper::string::padToLength(aStr, rPar.Get(1)->GetLong(), '\t'); 1600 rPar.Get(0)->PutString(aStr.makeStringAndClear()); 1601 } 1602 } 1603 1604 void SbRtl_Tan(StarBASIC *, SbxArray & rPar, bool) 1605 { 1606 if ( rPar.Count() < 2 ) 1607 { 1608 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1609 } 1610 else 1611 { 1612 SbxVariableRef pArg = rPar.Get( 1 ); 1613 rPar.Get( 0 )->PutDouble( tan( pArg->GetDouble() ) ); 1614 } 1615 } 1616 1617 void SbRtl_UCase(StarBASIC *, SbxArray & rPar, bool) 1618 { 1619 if ( rPar.Count() < 2 ) 1620 { 1621 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1622 } 1623 else 1624 { 1625 const CharClass& rCharClass = GetCharClass(); 1626 OUString aStr( rPar.Get(1)->GetOUString() ); 1627 aStr = rCharClass.uppercase( aStr ); 1628 rPar.Get(0)->PutString( aStr ); 1629 } 1630 } 1631 1632 1633 void SbRtl_Val(StarBASIC * pBasic, SbxArray & rPar, bool bWrite) 1634 { 1635 (void)pBasic; 1636 (void)bWrite; 1637 1638 if ( rPar.Count() < 2 ) 1639 { 1640 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1641 } 1642 else 1643 { 1644 double nResult = 0.0; 1645 char* pEndPtr; 1646 1647 OUString aStr( rPar.Get(1)->GetOUString() ); 1648 1649 FilterWhiteSpace( aStr ); 1650 if ( aStr.getLength() > 1 && aStr[0] == '&' ) 1651 { 1652 int nRadix = 10; 1653 char aChar = static_cast<char>(aStr[1]); 1654 if ( aChar == 'h' || aChar == 'H' ) 1655 { 1656 nRadix = 16; 1657 } 1658 else if ( aChar == 'o' || aChar == 'O' ) 1659 { 1660 nRadix = 8; 1661 } 1662 if ( nRadix != 10 ) 1663 { 1664 OString aByteStr(OUStringToOString(aStr, osl_getThreadTextEncoding())); 1665 sal_Int16 nlResult = static_cast<sal_Int16>(strtol( aByteStr.getStr()+2, &pEndPtr, nRadix)); 1666 nResult = static_cast<double>(nlResult); 1667 } 1668 } 1669 else 1670 { 1671 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; 1672 sal_Int32 nParseEnd = 0; 1673 nResult = ::rtl::math::stringToDouble( aStr, '.', ',', &eStatus, &nParseEnd ); 1674 if ( eStatus != rtl_math_ConversionStatus_Ok ) 1675 StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW ); 1676 /* TODO: we should check whether all characters were parsed here, 1677 * but earlier code silently ignored trailing nonsense such as "1x" 1678 * resulting in 1 with the side effect that any alpha-only-string 1679 * like "x" resulted in 0. Not changing that now (2013-03-22) as 1680 * user macros may rely on it. */ 1681 #if 0 1682 else if ( nParseEnd != aStr.getLength() ) 1683 StarBASIC::Error( ERRCODE_BASIC_CONVERSION ); 1684 #endif 1685 } 1686 1687 rPar.Get(0)->PutDouble( nResult ); 1688 } 1689 } 1690 1691 1692 // Helper functions for date conversion 1693 sal_Int16 implGetDateDay( double aDate ) 1694 { 1695 aDate -= 2.0; // standardize: 1.1.1900 => 0.0 1696 aDate = floor( aDate ); 1697 Date aRefDate( 1, 1, 1900 ); 1698 aRefDate.AddDays( aDate ); 1699 1700 sal_Int16 nRet = static_cast<sal_Int16>( aRefDate.GetDay() ); 1701 return nRet; 1702 } 1703 1704 sal_Int16 implGetDateMonth( double aDate ) 1705 { 1706 Date aRefDate( 1,1,1900 ); 1707 sal_Int32 nDays = static_cast<sal_Int32>(aDate); 1708 nDays -= 2; // standardize: 1.1.1900 => 0.0 1709 aRefDate.AddDays( nDays ); 1710 sal_Int16 nRet = static_cast<sal_Int16>( aRefDate.GetMonth() ); 1711 return nRet; 1712 } 1713 1714 css::util::Date SbxDateToUNODate( const SbxValue* const pVal ) 1715 { 1716 double aDate = pVal->GetDate(); 1717 1718 css::util::Date aUnoDate; 1719 aUnoDate.Day = implGetDateDay ( aDate ); 1720 aUnoDate.Month = implGetDateMonth( aDate ); 1721 aUnoDate.Year = implGetDateYear ( aDate ); 1722 1723 return aUnoDate; 1724 } 1725 1726 void SbxDateFromUNODate( SbxValue *pVal, const css::util::Date& aUnoDate) 1727 { 1728 double dDate; 1729 if( implDateSerial( aUnoDate.Year, aUnoDate.Month, aUnoDate.Day, false, SbDateCorrection::None, dDate ) ) 1730 { 1731 pVal->PutDate( dDate ); 1732 } 1733 } 1734 1735 // Function to convert date to UNO date (com.sun.star.util.Date) 1736 void SbRtl_CDateToUnoDate(StarBASIC *, SbxArray & rPar, bool) 1737 { 1738 if ( rPar.Count() != 2 ) 1739 { 1740 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1741 return; 1742 } 1743 1744 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNODate(rPar.Get(1)))); 1745 } 1746 1747 // Function to convert date from UNO date (com.sun.star.util.Date) 1748 void SbRtl_CDateFromUnoDate(StarBASIC *, SbxArray & rPar, bool) 1749 { 1750 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT ) 1751 { 1752 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1753 return; 1754 } 1755 1756 Any aAny (sbxToUnoValue(rPar.Get(1), cppu::UnoType<css::util::Date>::get())); 1757 css::util::Date aUnoDate; 1758 if(aAny >>= aUnoDate) 1759 SbxDateFromUNODate(rPar.Get(0), aUnoDate); 1760 else 1761 SbxBase::SetError( ERRCODE_BASIC_CONVERSION ); 1762 } 1763 1764 css::util::Time SbxDateToUNOTime( const SbxValue* const pVal ) 1765 { 1766 double aDate = pVal->GetDate(); 1767 1768 css::util::Time aUnoTime; 1769 aUnoTime.Hours = implGetHour ( aDate ); 1770 aUnoTime.Minutes = implGetMinute ( aDate ); 1771 aUnoTime.Seconds = implGetSecond ( aDate ); 1772 aUnoTime.NanoSeconds = 0; 1773 1774 return aUnoTime; 1775 } 1776 1777 void SbxDateFromUNOTime( SbxValue *pVal, const css::util::Time& aUnoTime) 1778 { 1779 pVal->PutDate( implTimeSerial(aUnoTime.Hours, aUnoTime.Minutes, aUnoTime.Seconds) ); 1780 } 1781 1782 // Function to convert date to UNO time (com.sun.star.util.Time) 1783 void SbRtl_CDateToUnoTime(StarBASIC *, SbxArray & rPar, bool) 1784 { 1785 if ( rPar.Count() != 2 ) 1786 { 1787 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1788 return; 1789 } 1790 1791 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNOTime(rPar.Get(1)))); 1792 } 1793 1794 // Function to convert date from UNO time (com.sun.star.util.Time) 1795 void SbRtl_CDateFromUnoTime(StarBASIC *, SbxArray & rPar, bool) 1796 { 1797 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT ) 1798 { 1799 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1800 return; 1801 } 1802 1803 Any aAny (sbxToUnoValue(rPar.Get(1), cppu::UnoType<css::util::Time>::get())); 1804 css::util::Time aUnoTime; 1805 if(aAny >>= aUnoTime) 1806 SbxDateFromUNOTime(rPar.Get(0), aUnoTime); 1807 else 1808 SbxBase::SetError( ERRCODE_BASIC_CONVERSION ); 1809 } 1810 1811 css::util::DateTime SbxDateToUNODateTime( const SbxValue* const pVal ) 1812 { 1813 double aDate = pVal->GetDate(); 1814 1815 css::util::DateTime aUnoDT; 1816 aUnoDT.Day = implGetDateDay ( aDate ); 1817 aUnoDT.Month = implGetDateMonth( aDate ); 1818 aUnoDT.Year = implGetDateYear ( aDate ); 1819 aUnoDT.Hours = implGetHour ( aDate ); 1820 aUnoDT.Minutes = implGetMinute ( aDate ); 1821 aUnoDT.Seconds = implGetSecond ( aDate ); 1822 aUnoDT.NanoSeconds = 0; 1823 1824 return aUnoDT; 1825 } 1826 1827 void SbxDateFromUNODateTime( SbxValue *pVal, const css::util::DateTime& aUnoDT) 1828 { 1829 double dDate(0.0); 1830 if( implDateTimeSerial( aUnoDT.Year, aUnoDT.Month, aUnoDT.Day, 1831 aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, 1832 dDate ) ) 1833 { 1834 pVal->PutDate( dDate ); 1835 } 1836 } 1837 1838 // Function to convert date to UNO date (com.sun.star.util.Date) 1839 void SbRtl_CDateToUnoDateTime(StarBASIC *, SbxArray & rPar, bool) 1840 { 1841 if ( rPar.Count() != 2 ) 1842 { 1843 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1844 return; 1845 } 1846 1847 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNODateTime(rPar.Get(1)))); 1848 } 1849 1850 // Function to convert date from UNO date (com.sun.star.util.Date) 1851 void SbRtl_CDateFromUnoDateTime(StarBASIC *, SbxArray & rPar, bool) 1852 { 1853 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT ) 1854 { 1855 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1856 return; 1857 } 1858 1859 Any aAny (sbxToUnoValue(rPar.Get(1), cppu::UnoType<css::util::DateTime>::get())); 1860 css::util::DateTime aUnoDT; 1861 if(aAny >>= aUnoDT) 1862 SbxDateFromUNODateTime(rPar.Get(0), aUnoDT); 1863 else 1864 SbxBase::SetError( ERRCODE_BASIC_CONVERSION ); 1865 } 1866 1867 // Function to convert date to ISO 8601 date format YYYYMMDD 1868 void SbRtl_CDateToIso(StarBASIC *, SbxArray & rPar, bool) 1869 { 1870 if ( rPar.Count() == 2 ) 1871 { 1872 double aDate = rPar.Get(1)->GetDate(); 1873 1874 // Date may actually even be -YYYYYMMDD 1875 char Buffer[11]; 1876 sal_Int16 nYear = implGetDateYear( aDate ); 1877 snprintf( Buffer, sizeof( Buffer ), (nYear < 0 ? "%05d%02d%02d" : "%04d%02d%02d"), 1878 static_cast<int>(nYear), 1879 static_cast<int>(implGetDateMonth( aDate )), 1880 static_cast<int>(implGetDateDay( aDate )) ); 1881 OUString aRetStr = OUString::createFromAscii( Buffer ); 1882 rPar.Get(0)->PutString( aRetStr ); 1883 } 1884 else 1885 { 1886 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1887 } 1888 } 1889 1890 // Function to convert date from ISO 8601 date format YYYYMMDD or YYYY-MM-DD 1891 // And even YYMMDD for compatibility, sigh.. 1892 void SbRtl_CDateFromIso(StarBASIC *, SbxArray & rPar, bool) 1893 { 1894 if ( rPar.Count() == 2 ) 1895 { 1896 do 1897 { 1898 OUString aStr = rPar.Get(1)->GetOUString(); 1899 if (aStr.isEmpty()) 1900 break; 1901 1902 // Valid formats are 1903 // YYYYMMDD -YYYMMDD YYYYYMMDD -YYYYYMMDD YYMMDD 1904 // YYYY-MM-DD -YYYY-MM-DD YYYYY-MM-DD -YYYYY-MM-DD 1905 1906 sal_Int32 nSign = 1; 1907 if (aStr[0] == '-') 1908 { 1909 nSign = -1; 1910 aStr = aStr.copy(1); 1911 } 1912 const sal_Int32 nLen = aStr.getLength(); 1913 1914 // Signed YYMMDD two digit year is invalid. 1915 if (nLen == 6 && nSign == -1) 1916 break; 1917 1918 // Now valid 1919 // YYYYMMDD YYYYYMMDD YYMMDD 1920 // YYYY-MM-DD YYYYY-MM-DD 1921 if (nLen != 6 && (nLen < 8 || 11 < nLen)) 1922 break; 1923 1924 bool bUseTwoDigitYear = false; 1925 OUString aYearStr, aMonthStr, aDayStr; 1926 if (nLen == 6 || nLen == 8 || nLen == 9) 1927 { 1928 // ((Y)YY)YYMMDD 1929 if (!comphelper::string::isdigitAsciiString(aStr)) 1930 break; 1931 1932 const sal_Int32 nMonthPos = (nLen == 8 ? 4 : (nLen == 6 ? 2 : 5)); 1933 if (nMonthPos == 2) 1934 bUseTwoDigitYear = true; 1935 aYearStr = aStr.copy( 0, nMonthPos ); 1936 aMonthStr = aStr.copy( nMonthPos, 2 ); 1937 aDayStr = aStr.copy( nMonthPos + 2, 2 ); 1938 } 1939 else 1940 { 1941 // (Y)YYYY-MM-DD 1942 const sal_Int32 nMonthSep = (nLen == 11 ? 5 : 4); 1943 if (aStr.indexOf('-') != nMonthSep) 1944 break; 1945 if (aStr.indexOf('-', nMonthSep + 1) != nMonthSep + 3) 1946 break; 1947 1948 aYearStr = aStr.copy( 0, nMonthSep ); 1949 aMonthStr = aStr.copy( nMonthSep + 1, 2 ); 1950 aDayStr = aStr.copy( nMonthSep + 4, 2 ); 1951 if ( !comphelper::string::isdigitAsciiString(aYearStr) || 1952 !comphelper::string::isdigitAsciiString(aMonthStr) || 1953 !comphelper::string::isdigitAsciiString(aDayStr)) 1954 break; 1955 } 1956 1957 double dDate; 1958 if (!implDateSerial( static_cast<sal_Int16>(nSign * aYearStr.toInt32()), 1959 static_cast<sal_Int16>(aMonthStr.toInt32()), static_cast<sal_Int16>(aDayStr.toInt32()), 1960 bUseTwoDigitYear, SbDateCorrection::None, dDate )) 1961 break; 1962 1963 rPar.Get(0)->PutDate( dDate ); 1964 1965 return; 1966 } 1967 while (false); 1968 1969 SbxBase::SetError( ERRCODE_BASIC_BAD_PARAMETER ); 1970 } 1971 else 1972 { 1973 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1974 } 1975 } 1976 1977 void SbRtl_DateSerial(StarBASIC *, SbxArray & rPar, bool) 1978 { 1979 if ( rPar.Count() < 4 ) 1980 { 1981 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 1982 return; 1983 } 1984 sal_Int16 nYear = rPar.Get(1)->GetInteger(); 1985 sal_Int16 nMonth = rPar.Get(2)->GetInteger(); 1986 sal_Int16 nDay = rPar.Get(3)->GetInteger(); 1987 1988 double dDate; 1989 if( implDateSerial( nYear, nMonth, nDay, true, SbDateCorrection::RollOver, dDate ) ) 1990 { 1991 rPar.Get(0)->PutDate( dDate ); 1992 } 1993 } 1994 1995 void SbRtl_TimeSerial(StarBASIC *, SbxArray & rPar, bool) 1996 { 1997 if ( rPar.Count() < 4 ) 1998 { 1999 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2000 return; 2001 } 2002 sal_Int16 nHour = rPar.Get(1)->GetInteger(); 2003 if ( nHour == 24 ) 2004 { 2005 nHour = 0; // because of UNO DateTimes, which go till 24 o'clock 2006 } 2007 sal_Int16 nMinute = rPar.Get(2)->GetInteger(); 2008 sal_Int16 nSecond = rPar.Get(3)->GetInteger(); 2009 if ((nHour < 0 || nHour > 23) || 2010 (nMinute < 0 || nMinute > 59 ) || 2011 (nSecond < 0 || nSecond > 59 )) 2012 { 2013 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2014 return; 2015 } 2016 2017 rPar.Get(0)->PutDate( implTimeSerial(nHour, nMinute, nSecond) ); // JSM 2018 } 2019 2020 void SbRtl_DateValue(StarBASIC *, SbxArray & rPar, bool) 2021 { 2022 if ( rPar.Count() < 2 ) 2023 { 2024 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2025 } 2026 else 2027 { 2028 // #39629 check GetSbData()->pInst, can be called from the URL line 2029 std::shared_ptr<SvNumberFormatter> pFormatter; 2030 if( GetSbData()->pInst ) 2031 { 2032 pFormatter = GetSbData()->pInst->GetNumberFormatter(); 2033 } 2034 else 2035 { 2036 sal_uInt32 n; // Dummy 2037 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n ); 2038 } 2039 2040 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType(); 2041 sal_uInt32 nIndex = pFormatter->GetStandardIndex( eLangType); 2042 double fResult; 2043 OUString aStr( rPar.Get(1)->GetOUString() ); 2044 bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult ); 2045 SvNumFormatType nType = pFormatter->GetType( nIndex ); 2046 2047 // DateValue("February 12, 1969") raises error if the system locale is not en_US 2048 // It seems that both locale number formatter and English number 2049 // formatter are supported in Visual Basic. 2050 if( !bSuccess && ( eLangType != LANGUAGE_ENGLISH_US ) ) 2051 { 2052 // Try using LANGUAGE_ENGLISH_US to get the date value. 2053 nIndex = pFormatter->GetStandardIndex( LANGUAGE_ENGLISH_US); 2054 bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult ); 2055 nType = pFormatter->GetType( nIndex ); 2056 } 2057 2058 if(bSuccess && (nType==SvNumFormatType::DATE || nType==SvNumFormatType::DATETIME)) 2059 { 2060 if ( nType == SvNumFormatType::DATETIME ) 2061 { 2062 // cut time 2063 if ( fResult > 0.0 ) 2064 { 2065 fResult = floor( fResult ); 2066 } 2067 else 2068 { 2069 fResult = ceil( fResult ); 2070 } 2071 } 2072 rPar.Get(0)->PutDate( fResult ); 2073 } 2074 else 2075 { 2076 StarBASIC::Error( ERRCODE_BASIC_CONVERSION ); 2077 } 2078 } 2079 } 2080 2081 void SbRtl_TimeValue(StarBASIC *, SbxArray & rPar, bool) 2082 { 2083 if ( rPar.Count() < 2 ) 2084 { 2085 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2086 } 2087 else 2088 { 2089 std::shared_ptr<SvNumberFormatter> pFormatter; 2090 if( GetSbData()->pInst ) 2091 pFormatter = GetSbData()->pInst->GetNumberFormatter(); 2092 else 2093 { 2094 sal_uInt32 n; 2095 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n ); 2096 } 2097 2098 sal_uInt32 nIndex = 0; 2099 double fResult; 2100 bool bSuccess = pFormatter->IsNumberFormat( rPar.Get(1)->GetOUString(), 2101 nIndex, fResult ); 2102 SvNumFormatType nType = pFormatter->GetType(nIndex); 2103 if(bSuccess && (nType==SvNumFormatType::TIME||nType==SvNumFormatType::DATETIME)) 2104 { 2105 if ( nType == SvNumFormatType::DATETIME ) 2106 { 2107 // cut days 2108 fResult = fmod( fResult, 1 ); 2109 } 2110 rPar.Get(0)->PutDate( fResult ); 2111 } 2112 else 2113 { 2114 StarBASIC::Error( ERRCODE_BASIC_CONVERSION ); 2115 } 2116 } 2117 } 2118 2119 void SbRtl_Day(StarBASIC *, SbxArray & rPar, bool) 2120 { 2121 if ( rPar.Count() < 2 ) 2122 { 2123 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2124 } 2125 else 2126 { 2127 SbxVariableRef pArg = rPar.Get( 1 ); 2128 double aDate = pArg->GetDate(); 2129 2130 sal_Int16 nDay = implGetDateDay( aDate ); 2131 rPar.Get(0)->PutInteger( nDay ); 2132 } 2133 } 2134 2135 void SbRtl_Year(StarBASIC *, SbxArray & rPar, bool) 2136 { 2137 if ( rPar.Count() < 2 ) 2138 { 2139 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2140 } 2141 else 2142 { 2143 sal_Int16 nYear = implGetDateYear( rPar.Get(1)->GetDate() ); 2144 rPar.Get(0)->PutInteger( nYear ); 2145 } 2146 } 2147 2148 sal_Int16 implGetHour( double dDate ) 2149 { 2150 double nFrac = dDate - floor( dDate ); 2151 nFrac *= 86400.0; 2152 sal_Int32 nSeconds = static_cast<sal_Int32>(nFrac + 0.5); 2153 sal_Int16 nHour = static_cast<sal_Int16>(nSeconds / 3600); 2154 return nHour; 2155 } 2156 2157 void SbRtl_Hour(StarBASIC *, SbxArray & rPar, bool) 2158 { 2159 if ( rPar.Count() < 2 ) 2160 { 2161 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2162 } 2163 else 2164 { 2165 double nArg = rPar.Get(1)->GetDate(); 2166 sal_Int16 nHour = implGetHour( nArg ); 2167 rPar.Get(0)->PutInteger( nHour ); 2168 } 2169 } 2170 2171 void SbRtl_Minute(StarBASIC *, SbxArray & rPar, bool) 2172 { 2173 if ( rPar.Count() < 2 ) 2174 { 2175 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2176 } 2177 else 2178 { 2179 double nArg = rPar.Get(1)->GetDate(); 2180 sal_Int16 nMin = implGetMinute( nArg ); 2181 rPar.Get(0)->PutInteger( nMin ); 2182 } 2183 } 2184 2185 void SbRtl_Month(StarBASIC *, SbxArray & rPar, bool) 2186 { 2187 if ( rPar.Count() < 2 ) 2188 { 2189 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2190 } 2191 else 2192 { 2193 sal_Int16 nMonth = implGetDateMonth( rPar.Get(1)->GetDate() ); 2194 rPar.Get(0)->PutInteger( nMonth ); 2195 } 2196 } 2197 2198 sal_Int16 implGetSecond( double dDate ) 2199 { 2200 double nFrac = dDate - floor( dDate ); 2201 nFrac *= 86400.0; 2202 sal_Int32 nSeconds = static_cast<sal_Int32>(nFrac + 0.5); 2203 sal_Int16 nTemp = static_cast<sal_Int16>(nSeconds / 3600); 2204 nSeconds -= nTemp * 3600; 2205 nTemp = static_cast<sal_Int16>(nSeconds / 60); 2206 nSeconds -= nTemp * 60; 2207 2208 sal_Int16 nRet = static_cast<sal_Int16>(nSeconds); 2209 return nRet; 2210 } 2211 2212 void SbRtl_Second(StarBASIC *, SbxArray & rPar, bool) 2213 { 2214 if ( rPar.Count() < 2 ) 2215 { 2216 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2217 } 2218 else 2219 { 2220 double nArg = rPar.Get(1)->GetDate(); 2221 sal_Int16 nSecond = implGetSecond( nArg ); 2222 rPar.Get(0)->PutInteger( nSecond ); 2223 } 2224 } 2225 2226 double Now_Impl() 2227 { 2228 DateTime aDateTime( DateTime::SYSTEM ); 2229 double aSerial = static_cast<double>(GetDayDiff( aDateTime )); 2230 long nSeconds = aDateTime.GetHour(); 2231 nSeconds *= 3600; 2232 nSeconds += aDateTime.GetMin() * 60; 2233 nSeconds += aDateTime.GetSec(); 2234 double nDays = static_cast<double>(nSeconds) / (24.0*3600.0); 2235 aSerial += nDays; 2236 return aSerial; 2237 } 2238 2239 // Date Now() 2240 2241 void SbRtl_Now(StarBASIC *, SbxArray & rPar, bool) 2242 { 2243 rPar.Get(0)->PutDate( Now_Impl() ); 2244 } 2245 2246 // Date Time() 2247 2248 void SbRtl_Time(StarBASIC *, SbxArray & rPar, bool bWrite) 2249 { 2250 if ( !bWrite ) 2251 { 2252 tools::Time aTime( tools::Time::SYSTEM ); 2253 SbxVariable* pMeth = rPar.Get( 0 ); 2254 OUString aRes; 2255 if( pMeth->IsFixed() ) 2256 { 2257 // Time$: hh:mm:ss 2258 char buf[ 20 ]; 2259 snprintf( buf, sizeof(buf), "%02d:%02d:%02d", 2260 aTime.GetHour(), aTime.GetMin(), aTime.GetSec() ); 2261 aRes = OUString::createFromAscii( buf ); 2262 } 2263 else 2264 { 2265 // Time: system dependent 2266 long nSeconds=aTime.GetHour(); 2267 nSeconds *= 3600; 2268 nSeconds += aTime.GetMin() * 60; 2269 nSeconds += aTime.GetSec(); 2270 double nDays = static_cast<double>(nSeconds) * ( 1.0 / (24.0*3600.0) ); 2271 Color* pCol; 2272 2273 std::shared_ptr<SvNumberFormatter> pFormatter; 2274 sal_uInt32 nIndex; 2275 if( GetSbData()->pInst ) 2276 { 2277 pFormatter = GetSbData()->pInst->GetNumberFormatter(); 2278 nIndex = GetSbData()->pInst->GetStdTimeIdx(); 2279 } 2280 else 2281 { 2282 sal_uInt32 n; // Dummy 2283 pFormatter = SbiInstance::PrepareNumberFormatter( n, nIndex, n ); 2284 } 2285 2286 pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol ); 2287 } 2288 pMeth->PutString( aRes ); 2289 } 2290 else 2291 { 2292 StarBASIC::Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); 2293 } 2294 } 2295 2296 void SbRtl_Timer(StarBASIC *, SbxArray & rPar, bool) 2297 { 2298 tools::Time aTime( tools::Time::SYSTEM ); 2299 long nSeconds = aTime.GetHour(); 2300 nSeconds *= 3600; 2301 nSeconds += aTime.GetMin() * 60; 2302 nSeconds += aTime.GetSec(); 2303 rPar.Get(0)->PutDate( static_cast<double>(nSeconds) ); 2304 } 2305 2306 2307 void SbRtl_Date(StarBASIC *, SbxArray & rPar, bool bWrite) 2308 { 2309 if ( !bWrite ) 2310 { 2311 Date aToday( Date::SYSTEM ); 2312 double nDays = static_cast<double>(GetDayDiff( aToday )); 2313 SbxVariable* pMeth = rPar.Get( 0 ); 2314 if( pMeth->IsString() ) 2315 { 2316 OUString aRes; 2317 Color* pCol; 2318 2319 std::shared_ptr<SvNumberFormatter> pFormatter; 2320 sal_uInt32 nIndex; 2321 if( GetSbData()->pInst ) 2322 { 2323 pFormatter = GetSbData()->pInst->GetNumberFormatter(); 2324 nIndex = GetSbData()->pInst->GetStdDateIdx(); 2325 } 2326 else 2327 { 2328 sal_uInt32 n; 2329 pFormatter = SbiInstance::PrepareNumberFormatter( nIndex, n, n ); 2330 } 2331 2332 pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol ); 2333 pMeth->PutString( aRes ); 2334 } 2335 else 2336 { 2337 pMeth->PutDate( nDays ); 2338 } 2339 } 2340 else 2341 { 2342 StarBASIC::Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); 2343 } 2344 } 2345 2346 void SbRtl_IsArray(StarBASIC *, SbxArray & rPar, bool) 2347 { 2348 if ( rPar.Count() < 2 ) 2349 { 2350 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2351 } 2352 else 2353 { 2354 rPar.Get(0)->PutBool((rPar.Get(1)->GetType() & SbxARRAY) != 0); 2355 } 2356 } 2357 2358 void SbRtl_IsObject(StarBASIC *, SbxArray & rPar, bool) 2359 { 2360 if ( rPar.Count() < 2 ) 2361 { 2362 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2363 } 2364 else 2365 { 2366 SbxVariable* pVar = rPar.Get(1); 2367 bool bObject = pVar->IsObject(); 2368 SbxBase* pObj = (bObject ? pVar->GetObject() : nullptr); 2369 2370 SbUnoClass* pUnoClass; 2371 if( pObj && ( pUnoClass=dynamic_cast<SbUnoClass*>( pObj) ) != nullptr ) 2372 { 2373 bObject = pUnoClass->getUnoClass().is(); 2374 } 2375 rPar.Get( 0 )->PutBool( bObject ); 2376 } 2377 } 2378 2379 void SbRtl_IsDate(StarBASIC *, SbxArray & rPar, bool) 2380 { 2381 if ( rPar.Count() < 2 ) 2382 { 2383 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2384 } 2385 else 2386 { 2387 // #46134 only string is converted, all other types result in sal_False 2388 SbxVariableRef xArg = rPar.Get( 1 ); 2389 SbxDataType eType = xArg->GetType(); 2390 bool bDate = false; 2391 2392 if( eType == SbxDATE ) 2393 { 2394 bDate = true; 2395 } 2396 else if( eType == SbxSTRING ) 2397 { 2398 ErrCode nPrevError = SbxBase::GetError(); 2399 SbxBase::ResetError(); 2400 2401 // force conversion of the parameter to SbxDATE 2402 xArg->SbxValue::GetDate(); 2403 2404 bDate = !SbxBase::IsError(); 2405 2406 SbxBase::ResetError(); 2407 SbxBase::SetError( nPrevError ); 2408 } 2409 rPar.Get( 0 )->PutBool( bDate ); 2410 } 2411 } 2412 2413 void SbRtl_IsEmpty(StarBASIC *, SbxArray & rPar, bool) 2414 { 2415 if ( rPar.Count() < 2 ) 2416 { 2417 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2418 } 2419 else 2420 { 2421 SbxVariable* pVar = nullptr; 2422 if( SbiRuntime::isVBAEnabled() ) 2423 { 2424 pVar = getDefaultProp( rPar.Get(1) ); 2425 } 2426 if ( pVar ) 2427 { 2428 pVar->Broadcast( SfxHintId::BasicDataWanted ); 2429 rPar.Get( 0 )->PutBool( pVar->IsEmpty() ); 2430 } 2431 else 2432 { 2433 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsEmpty() ); 2434 } 2435 } 2436 } 2437 2438 void SbRtl_IsError(StarBASIC *, SbxArray & rPar, bool) 2439 { 2440 if ( rPar.Count() < 2 ) 2441 { 2442 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2443 } 2444 else 2445 { 2446 SbxVariable* pVar =rPar.Get( 1 ); 2447 SbUnoObject* pObj = dynamic_cast<SbUnoObject*>( pVar ); 2448 if ( !pObj ) 2449 { 2450 if ( SbxBase* pBaseObj = (pVar->IsObject() ? pVar->GetObject() : nullptr) ) 2451 { 2452 pObj = dynamic_cast<SbUnoObject*>( pBaseObj ); 2453 } 2454 } 2455 uno::Reference< script::XErrorQuery > xError; 2456 if ( pObj ) 2457 { 2458 xError.set( pObj->getUnoAny(), uno::UNO_QUERY ); 2459 } 2460 if ( xError.is() ) 2461 { 2462 rPar.Get( 0 )->PutBool( xError->hasError() ); 2463 } 2464 else 2465 { 2466 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() ); 2467 } 2468 } 2469 } 2470 2471 void SbRtl_IsNull(StarBASIC *, SbxArray & rPar, bool) 2472 { 2473 if ( rPar.Count() < 2 ) 2474 { 2475 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2476 } 2477 else 2478 { 2479 // #51475 because of Uno-objects return true 2480 // even if the pObj value is NULL 2481 SbxVariableRef pArg = rPar.Get( 1 ); 2482 bool bNull = rPar.Get(1)->IsNull(); 2483 if( !bNull && pArg->GetType() == SbxOBJECT ) 2484 { 2485 SbxBase* pObj = pArg->GetObject(); 2486 if( !pObj ) 2487 { 2488 bNull = true; 2489 } 2490 } 2491 rPar.Get( 0 )->PutBool( bNull ); 2492 } 2493 } 2494 2495 void SbRtl_IsNumeric(StarBASIC *, SbxArray & rPar, bool) 2496 { 2497 if ( rPar.Count() < 2 ) 2498 { 2499 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2500 } 2501 else 2502 { 2503 rPar.Get( 0 )->PutBool( rPar.Get( 1 )->IsNumericRTL() ); 2504 } 2505 } 2506 2507 2508 void SbRtl_IsMissing(StarBASIC *, SbxArray & rPar, bool) 2509 { 2510 if ( rPar.Count() < 2 ) 2511 { 2512 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2513 } 2514 else 2515 { 2516 // #57915 Missing is reported by an error 2517 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() ); 2518 } 2519 } 2520 2521 // Function looks for wildcards, removes them and always returns the pure path 2522 OUString implSetupWildcard( const OUString& rFileParam, SbiRTLData* pRTLData ) 2523 { 2524 static sal_Char cDelim1 = '/'; 2525 static sal_Char cDelim2 = '\\'; 2526 static sal_Char cWild1 = '*'; 2527 static sal_Char cWild2 = '?'; 2528 2529 pRTLData->pWildCard.reset(); 2530 pRTLData->sFullNameToBeChecked.clear(); 2531 2532 OUString aFileParam = rFileParam; 2533 sal_Int32 nLastWild = aFileParam.lastIndexOf( cWild1 ); 2534 if( nLastWild < 0 ) 2535 { 2536 nLastWild = aFileParam.lastIndexOf( cWild2 ); 2537 } 2538 bool bHasWildcards = ( nLastWild >= 0 ); 2539 2540 2541 sal_Int32 nLastDelim = aFileParam.lastIndexOf( cDelim1 ); 2542 if( nLastDelim < 0 ) 2543 { 2544 nLastDelim = aFileParam.lastIndexOf( cDelim2 ); 2545 } 2546 if( bHasWildcards ) 2547 { 2548 // Wildcards in path? 2549 if( nLastDelim >= 0 && nLastDelim > nLastWild ) 2550 { 2551 return aFileParam; 2552 } 2553 } 2554 else 2555 { 2556 OUString aPathStr = getFullPath( aFileParam ); 2557 if( nLastDelim != aFileParam.getLength() - 1 ) 2558 { 2559 pRTLData->sFullNameToBeChecked = aPathStr; 2560 } 2561 return aPathStr; 2562 } 2563 2564 OUString aPureFileName; 2565 if( nLastDelim < 0 ) 2566 { 2567 aPureFileName = aFileParam; 2568 aFileParam.clear(); 2569 } 2570 else 2571 { 2572 aPureFileName = aFileParam.copy( nLastDelim + 1 ); 2573 aFileParam = aFileParam.copy( 0, nLastDelim ); 2574 } 2575 2576 // Try again to get a valid URL/UNC-path with only the path 2577 OUString aPathStr = getFullPath( aFileParam ); 2578 2579 // Is there a pure file name left? Otherwise the path is 2580 // invalid anyway because it was not accepted by OSL before 2581 if (aPureFileName != "*") 2582 { 2583 pRTLData->pWildCard = o3tl::make_unique<WildCard>( aPureFileName ); 2584 } 2585 return aPathStr; 2586 } 2587 2588 inline bool implCheckWildcard( const OUString& rName, SbiRTLData const * pRTLData ) 2589 { 2590 bool bMatch = true; 2591 2592 if( pRTLData->pWildCard ) 2593 { 2594 bMatch = pRTLData->pWildCard->Matches( rName ); 2595 } 2596 return bMatch; 2597 } 2598 2599 2600 bool isRootDir( const OUString& aDirURLStr ) 2601 { 2602 INetURLObject aDirURLObj( aDirURLStr ); 2603 bool bRoot = false; 2604 2605 // Check if it's a root directory 2606 sal_Int32 nCount = aDirURLObj.getSegmentCount(); 2607 2608 // No segment means Unix root directory "file:///" 2609 if( nCount == 0 ) 2610 { 2611 bRoot = true; 2612 } 2613 // Exactly one segment needs further checking, because it 2614 // can be Unix "file:///foo/" -> no root 2615 // or Windows "file:///c:/" -> root 2616 else if( nCount == 1 ) 2617 { 2618 OUString aSeg1 = aDirURLObj.getName( 0, true, 2619 INetURLObject::DecodeMechanism::WithCharset ); 2620 if( aSeg1[1] == ':' ) 2621 { 2622 bRoot = true; 2623 } 2624 } 2625 // More than one segments can never be root 2626 // so bRoot remains false 2627 2628 return bRoot; 2629 } 2630 2631 void SbRtl_Dir(StarBASIC *, SbxArray & rPar, bool) 2632 { 2633 OUString aPath; 2634 2635 sal_uInt16 nParCount = rPar.Count(); 2636 if( nParCount > 3 ) 2637 { 2638 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 2639 } 2640 else 2641 { 2642 SbiRTLData* pRTLData = GetSbData()->pInst->GetRTLData(); 2643 2644 // #34645: can also be called from the URL line via 'macro: Dir' 2645 // there's no pRTLDate existing in that case and the method must be left 2646 if( !pRTLData ) 2647 { 2648 return; 2649 } 2650 if( hasUno() ) 2651 { 2652 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 2653 if( xSFI.is() ) 2654 { 2655 if ( nParCount >= 2 ) 2656 { 2657 OUString aFileParam = rPar.Get(1)->GetOUString(); 2658 2659 OUString aFileURLStr = implSetupWildcard( aFileParam, pRTLData ); 2660 if( !pRTLData->sFullNameToBeChecked.isEmpty()) 2661 { 2662 bool bExists = false; 2663 try { bExists = xSFI->exists( aFileURLStr ); } 2664 catch(const Exception & ) {} 2665 2666 OUString aNameOnlyStr; 2667 if( bExists ) 2668 { 2669 INetURLObject aFileURL( aFileURLStr ); 2670 aNameOnlyStr = aFileURL.getName( INetURLObject::LAST_SEGMENT, 2671 true, INetURLObject::DecodeMechanism::WithCharset ); 2672 } 2673 rPar.Get(0)->PutString( aNameOnlyStr ); 2674 return; 2675 } 2676 2677 try 2678 { 2679 OUString aDirURLStr; 2680 bool bFolder = xSFI->isFolder( aFileURLStr ); 2681 2682 if( bFolder ) 2683 { 2684 aDirURLStr = aFileURLStr; 2685 } 2686 else 2687 { 2688 rPar.Get(0)->PutString( "" ); 2689 } 2690 2691 SbAttributes nFlags = SbAttributes::NONE; 2692 if ( nParCount > 2 ) 2693 { 2694 pRTLData->nDirFlags = nFlags = static_cast<SbAttributes>(rPar.Get(2)->GetInteger()); 2695 } 2696 else 2697 { 2698 pRTLData->nDirFlags = SbAttributes::NONE; 2699 } 2700 // Read directory 2701 bool bIncludeFolders = bool(nFlags & SbAttributes::DIRECTORY); 2702 pRTLData->aDirSeq = xSFI->getFolderContents( aDirURLStr, bIncludeFolders ); 2703 pRTLData->nCurDirPos = 0; 2704 2705 // #78651 Add "." and ".." directories for VB compatibility 2706 if( bIncludeFolders ) 2707 { 2708 bool bRoot = isRootDir( aDirURLStr ); 2709 2710 // If it's no root directory we flag the need for 2711 // the "." and ".." directories by the value -2 2712 // for the actual position. Later for -2 will be 2713 // returned "." and for -1 ".." 2714 if( !bRoot ) 2715 { 2716 pRTLData->nCurDirPos = -2; 2717 } 2718 } 2719 } 2720 catch(const Exception & ) 2721 { 2722 } 2723 } 2724 2725 2726 if( pRTLData->aDirSeq.getLength() > 0 ) 2727 { 2728 bool bFolderFlag = bool(pRTLData->nDirFlags & SbAttributes::DIRECTORY); 2729 2730 SbiInstance* pInst = GetSbData()->pInst; 2731 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 2732 for( ;; ) 2733 { 2734 if( pRTLData->nCurDirPos < 0 ) 2735 { 2736 if( pRTLData->nCurDirPos == -2 ) 2737 { 2738 aPath = "."; 2739 } 2740 else if( pRTLData->nCurDirPos == -1 ) 2741 { 2742 aPath = ".."; 2743 } 2744 pRTLData->nCurDirPos++; 2745 } 2746 else if( pRTLData->nCurDirPos >= pRTLData->aDirSeq.getLength() ) 2747 { 2748 pRTLData->aDirSeq.realloc( 0 ); 2749 aPath.clear(); 2750 break; 2751 } 2752 else 2753 { 2754 OUString aFile = pRTLData->aDirSeq.getConstArray()[pRTLData->nCurDirPos++]; 2755 2756 if( bCompatibility ) 2757 { 2758 if( !bFolderFlag ) 2759 { 2760 bool bFolder = xSFI->isFolder( aFile ); 2761 if( bFolder ) 2762 { 2763 continue; 2764 } 2765 } 2766 } 2767 else 2768 { 2769 // Only directories 2770 if( bFolderFlag ) 2771 { 2772 bool bFolder = xSFI->isFolder( aFile ); 2773 if( !bFolder ) 2774 { 2775 continue; 2776 } 2777 } 2778 } 2779 2780 INetURLObject aURL( aFile ); 2781 aPath = aURL.getName( INetURLObject::LAST_SEGMENT, true, 2782 INetURLObject::DecodeMechanism::WithCharset ); 2783 } 2784 2785 bool bMatch = implCheckWildcard( aPath, pRTLData ); 2786 if( !bMatch ) 2787 { 2788 continue; 2789 } 2790 break; 2791 } 2792 } 2793 rPar.Get(0)->PutString( aPath ); 2794 } 2795 } 2796 else 2797 { 2798 // TODO: OSL 2799 if ( nParCount >= 2 ) 2800 { 2801 OUString aFileParam = rPar.Get(1)->GetOUString(); 2802 2803 OUString aDirURL = implSetupWildcard( aFileParam, pRTLData ); 2804 2805 SbAttributes nFlags = SbAttributes::NONE; 2806 if ( nParCount > 2 ) 2807 { 2808 pRTLData->nDirFlags = nFlags = static_cast<SbAttributes>( rPar.Get(2)->GetInteger() ); 2809 } 2810 else 2811 { 2812 pRTLData->nDirFlags = SbAttributes::NONE; 2813 } 2814 2815 // Read directory 2816 bool bIncludeFolders = bool(nFlags & SbAttributes::DIRECTORY); 2817 pRTLData->pDir = o3tl::make_unique<Directory>( aDirURL ); 2818 FileBase::RC nRet = pRTLData->pDir->open(); 2819 if( nRet != FileBase::E_None ) 2820 { 2821 pRTLData->pDir.reset(); 2822 rPar.Get(0)->PutString( OUString() ); 2823 return; 2824 } 2825 2826 // #86950 Add "." and ".." directories for VB compatibility 2827 pRTLData->nCurDirPos = 0; 2828 if( bIncludeFolders ) 2829 { 2830 bool bRoot = isRootDir( aDirURL ); 2831 2832 // If it's no root directory we flag the need for 2833 // the "." and ".." directories by the value -2 2834 // for the actual position. Later for -2 will be 2835 // returned "." and for -1 ".." 2836 if( !bRoot ) 2837 { 2838 pRTLData->nCurDirPos = -2; 2839 } 2840 } 2841 2842 } 2843 2844 if( pRTLData->pDir ) 2845 { 2846 bool bFolderFlag = bool(pRTLData->nDirFlags & SbAttributes::DIRECTORY); 2847 for( ;; ) 2848 { 2849 if( pRTLData->nCurDirPos < 0 ) 2850 { 2851 if( pRTLData->nCurDirPos == -2 ) 2852 { 2853 aPath = "."; 2854 } 2855 else if( pRTLData->nCurDirPos == -1 ) 2856 { 2857 aPath = ".."; 2858 } 2859 pRTLData->nCurDirPos++; 2860 } 2861 else 2862 { 2863 DirectoryItem aItem; 2864 FileBase::RC nRet = pRTLData->pDir->getNextItem( aItem ); 2865 if( nRet != FileBase::E_None ) 2866 { 2867 pRTLData->pDir.reset(); 2868 aPath.clear(); 2869 break; 2870 } 2871 2872 // Handle flags 2873 FileStatus aFileStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName ); 2874 nRet = aItem.getFileStatus( aFileStatus ); 2875 if( nRet != FileBase::E_None ) 2876 { 2877 SAL_WARN("basic", "getFileStatus failed"); 2878 continue; 2879 } 2880 2881 // Only directories? 2882 if( bFolderFlag ) 2883 { 2884 FileStatus::Type aType = aFileStatus.getFileType(); 2885 bool bFolder = isFolder( aType ); 2886 if( !bFolder ) 2887 { 2888 continue; 2889 } 2890 } 2891 2892 aPath = aFileStatus.getFileName(); 2893 } 2894 2895 bool bMatch = implCheckWildcard( aPath, pRTLData ); 2896 if( !bMatch ) 2897 { 2898 continue; 2899 } 2900 break; 2901 } 2902 } 2903 rPar.Get(0)->PutString( aPath ); 2904 } 2905 } 2906 } 2907 2908 2909 void SbRtl_GetAttr(StarBASIC * pBasic, SbxArray & rPar, bool bWrite) 2910 { 2911 (void)pBasic; 2912 (void)bWrite; 2913 2914 if ( rPar.Count() == 2 ) 2915 { 2916 sal_Int16 nFlags = 0; 2917 2918 // In Windows, we want to use Windows API to get the file attributes 2919 // for VBA interoperability. 2920 #if defined(_WIN32) 2921 if( SbiRuntime::isVBAEnabled() ) 2922 { 2923 OUString aPathURL = getFullPath( rPar.Get(1)->GetOUString() ); 2924 OUString aPath; 2925 FileBase::getSystemPathFromFileURL( aPathURL, aPath ); 2926 DWORD nRealFlags = GetFileAttributesW (o3tl::toW(aPath.getStr())); 2927 if (nRealFlags != 0xffffffff) 2928 { 2929 if (nRealFlags == FILE_ATTRIBUTE_NORMAL) 2930 { 2931 nRealFlags = 0; 2932 } 2933 nFlags = static_cast<sal_Int16>(nRealFlags); 2934 } 2935 else 2936 { 2937 StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND ); 2938 } 2939 rPar.Get(0)->PutInteger( nFlags ); 2940 2941 return; 2942 } 2943 #endif 2944 2945 if( hasUno() ) 2946 { 2947 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 2948 if( xSFI.is() ) 2949 { 2950 try 2951 { 2952 OUString aPath = getFullPath( rPar.Get(1)->GetOUString() ); 2953 bool bExists = false; 2954 try { bExists = xSFI->exists( aPath ); } 2955 catch(const Exception & ) {} 2956 if( !bExists ) 2957 { 2958 StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND ); 2959 return; 2960 } 2961 2962 bool bReadOnly = xSFI->isReadOnly( aPath ); 2963 bool bHidden = xSFI->isHidden( aPath ); 2964 bool bDirectory = xSFI->isFolder( aPath ); 2965 if( bReadOnly ) 2966 { 2967 nFlags |= sal_uInt16(SbAttributes::READONLY); 2968 } 2969 if( bHidden ) 2970 { 2971 nFlags |= sal_uInt16(SbAttributes::HIDDEN); 2972 } 2973 if( bDirectory ) 2974 { 2975 nFlags |= sal_uInt16(SbAttributes::DIRECTORY); 2976 } 2977 } 2978 catch(const Exception & ) 2979 { 2980 StarBASIC::Error( ERRCODE_IO_GENERAL ); 2981 } 2982 } 2983 } 2984 else 2985 { 2986 DirectoryItem aItem; 2987 DirectoryItem::get( getFullPath( rPar.Get(1)->GetOUString() ), aItem ); 2988 FileStatus aFileStatus( osl_FileStatus_Mask_Attributes | osl_FileStatus_Mask_Type ); 2989 aItem.getFileStatus( aFileStatus ); 2990 sal_uInt64 nAttributes = aFileStatus.getAttributes(); 2991 bool bReadOnly = (nAttributes & osl_File_Attribute_ReadOnly) != 0; 2992 2993 FileStatus::Type aType = aFileStatus.getFileType(); 2994 bool bDirectory = isFolder( aType ); 2995 if( bReadOnly ) 2996 { 2997 nFlags |= sal_uInt16(SbAttributes::READONLY); 2998 } 2999 if( bDirectory ) 3000 { 3001 nFlags |= sal_uInt16(SbAttributes::DIRECTORY); 3002 } 3003 } 3004 rPar.Get(0)->PutInteger( nFlags ); 3005 } 3006 else 3007 { 3008 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3009 } 3010 } 3011 3012 3013 void SbRtl_FileDateTime(StarBASIC *, SbxArray & rPar, bool) 3014 { 3015 if ( rPar.Count() != 2 ) 3016 { 3017 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3018 } 3019 else 3020 { 3021 OUString aPath = rPar.Get(1)->GetOUString(); 3022 tools::Time aTime( tools::Time::EMPTY ); 3023 Date aDate( Date::EMPTY ); 3024 if( hasUno() ) 3025 { 3026 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 3027 if( xSFI.is() ) 3028 { 3029 try 3030 { 3031 util::DateTime aUnoDT = xSFI->getDateTimeModified( aPath ); 3032 aTime = tools::Time( aUnoDT ); 3033 aDate = Date( aUnoDT ); 3034 } 3035 catch(const Exception & ) 3036 { 3037 StarBASIC::Error( ERRCODE_IO_GENERAL ); 3038 } 3039 } 3040 } 3041 else 3042 { 3043 DirectoryItem aItem; 3044 DirectoryItem::get( getFullPath( aPath ), aItem ); 3045 FileStatus aFileStatus( osl_FileStatus_Mask_ModifyTime ); 3046 aItem.getFileStatus( aFileStatus ); 3047 TimeValue aTimeVal = aFileStatus.getModifyTime(); 3048 oslDateTime aDT; 3049 osl_getDateTimeFromTimeValue( &aTimeVal, &aDT ); 3050 3051 aTime = tools::Time( aDT.Hours, aDT.Minutes, aDT.Seconds, aDT.NanoSeconds ); 3052 aDate = Date( aDT.Day, aDT.Month, aDT.Year ); 3053 } 3054 3055 double fSerial = static_cast<double>(GetDayDiff( aDate )); 3056 long nSeconds = aTime.GetHour(); 3057 nSeconds *= 3600; 3058 nSeconds += aTime.GetMin() * 60; 3059 nSeconds += aTime.GetSec(); 3060 double nDays = static_cast<double>(nSeconds) / (24.0*3600.0); 3061 fSerial += nDays; 3062 3063 Color* pCol; 3064 3065 std::shared_ptr<SvNumberFormatter> pFormatter; 3066 sal_uInt32 nIndex; 3067 if( GetSbData()->pInst ) 3068 { 3069 pFormatter = GetSbData()->pInst->GetNumberFormatter(); 3070 nIndex = GetSbData()->pInst->GetStdDateTimeIdx(); 3071 } 3072 else 3073 { 3074 sal_uInt32 n; 3075 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, nIndex ); 3076 } 3077 3078 OUString aRes; 3079 pFormatter->GetOutputString( fSerial, nIndex, aRes, &pCol ); 3080 rPar.Get(0)->PutString( aRes ); 3081 } 3082 } 3083 3084 3085 void SbRtl_EOF(StarBASIC *, SbxArray & rPar, bool) 3086 { 3087 // No changes for UCB 3088 if ( rPar.Count() != 2 ) 3089 { 3090 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3091 } 3092 else 3093 { 3094 sal_Int16 nChannel = rPar.Get(1)->GetInteger(); 3095 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 3096 SbiStream* pSbStrm = pIO->GetStream( nChannel ); 3097 if ( !pSbStrm ) 3098 { 3099 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL ); 3100 return; 3101 } 3102 bool beof; 3103 SvStream* pSvStrm = pSbStrm->GetStrm(); 3104 if ( pSbStrm->IsText() ) 3105 { 3106 char cBla; 3107 (*pSvStrm).ReadChar( cBla ); // can we read another character? 3108 beof = pSvStrm->eof(); 3109 if ( !beof ) 3110 { 3111 pSvStrm->SeekRel( -1 ); 3112 } 3113 } 3114 else 3115 { 3116 beof = pSvStrm->eof(); // for binary data! 3117 } 3118 rPar.Get(0)->PutBool( beof ); 3119 } 3120 } 3121 3122 void SbRtl_FileAttr(StarBASIC *, SbxArray & rPar, bool) 3123 { 3124 // No changes for UCB 3125 // #57064 Although this function doesn't operate with DirEntry, it is 3126 // not touched by the adjustment to virtual URLs, as it only works on 3127 // already opened files and the name doesn't matter there. 3128 3129 if ( rPar.Count() != 3 ) 3130 { 3131 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3132 } 3133 else 3134 { 3135 sal_Int16 nChannel = rPar.Get(1)->GetInteger(); 3136 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 3137 SbiStream* pSbStrm = pIO->GetStream( nChannel ); 3138 if ( !pSbStrm ) 3139 { 3140 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL ); 3141 return; 3142 } 3143 sal_Int16 nRet; 3144 if ( rPar.Get(2)->GetInteger() == 1 ) 3145 { 3146 nRet = static_cast<sal_Int16>(pSbStrm->GetMode()); 3147 } 3148 else 3149 { 3150 nRet = 0; // System file handle not supported 3151 } 3152 rPar.Get(0)->PutInteger( nRet ); 3153 } 3154 } 3155 void SbRtl_Loc(StarBASIC *, SbxArray & rPar, bool) 3156 { 3157 // No changes for UCB 3158 if ( rPar.Count() != 2 ) 3159 { 3160 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3161 } 3162 else 3163 { 3164 sal_Int16 nChannel = rPar.Get(1)->GetInteger(); 3165 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 3166 SbiStream* pSbStrm = pIO->GetStream( nChannel ); 3167 if ( !pSbStrm ) 3168 { 3169 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL ); 3170 return; 3171 } 3172 SvStream* pSvStrm = pSbStrm->GetStrm(); 3173 std::size_t nPos; 3174 if( pSbStrm->IsRandom()) 3175 { 3176 short nBlockLen = pSbStrm->GetBlockLen(); 3177 nPos = nBlockLen ? (pSvStrm->Tell() / nBlockLen) : 0; 3178 nPos++; // block positions starting at 1 3179 } 3180 else if ( pSbStrm->IsText() ) 3181 { 3182 nPos = pSbStrm->GetLine(); 3183 } 3184 else if( pSbStrm->IsBinary() ) 3185 { 3186 nPos = pSvStrm->Tell(); 3187 } 3188 else if ( pSbStrm->IsSeq() ) 3189 { 3190 nPos = ( pSvStrm->Tell()+1 ) / 128; 3191 } 3192 else 3193 { 3194 nPos = pSvStrm->Tell(); 3195 } 3196 rPar.Get(0)->PutLong( static_cast<sal_Int32>(nPos) ); 3197 } 3198 } 3199 3200 void SbRtl_Lof(StarBASIC *, SbxArray & rPar, bool) 3201 { 3202 // No changes for UCB 3203 if ( rPar.Count() != 2 ) 3204 { 3205 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3206 } 3207 else 3208 { 3209 sal_Int16 nChannel = rPar.Get(1)->GetInteger(); 3210 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 3211 SbiStream* pSbStrm = pIO->GetStream( nChannel ); 3212 if ( !pSbStrm ) 3213 { 3214 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL ); 3215 return; 3216 } 3217 SvStream* pSvStrm = pSbStrm->GetStrm(); 3218 sal_uInt64 const nOldPos = pSvStrm->Tell(); 3219 sal_uInt64 const nLen = pSvStrm->Seek( STREAM_SEEK_TO_END ); 3220 pSvStrm->Seek( nOldPos ); 3221 rPar.Get(0)->PutLong( static_cast<sal_Int32>(nLen) ); 3222 } 3223 } 3224 3225 3226 void SbRtl_Seek(StarBASIC *, SbxArray & rPar, bool) 3227 { 3228 // No changes for UCB 3229 int nArgs = static_cast<int>(rPar.Count()); 3230 if ( nArgs < 2 || nArgs > 3 ) 3231 { 3232 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3233 return; 3234 } 3235 sal_Int16 nChannel = rPar.Get(1)->GetInteger(); 3236 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 3237 SbiStream* pSbStrm = pIO->GetStream( nChannel ); 3238 if ( !pSbStrm ) 3239 { 3240 StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL ); 3241 return; 3242 } 3243 SvStream* pStrm = pSbStrm->GetStrm(); 3244 3245 if ( nArgs == 2 ) // Seek-Function 3246 { 3247 sal_uInt64 nPos = pStrm->Tell(); 3248 if( pSbStrm->IsRandom() ) 3249 { 3250 nPos = nPos / pSbStrm->GetBlockLen(); 3251 } 3252 nPos++; // Basic counts from 1 3253 rPar.Get(0)->PutLong( static_cast<sal_Int32>(nPos) ); 3254 } 3255 else // Seek-Statement 3256 { 3257 sal_Int32 nPos = rPar.Get(2)->GetLong(); 3258 if ( nPos < 1 ) 3259 { 3260 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3261 return; 3262 } 3263 nPos--; // Basic counts from 1, SvStreams count from 0 3264 pSbStrm->SetExpandOnWriteTo( 0 ); 3265 if ( pSbStrm->IsRandom() ) 3266 { 3267 nPos *= pSbStrm->GetBlockLen(); 3268 } 3269 pStrm->Seek( static_cast<sal_uInt64>(nPos) ); 3270 pSbStrm->SetExpandOnWriteTo( nPos ); 3271 } 3272 } 3273 3274 void SbRtl_Format(StarBASIC *, SbxArray & rPar, bool) 3275 { 3276 sal_uInt16 nArgCount = rPar.Count(); 3277 if ( nArgCount < 2 || nArgCount > 3 ) 3278 { 3279 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3280 } 3281 else 3282 { 3283 OUString aResult; 3284 if( nArgCount == 2 ) 3285 { 3286 rPar.Get(1)->Format( aResult ); 3287 } 3288 else 3289 { 3290 OUString aFmt( rPar.Get(2)->GetOUString() ); 3291 rPar.Get(1)->Format( aResult, &aFmt ); 3292 } 3293 rPar.Get(0)->PutString( aResult ); 3294 } 3295 } 3296 3297 namespace { 3298 3299 // note: BASIC does not use comphelper::random, because 3300 // Randomize(int) must be supported and should not affect non-BASIC random use 3301 struct RandomNumberGenerator 3302 { 3303 std::mt19937 global_rng; 3304 3305 RandomNumberGenerator() 3306 { 3307 try 3308 { 3309 std::random_device rd; 3310 // initialises the state of the global random number generator 3311 // should only be called once. 3312 // (note, a few std::variate_generator<> (like normal) have their 3313 // own state which would need a reset as well to guarantee identical 3314 // sequence of numbers, e.g. via myrand.distribution().reset()) 3315 global_rng.seed(rd() ^ time(nullptr)); 3316 } 3317 catch (std::runtime_error& e) 3318 { 3319 SAL_WARN("basic", "Using std::random_device failed: " << e.what()); 3320 global_rng.seed(time(nullptr)); 3321 } 3322 } 3323 }; 3324 3325 class theRandomNumberGenerator : public rtl::Static<RandomNumberGenerator, theRandomNumberGenerator> {}; 3326 3327 } 3328 3329 void SbRtl_Randomize(StarBASIC *, SbxArray & rPar, bool) 3330 { 3331 if ( rPar.Count() > 2 ) 3332 { 3333 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3334 } 3335 if( rPar.Count() == 2 ) 3336 { 3337 int nSeed = static_cast<int>(rPar.Get(1)->GetInteger()); 3338 theRandomNumberGenerator::get().global_rng.seed(nSeed); 3339 } 3340 // without parameter, no need to do anything - RNG is seeded at first use 3341 } 3342 3343 void SbRtl_Rnd(StarBASIC *, SbxArray & rPar, bool) 3344 { 3345 if ( rPar.Count() > 2 ) 3346 { 3347 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3348 } 3349 else 3350 { 3351 std::uniform_real_distribution<double> dist(0.0, 1.0); 3352 double const tmp(dist(theRandomNumberGenerator::get().global_rng)); 3353 rPar.Get(0)->PutDouble(tmp); 3354 } 3355 } 3356 3357 3358 // Syntax: Shell("Path",[ Window-Style,[ "Params", [ bSync = sal_False ]]]) 3359 // WindowStyles (VBA compatible): 3360 // 2 == Minimized 3361 // 3 == Maximized 3362 // 10 == Full-Screen (text mode applications OS/2, WIN95, WNT) 3363 // HACK: The WindowStyle will be passed to 3364 // Application::StartApp in Creator. Format: "xxxx2" 3365 3366 3367 void SbRtl_Shell(StarBASIC *, SbxArray & rPar, bool) 3368 { 3369 std::size_t nArgCount = rPar.Count(); 3370 if ( nArgCount < 2 || nArgCount > 5 ) 3371 { 3372 rPar.Get(0)->PutLong(0); 3373 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3374 } 3375 else 3376 { 3377 oslProcessOption nOptions = osl_Process_SEARCHPATH | osl_Process_DETACHED; 3378 3379 OUString aCmdLine = rPar.Get(1)->GetOUString(); 3380 // attach additional parameters - everything must be parsed anyway 3381 if( nArgCount >= 4 ) 3382 { 3383 OUString tmp = rPar.Get(3)->GetOUString().trim(); 3384 if (!tmp.isEmpty()) 3385 { 3386 aCmdLine += " "; 3387 aCmdLine += tmp; 3388 } 3389 } 3390 else if( aCmdLine.isEmpty() ) 3391 { 3392 // avoid special treatment (empty list) 3393 aCmdLine += " "; 3394 } 3395 sal_Int32 nLen = aCmdLine.getLength(); 3396 3397 // #55735 if there are parameters, they have to be separated 3398 // #72471 also separate the single parameters 3399 std::vector<OUString> aTokenVector; 3400 OUString aToken; 3401 sal_Int32 i = 0; 3402 sal_Unicode c; 3403 while( i < nLen ) 3404 { 3405 for ( ;; ++i ) 3406 { 3407 c = aCmdLine[ i ]; 3408 if ( c != ' ' && c != '\t' ) 3409 { 3410 break; 3411 } 3412 } 3413 3414 if( c == '\"' || c == '\'' ) 3415 { 3416 sal_Int32 iFoundPos = aCmdLine.indexOf( c, i + 1 ); 3417 3418 if( iFoundPos < 0 ) 3419 { 3420 aToken = aCmdLine.copy( i); 3421 i = nLen; 3422 } 3423 else 3424 { 3425 aToken = aCmdLine.copy( i + 1, (iFoundPos - i - 1) ); 3426 i = iFoundPos + 1; 3427 } 3428 } 3429 else 3430 { 3431 sal_Int32 iFoundSpacePos = aCmdLine.indexOf( ' ', i ); 3432 sal_Int32 iFoundTabPos = aCmdLine.indexOf( '\t', i ); 3433 sal_Int32 iFoundPos = iFoundSpacePos >= 0 ? iFoundTabPos >= 0 ? std::min( iFoundSpacePos, iFoundTabPos ) : iFoundSpacePos : -1; 3434 3435 if( iFoundPos < 0 ) 3436 { 3437 aToken = aCmdLine.copy( i ); 3438 i = nLen; 3439 } 3440 else 3441 { 3442 aToken = aCmdLine.copy( i, (iFoundPos - i) ); 3443 i = iFoundPos; 3444 } 3445 } 3446 3447 // insert into the list 3448 aTokenVector.push_back( aToken ); 3449 } 3450 // #55735 / #72471 end 3451 3452 sal_Int16 nWinStyle = 0; 3453 if( nArgCount >= 3 ) 3454 { 3455 nWinStyle = rPar.Get(2)->GetInteger(); 3456 switch( nWinStyle ) 3457 { 3458 case 2: 3459 nOptions |= osl_Process_MINIMIZED; 3460 break; 3461 case 3: 3462 nOptions |= osl_Process_MAXIMIZED; 3463 break; 3464 case 10: 3465 nOptions |= osl_Process_FULLSCREEN; 3466 break; 3467 } 3468 3469 bool bSync = false; 3470 if( nArgCount >= 5 ) 3471 { 3472 bSync = rPar.Get(4)->GetBool(); 3473 } 3474 if( bSync ) 3475 { 3476 nOptions |= osl_Process_WAIT; 3477 } 3478 } 3479 3480 // #72471 work parameter(s) up 3481 std::vector<OUString>::const_iterator iter = aTokenVector.begin(); 3482 OUString aOUStrProgURL = getFullPath( *iter ); 3483 3484 ++iter; 3485 3486 sal_uInt16 nParamCount = sal::static_int_cast< sal_uInt16 >(aTokenVector.size() - 1 ); 3487 std::unique_ptr<rtl_uString*[]> pParamList; 3488 if( nParamCount ) 3489 { 3490 pParamList.reset( new rtl_uString*[nParamCount]); 3491 for(int iVector = 0; iter != aTokenVector.end(); ++iVector, ++iter) 3492 { 3493 const OUString& rParamStr = (*iter); 3494 pParamList[iVector] = nullptr; 3495 rtl_uString_assign(&(pParamList[iVector]), rParamStr.pData); 3496 } 3497 } 3498 3499 oslProcess pApp; 3500 bool bSucc = osl_executeProcess( 3501 aOUStrProgURL.pData, 3502 pParamList.get(), 3503 nParamCount, 3504 nOptions, 3505 nullptr, 3506 nullptr, 3507 nullptr, 0, 3508 &pApp ) == osl_Process_E_None; 3509 3510 // 53521 only free process handle on success 3511 if (bSucc) 3512 { 3513 osl_freeProcessHandle( pApp ); 3514 } 3515 3516 for(int j = 0; j < nParamCount; ++j) 3517 { 3518 rtl_uString_release(pParamList[j]); 3519 } 3520 3521 if( !bSucc ) 3522 { 3523 StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND ); 3524 } 3525 else 3526 { 3527 rPar.Get(0)->PutLong( 0 ); 3528 } 3529 } 3530 } 3531 3532 void SbRtl_VarType(StarBASIC *, SbxArray & rPar, bool) 3533 { 3534 if ( rPar.Count() != 2 ) 3535 { 3536 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3537 } 3538 else 3539 { 3540 SbxDataType eType = rPar.Get(1)->GetType(); 3541 rPar.Get(0)->PutInteger( static_cast<sal_Int16>(eType) ); 3542 } 3543 } 3544 3545 // Exported function 3546 OUString getBasicTypeName( SbxDataType eType ) 3547 { 3548 static const char* pTypeNames[] = 3549 { 3550 "Empty", // SbxEMPTY 3551 "Null", // SbxNULL 3552 "Integer", // SbxINTEGER 3553 "Long", // SbxLONG 3554 "Single", // SbxSINGLE 3555 "Double", // SbxDOUBLE 3556 "Currency", // SbxCURRENCY 3557 "Date", // SbxDATE 3558 "String", // SbxSTRING 3559 "Object", // SbxOBJECT 3560 "Error", // SbxERROR 3561 "Boolean", // SbxBOOL 3562 "Variant", // SbxVARIANT 3563 "DataObject", // SbxDATAOBJECT 3564 "Unknown Type", 3565 "Unknown Type", 3566 "Char", // SbxCHAR 3567 "Byte", // SbxBYTE 3568 "UShort", // SbxUSHORT 3569 "ULong", // SbxULONG 3570 "Long64", // SbxLONG64 3571 "ULong64", // SbxULONG64 3572 "Int", // SbxINT 3573 "UInt", // SbxUINT 3574 "Void", // SbxVOID 3575 "HResult", // SbxHRESULT 3576 "Pointer", // SbxPOINTER 3577 "DimArray", // SbxDIMARRAY 3578 "CArray", // SbxCARRAY 3579 "Userdef", // SbxUSERDEF 3580 "Lpstr", // SbxLPSTR 3581 "Lpwstr", // SbxLPWSTR 3582 "Unknown Type", // SbxCoreSTRING 3583 "WString", // SbxWSTRING 3584 "WChar", // SbxWCHAR 3585 "Int64", // SbxSALINT64 3586 "UInt64", // SbxSALUINT64 3587 "Decimal", // SbxDECIMAL 3588 }; 3589 3590 size_t nPos = static_cast<size_t>(eType) & 0x0FFF; 3591 const size_t nTypeNameCount = SAL_N_ELEMENTS( pTypeNames ); 3592 if ( nPos >= nTypeNameCount ) 3593 { 3594 nPos = nTypeNameCount - 1; 3595 } 3596 return OUString::createFromAscii(pTypeNames[nPos]); 3597 } 3598 3599 OUString getObjectTypeName( SbxVariable* pVar ) 3600 { 3601 OUString sRet( "Object" ); 3602 if ( pVar ) 3603 { 3604 SbxBase* pBaseObj = pVar->GetObject(); 3605 if( !pBaseObj ) 3606 { 3607 sRet = "Nothing"; 3608 } 3609 else 3610 { 3611 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pVar ); 3612 if ( !pUnoObj ) 3613 { 3614 pUnoObj = dynamic_cast<SbUnoObject*>( pBaseObj ); 3615 } 3616 if ( pUnoObj ) 3617 { 3618 Any aObj = pUnoObj->getUnoAny(); 3619 // For upstreaming unless we start to build oovbaapi by default 3620 // we need to get detect the vba-ness of the object in some 3621 // other way 3622 // note: Automation objects do not support XServiceInfo 3623 uno::Reference< XServiceInfo > xServInfo( aObj, uno::UNO_QUERY ); 3624 if ( xServInfo.is() ) 3625 { 3626 // is this a VBA object ? 3627 Sequence< OUString > sServices = xServInfo->getSupportedServiceNames(); 3628 if ( sServices.getLength() ) 3629 { 3630 sRet = sServices[ 0 ]; 3631 } 3632 } 3633 else 3634 { 3635 uno::Reference< bridge::oleautomation::XAutomationObject > xAutoMation( aObj, uno::UNO_QUERY ); 3636 if ( xAutoMation.is() ) 3637 { 3638 uno::Reference< script::XInvocation > xInv( aObj, uno::UNO_QUERY ); 3639 if ( xInv.is() ) 3640 { 3641 try 3642 { 3643 xInv->getValue( "$GetTypeName" ) >>= sRet; 3644 } 3645 catch(const Exception& ) 3646 { 3647 } 3648 } 3649 } 3650 } 3651 sal_Int32 nDot = sRet.lastIndexOf( '.' ); 3652 if ( nDot != -1 && nDot < sRet.getLength() ) 3653 { 3654 sRet = sRet.copy( nDot + 1 ); 3655 } 3656 } 3657 } 3658 } 3659 return sRet; 3660 } 3661 3662 void SbRtl_TypeName(StarBASIC *, SbxArray & rPar, bool) 3663 { 3664 if ( rPar.Count() != 2 ) 3665 { 3666 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3667 } 3668 else 3669 { 3670 SbxDataType eType = rPar.Get(1)->GetType(); 3671 bool bIsArray = ( ( eType & SbxARRAY ) != 0 ); 3672 3673 OUString aRetStr; 3674 if ( SbiRuntime::isVBAEnabled() && eType == SbxOBJECT ) 3675 { 3676 aRetStr = getObjectTypeName( rPar.Get(1) ); 3677 } 3678 else 3679 { 3680 aRetStr = getBasicTypeName( eType ); 3681 } 3682 if( bIsArray ) 3683 { 3684 aRetStr += "()"; 3685 } 3686 rPar.Get(0)->PutString( aRetStr ); 3687 } 3688 } 3689 3690 void SbRtl_Len(StarBASIC *, SbxArray & rPar, bool) 3691 { 3692 if ( rPar.Count() != 2 ) 3693 { 3694 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3695 } 3696 else 3697 { 3698 const OUString& rStr = rPar.Get(1)->GetOUString(); 3699 rPar.Get(0)->PutLong( rStr.getLength() ); 3700 } 3701 } 3702 3703 void SbRtl_DDEInitiate(StarBASIC *, SbxArray & rPar, bool) 3704 { 3705 int nArgs = static_cast<int>(rPar.Count()); 3706 if ( nArgs != 3 ) 3707 { 3708 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3709 return; 3710 } 3711 const OUString& rApp = rPar.Get(1)->GetOUString(); 3712 const OUString& rTopic = rPar.Get(2)->GetOUString(); 3713 3714 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl(); 3715 size_t nChannel; 3716 ErrCode nDdeErr = pDDE->Initiate( rApp, rTopic, nChannel ); 3717 if( nDdeErr ) 3718 { 3719 StarBASIC::Error( nDdeErr ); 3720 } 3721 else 3722 { 3723 rPar.Get(0)->PutInteger( static_cast<sal_Int16>(nChannel) ); 3724 } 3725 } 3726 3727 void SbRtl_DDETerminate(StarBASIC *, SbxArray & rPar, bool) 3728 { 3729 rPar.Get(0)->PutEmpty(); 3730 int nArgs = static_cast<int>(rPar.Count()); 3731 if ( nArgs != 2 ) 3732 { 3733 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3734 return; 3735 } 3736 size_t nChannel = rPar.Get(1)->GetInteger(); 3737 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl(); 3738 ErrCode nDdeErr = pDDE->Terminate( nChannel ); 3739 if( nDdeErr ) 3740 { 3741 StarBASIC::Error( nDdeErr ); 3742 } 3743 } 3744 3745 void SbRtl_DDETerminateAll(StarBASIC *, SbxArray & rPar, bool) 3746 { 3747 rPar.Get(0)->PutEmpty(); 3748 int nArgs = static_cast<int>(rPar.Count()); 3749 if ( nArgs != 1 ) 3750 { 3751 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3752 return; 3753 } 3754 3755 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl(); 3756 ErrCode nDdeErr = pDDE->TerminateAll(); 3757 if( nDdeErr ) 3758 { 3759 StarBASIC::Error( nDdeErr ); 3760 } 3761 } 3762 3763 void SbRtl_DDERequest(StarBASIC *, SbxArray & rPar, bool) 3764 { 3765 int nArgs = static_cast<int>(rPar.Count()); 3766 if ( nArgs != 3 ) 3767 { 3768 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3769 return; 3770 } 3771 size_t nChannel = rPar.Get(1)->GetInteger(); 3772 const OUString& rItem = rPar.Get(2)->GetOUString(); 3773 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl(); 3774 OUString aResult; 3775 ErrCode nDdeErr = pDDE->Request( nChannel, rItem, aResult ); 3776 if( nDdeErr ) 3777 { 3778 StarBASIC::Error( nDdeErr ); 3779 } 3780 else 3781 { 3782 rPar.Get(0)->PutString( aResult ); 3783 } 3784 } 3785 3786 void SbRtl_DDEExecute(StarBASIC *, SbxArray & rPar, bool) 3787 { 3788 rPar.Get(0)->PutEmpty(); 3789 int nArgs = static_cast<int>(rPar.Count()); 3790 if ( nArgs != 3 ) 3791 { 3792 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3793 return; 3794 } 3795 size_t nChannel = rPar.Get(1)->GetInteger(); 3796 const OUString& rCommand = rPar.Get(2)->GetOUString(); 3797 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl(); 3798 ErrCode nDdeErr = pDDE->Execute( nChannel, rCommand ); 3799 if( nDdeErr ) 3800 { 3801 StarBASIC::Error( nDdeErr ); 3802 } 3803 } 3804 3805 void SbRtl_DDEPoke(StarBASIC *, SbxArray & rPar, bool) 3806 { 3807 rPar.Get(0)->PutEmpty(); 3808 int nArgs = static_cast<int>(rPar.Count()); 3809 if ( nArgs != 4 ) 3810 { 3811 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3812 return; 3813 } 3814 size_t nChannel = rPar.Get(1)->GetInteger(); 3815 const OUString& rItem = rPar.Get(2)->GetOUString(); 3816 const OUString& rData = rPar.Get(3)->GetOUString(); 3817 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl(); 3818 ErrCode nDdeErr = pDDE->Poke( nChannel, rItem, rData ); 3819 if( nDdeErr ) 3820 { 3821 StarBASIC::Error( nDdeErr ); 3822 } 3823 } 3824 3825 3826 void SbRtl_FreeFile(StarBASIC *, SbxArray & rPar, bool) 3827 { 3828 if ( rPar.Count() != 1 ) 3829 { 3830 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3831 return; 3832 } 3833 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 3834 short nChannel = 1; 3835 while( nChannel < CHANNELS ) 3836 { 3837 SbiStream* pStrm = pIO->GetStream( nChannel ); 3838 if( !pStrm ) 3839 { 3840 rPar.Get(0)->PutInteger( nChannel ); 3841 return; 3842 } 3843 nChannel++; 3844 } 3845 StarBASIC::Error( ERRCODE_BASIC_TOO_MANY_FILES ); 3846 } 3847 3848 void SbRtl_LBound(StarBASIC *, SbxArray & rPar, bool) 3849 { 3850 sal_uInt16 nParCount = rPar.Count(); 3851 if ( nParCount != 3 && nParCount != 2 ) 3852 { 3853 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3854 return; 3855 } 3856 SbxBase* pParObj = rPar.Get(1)->GetObject(); 3857 SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj ); 3858 if( pArr ) 3859 { 3860 sal_Int32 nLower, nUpper; 3861 short nDim = (nParCount == 3) ? static_cast<short>(rPar.Get(2)->GetInteger()) : 1; 3862 if( !pArr->GetDim32( nDim, nLower, nUpper ) ) 3863 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE ); 3864 else 3865 rPar.Get(0)->PutLong( nLower ); 3866 } 3867 else 3868 StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS ); 3869 } 3870 3871 void SbRtl_UBound(StarBASIC *, SbxArray & rPar, bool) 3872 { 3873 sal_uInt16 nParCount = rPar.Count(); 3874 if ( nParCount != 3 && nParCount != 2 ) 3875 { 3876 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3877 return; 3878 } 3879 3880 SbxBase* pParObj = rPar.Get(1)->GetObject(); 3881 SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj ); 3882 if( pArr ) 3883 { 3884 sal_Int32 nLower, nUpper; 3885 short nDim = (nParCount == 3) ? static_cast<short>(rPar.Get(2)->GetInteger()) : 1; 3886 if( !pArr->GetDim32( nDim, nLower, nUpper ) ) 3887 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE ); 3888 else 3889 rPar.Get(0)->PutLong( nUpper ); 3890 } 3891 else 3892 StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS ); 3893 } 3894 3895 void SbRtl_RGB(StarBASIC *, SbxArray & rPar, bool) 3896 { 3897 if ( rPar.Count() != 4 ) 3898 { 3899 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3900 return; 3901 } 3902 3903 sal_Int32 nRed = rPar.Get(1)->GetInteger() & 0xFF; 3904 sal_Int32 nGreen = rPar.Get(2)->GetInteger() & 0xFF; 3905 sal_Int32 nBlue = rPar.Get(3)->GetInteger() & 0xFF; 3906 sal_Int32 nRGB; 3907 3908 SbiInstance* pInst = GetSbData()->pInst; 3909 bool bCompatibility = ( pInst && pInst->IsCompatibility() ); 3910 if( bCompatibility ) 3911 { 3912 nRGB = (nBlue << 16) | (nGreen << 8) | nRed; 3913 } 3914 else 3915 { 3916 nRGB = (nRed << 16) | (nGreen << 8) | nBlue; 3917 } 3918 rPar.Get(0)->PutLong( nRGB ); 3919 } 3920 3921 void SbRtl_QBColor(StarBASIC *, SbxArray & rPar, bool) 3922 { 3923 static const sal_Int32 pRGB[] = 3924 { 3925 0x000000, 3926 0x800000, 3927 0x008000, 3928 0x808000, 3929 0x000080, 3930 0x800080, 3931 0x008080, 3932 0xC0C0C0, 3933 0x808080, 3934 0xFF0000, 3935 0x00FF00, 3936 0xFFFF00, 3937 0x0000FF, 3938 0xFF00FF, 3939 0x00FFFF, 3940 0xFFFFFF, 3941 }; 3942 3943 if ( rPar.Count() != 2 ) 3944 { 3945 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3946 return; 3947 } 3948 3949 sal_Int16 nCol = rPar.Get(1)->GetInteger(); 3950 if( nCol < 0 || nCol > 15 ) 3951 { 3952 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3953 return; 3954 } 3955 sal_Int32 nRGB = pRGB[ nCol ]; 3956 rPar.Get(0)->PutLong( nRGB ); 3957 } 3958 3959 // StrConv(string, conversion, LCID) 3960 void SbRtl_StrConv(StarBASIC *, SbxArray & rPar, bool) 3961 { 3962 std::size_t nArgCount = rPar.Count()-1; 3963 if( nArgCount < 2 || nArgCount > 3 ) 3964 { 3965 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3966 return; 3967 } 3968 3969 OUString aOldStr = rPar.Get(1)->GetOUString(); 3970 sal_Int32 nConversion = rPar.Get(2)->GetLong(); 3971 3972 LanguageType nLanguage = LANGUAGE_SYSTEM; 3973 3974 sal_Int32 nOldLen = aOldStr.getLength(); 3975 if( nOldLen == 0 ) 3976 { 3977 // null string,return 3978 rPar.Get(0)->PutString(aOldStr); 3979 return; 3980 } 3981 3982 TransliterationFlags nType = TransliterationFlags::NONE; 3983 if ( (nConversion & 0x03) == 3 ) // vbProperCase 3984 { 3985 const CharClass& rCharClass = GetCharClass(); 3986 aOldStr = rCharClass.titlecase( aOldStr.toAsciiLowerCase(), 0, nOldLen ); 3987 } 3988 else if ( (nConversion & 0x01) == 1 ) // vbUpperCase 3989 { 3990 nType |= TransliterationFlags::LOWERCASE_UPPERCASE; 3991 } 3992 else if ( (nConversion & 0x02) == 2 ) // vbLowerCase 3993 { 3994 nType |= TransliterationFlags::UPPERCASE_LOWERCASE; 3995 } 3996 if ( (nConversion & 0x04) == 4 ) // vbWide 3997 { 3998 nType |= TransliterationFlags::HALFWIDTH_FULLWIDTH; 3999 } 4000 else if ( (nConversion & 0x08) == 8 ) // vbNarrow 4001 { 4002 nType |= TransliterationFlags::FULLWIDTH_HALFWIDTH; 4003 } 4004 if ( (nConversion & 0x10) == 16) // vbKatakana 4005 { 4006 nType |= TransliterationFlags::HIRAGANA_KATAKANA; 4007 } 4008 else if ( (nConversion & 0x20) == 32 ) // vbHiragana 4009 { 4010 nType |= TransliterationFlags::KATAKANA_HIRAGANA; 4011 } 4012 OUString aNewStr( aOldStr ); 4013 if( nType != TransliterationFlags::NONE ) 4014 { 4015 uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext(); 4016 ::utl::TransliterationWrapper aTransliterationWrapper( xContext, nType ); 4017 uno::Sequence<sal_Int32> aOffsets; 4018 aTransliterationWrapper.loadModuleIfNeeded( nLanguage ); 4019 aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets ); 4020 } 4021 4022 if ( (nConversion & 0x40) == 64 ) // vbUnicode 4023 { 4024 // convert the string to byte string, preserving unicode (2 bytes per character) 4025 sal_Int32 nSize = aNewStr.getLength()*2; 4026 const sal_Unicode* pSrc = aNewStr.getStr(); 4027 std::unique_ptr<sal_Char[]> pChar(new sal_Char[nSize+1]); 4028 for( sal_Int32 i=0; i < nSize; i++ ) 4029 { 4030 pChar[i] = static_cast< sal_Char >( (i%2) ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff ); 4031 if( i%2 ) 4032 { 4033 pSrc++; 4034 } 4035 } 4036 pChar[nSize] = '\0'; 4037 OString aOStr(pChar.get()); 4038 4039 // there is no concept about default codepage in unix. so it is incorrectly in unix 4040 OUString aOUStr = OStringToOUString(aOStr, osl_getThreadTextEncoding()); 4041 rPar.Get(0)->PutString( aOUStr ); 4042 return; 4043 } 4044 else if ( (nConversion & 0x80) == 128 ) // vbFromUnicode 4045 { 4046 // there is no concept about default codepage in unix. so it is incorrectly in unix 4047 OString aOStr = OUStringToOString(aNewStr,osl_getThreadTextEncoding()); 4048 const sal_Char* pChar = aOStr.getStr(); 4049 sal_Int32 nArraySize = aOStr.getLength(); 4050 SbxDimArray* pArray = new SbxDimArray(SbxBYTE); 4051 bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() ); 4052 if(nArraySize) 4053 { 4054 if( bIncIndex ) 4055 { 4056 pArray->AddDim( 1, nArraySize ); 4057 } 4058 else 4059 { 4060 pArray->AddDim( 0, nArraySize-1 ); 4061 } 4062 } 4063 else 4064 { 4065 pArray->unoAddDim( 0, -1 ); 4066 } 4067 4068 for( sal_Int32 i=0; i< nArraySize; i++) 4069 { 4070 SbxVariable* pNew = new SbxVariable( SbxBYTE ); 4071 pNew->PutByte(*pChar); 4072 pChar++; 4073 pNew->SetFlag( SbxFlagBits::Write ); 4074 short aIdx[1]; 4075 aIdx[0] = i; 4076 if( bIncIndex ) 4077 { 4078 ++aIdx[0]; 4079 } 4080 pArray->Put(pNew, aIdx); 4081 } 4082 4083 SbxVariableRef refVar = rPar.Get(0); 4084 SbxFlagBits nFlags = refVar->GetFlags(); 4085 refVar->ResetFlag( SbxFlagBits::Fixed ); 4086 refVar->PutObject( pArray ); 4087 refVar->SetFlags( nFlags ); 4088 refVar->SetParameters( nullptr ); 4089 return; 4090 } 4091 rPar.Get(0)->PutString(aNewStr); 4092 } 4093 4094 4095 void SbRtl_Beep(StarBASIC *, SbxArray & rPar, bool) 4096 { 4097 if ( rPar.Count() != 1 ) 4098 { 4099 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4100 return; 4101 } 4102 Sound::Beep(); 4103 } 4104 4105 void SbRtl_Load(StarBASIC *, SbxArray & rPar, bool) 4106 { 4107 if( rPar.Count() != 2 ) 4108 { 4109 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4110 return; 4111 } 4112 4113 4114 SbxBase* pObj = static_cast<SbxObject*>(rPar.Get(1)->GetObject()); 4115 if ( pObj ) 4116 { 4117 if (SbUserFormModule* pModule = dynamic_cast<SbUserFormModule*>(pObj)) 4118 { 4119 pModule->Load(); 4120 } 4121 else if (SbxObject* pSbxObj = dynamic_cast<SbxObject*>(pObj)) 4122 { 4123 SbxVariable* pVar = pSbxObj->Find("Load", SbxClassType::Method); 4124 if( pVar ) 4125 { 4126 pVar->GetInteger(); 4127 } 4128 } 4129 } 4130 } 4131 4132 void SbRtl_Unload(StarBASIC *, SbxArray & rPar, bool) 4133 { 4134 rPar.Get(0)->PutEmpty(); 4135 if( rPar.Count() != 2 ) 4136 { 4137 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4138 return; 4139 } 4140 4141 4142 SbxBase* pObj = static_cast<SbxObject*>(rPar.Get(1)->GetObject()); 4143 if ( pObj ) 4144 { 4145 if (SbUserFormModule* pFormModule = dynamic_cast<SbUserFormModule*>(pObj)) 4146 { 4147 pFormModule->Unload(); 4148 } 4149 else if (SbxObject *pSbxObj = dynamic_cast<SbxObject*>(pObj)) 4150 { 4151 SbxVariable* pVar = pSbxObj->Find("Unload", SbxClassType::Method); 4152 if( pVar ) 4153 { 4154 pVar->GetInteger(); 4155 } 4156 } 4157 } 4158 } 4159 4160 void SbRtl_LoadPicture(StarBASIC *, SbxArray & rPar, bool) 4161 { 4162 if( rPar.Count() != 2 ) 4163 { 4164 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4165 return; 4166 } 4167 4168 OUString aFileURL = getFullPath( rPar.Get(1)->GetOUString() ); 4169 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aFileURL, StreamMode::READ )); 4170 if( pStream ) 4171 { 4172 Bitmap aBmp; 4173 ReadDIB(aBmp, *pStream, true); 4174 Graphic aGraphic(aBmp); 4175 4176 SbxObjectRef xRef = new SbStdPicture; 4177 static_cast<SbStdPicture*>(xRef.get())->SetGraphic( aGraphic ); 4178 rPar.Get(0)->PutObject( xRef.get() ); 4179 } 4180 } 4181 4182 void SbRtl_SavePicture(StarBASIC *, SbxArray & rPar, bool) 4183 { 4184 rPar.Get(0)->PutEmpty(); 4185 if( rPar.Count() != 3 ) 4186 { 4187 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4188 return; 4189 } 4190 4191 SbxBase* pObj = static_cast<SbxObject*>(rPar.Get(1)->GetObject()); 4192 if (SbStdPicture *pPicture = dynamic_cast<SbStdPicture*>(pObj)) 4193 { 4194 SvFileStream aOStream( rPar.Get(2)->GetOUString(), StreamMode::WRITE | StreamMode::TRUNC ); 4195 Graphic aGraphic = pPicture->GetGraphic(); 4196 WriteGraphic( aOStream, aGraphic ); 4197 } 4198 } 4199 4200 void SbRtl_MsgBox(StarBASIC *, SbxArray & rPar, bool) 4201 { 4202 sal_uInt16 nArgCount = rPar.Count(); 4203 if( nArgCount < 2 || nArgCount > 6 ) 4204 { 4205 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4206 return; 4207 } 4208 WinBits nType = 0; // MB_OK 4209 if( nArgCount >= 3 ) 4210 nType = static_cast<WinBits>(rPar.Get(2)->GetInteger()); 4211 WinBits nStyle = nType; 4212 nStyle &= 15; // delete bits 4-16 4213 if (nStyle > 5) 4214 nStyle = 0; 4215 4216 enum BasicResponse 4217 { 4218 Ok = 1, 4219 Cancel = 2, 4220 Abort = 3, 4221 Retry = 4, 4222 Ignore = 5, 4223 Yes = 6, 4224 No = 7 4225 }; 4226 4227 OUString aMsg = rPar.Get(1)->GetOUString(); 4228 OUString aTitle; 4229 if( nArgCount >= 4 ) 4230 { 4231 aTitle = rPar.Get(3)->GetOUString(); 4232 } 4233 else 4234 { 4235 aTitle = Application::GetDisplayName(); 4236 } 4237 4238 WinBits nDialogType = nType & (16+32+64); 4239 4240 SolarMutexGuard aSolarGuard; 4241 vcl::Window* pParentWin = Application::GetDefDialogParent(); 4242 weld::Widget* pParent = pParentWin ? pParentWin->GetFrameWeld() : nullptr; 4243 4244 VclMessageType eType = VclMessageType::Info; 4245 4246 switch (nDialogType) 4247 { 4248 case 16: 4249 eType = VclMessageType::Error; 4250 break; 4251 case 32: 4252 eType = VclMessageType::Question; 4253 break; 4254 case 48: 4255 eType = VclMessageType::Warning; 4256 break; 4257 case 64: 4258 default: 4259 eType = VclMessageType::Info; 4260 break; 4261 } 4262 4263 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent, 4264 eType, VclButtonsType::NONE, aMsg)); 4265 4266 switch (nStyle) 4267 { 4268 case 0: // MB_OK 4269 default: 4270 xBox->add_button(Button::GetStandardText(StandardButtonType::OK), BasicResponse::Ok); 4271 break; 4272 case 1: // MB_OKCANCEL 4273 xBox->add_button(Button::GetStandardText(StandardButtonType::OK), BasicResponse::Ok); 4274 xBox->add_button(Button::GetStandardText(StandardButtonType::Cancel), BasicResponse::Cancel); 4275 4276 if (nType & 256 || nType & 512) 4277 xBox->set_default_response(BasicResponse::Cancel); 4278 else 4279 xBox->set_default_response(BasicResponse::Ok); 4280 4281 break; 4282 case 2: // MB_ABORTRETRYIGNORE 4283 xBox->add_button(Button::GetStandardText(StandardButtonType::Abort), BasicResponse::Abort); 4284 xBox->add_button(Button::GetStandardText(StandardButtonType::Retry), BasicResponse::Retry); 4285 xBox->add_button(Button::GetStandardText(StandardButtonType::Ignore), BasicResponse::Ignore); 4286 4287 if (nType & 256) 4288 xBox->set_default_response(BasicResponse::Retry); 4289 else if (nType & 512) 4290 xBox->set_default_response(BasicResponse::Ignore); 4291 else 4292 xBox->set_default_response(BasicResponse::Cancel); 4293 4294 break; 4295 case 3: // MB_YESNOCANCEL 4296 xBox->add_button(Button::GetStandardText(StandardButtonType::Yes), BasicResponse::Yes); 4297 xBox->add_button(Button::GetStandardText(StandardButtonType::No), BasicResponse::No); 4298 xBox->add_button(Button::GetStandardText(StandardButtonType::Cancel), BasicResponse::Cancel); 4299 4300 if (nType & 256 || nType & 512) 4301 xBox->set_default_response(BasicResponse::Cancel); 4302 else 4303 xBox->set_default_response(BasicResponse::Yes); 4304 4305 break; 4306 case 4: // MB_YESNO 4307 xBox->add_button(Button::GetStandardText(StandardButtonType::Yes), BasicResponse::Yes); 4308 xBox->add_button(Button::GetStandardText(StandardButtonType::No), BasicResponse::No); 4309 4310 if (nType & 256 || nType & 512) 4311 xBox->set_default_response(BasicResponse::No); 4312 else 4313 xBox->set_default_response(BasicResponse::Yes); 4314 4315 break; 4316 case 5: // MB_RETRYCANCEL 4317 xBox->add_button(Button::GetStandardText(StandardButtonType::Retry), BasicResponse::Retry); 4318 xBox->add_button(Button::GetStandardText(StandardButtonType::Cancel), BasicResponse::Cancel); 4319 4320 if (nType & 256 || nType & 512) 4321 xBox->set_default_response(BasicResponse::Cancel); 4322 else 4323 xBox->set_default_response(BasicResponse::Retry); 4324 4325 break; 4326 } 4327 4328 xBox->set_title(aTitle); 4329 sal_Int16 nRet = xBox->run(); 4330 rPar.Get(0)->PutInteger(nRet); 4331 } 4332 4333 void SbRtl_SetAttr(StarBASIC *, SbxArray & rPar, bool) 4334 { 4335 rPar.Get(0)->PutEmpty(); 4336 if ( rPar.Count() == 3 ) 4337 { 4338 OUString aStr = rPar.Get(1)->GetOUString(); 4339 SbAttributes nFlags = static_cast<SbAttributes>( rPar.Get(2)->GetInteger() ); 4340 4341 if( hasUno() ) 4342 { 4343 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 4344 if( xSFI.is() ) 4345 { 4346 try 4347 { 4348 bool bReadOnly = bool(nFlags & SbAttributes::READONLY); 4349 xSFI->setReadOnly( aStr, bReadOnly ); 4350 bool bHidden = bool(nFlags & SbAttributes::HIDDEN); 4351 xSFI->setHidden( aStr, bHidden ); 4352 } 4353 catch(const Exception & ) 4354 { 4355 StarBASIC::Error( ERRCODE_IO_GENERAL ); 4356 } 4357 } 4358 } 4359 } 4360 else 4361 { 4362 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4363 } 4364 } 4365 4366 void SbRtl_Reset(StarBASIC *, SbxArray &, bool) 4367 { 4368 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem(); 4369 if (pIO) 4370 { 4371 pIO->CloseAll(); 4372 } 4373 } 4374 4375 void SbRtl_DumpAllObjects(StarBASIC * pBasic, SbxArray & rPar, bool) 4376 { 4377 sal_uInt16 nArgCount = rPar.Count(); 4378 if( nArgCount < 2 || nArgCount > 3 ) 4379 { 4380 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4381 } 4382 else if( !pBasic ) 4383 { 4384 StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR ); 4385 } 4386 else 4387 { 4388 SbxObject* p = pBasic; 4389 while( p->GetParent() ) 4390 { 4391 p = p->GetParent(); 4392 } 4393 SvFileStream aStrm( rPar.Get( 1 )->GetOUString(), 4394 StreamMode::WRITE | StreamMode::TRUNC ); 4395 p->Dump( aStrm, rPar.Get( 2 )->GetBool() ); 4396 aStrm.Close(); 4397 if( aStrm.GetError() != ERRCODE_NONE ) 4398 { 4399 StarBASIC::Error( ERRCODE_BASIC_IO_ERROR ); 4400 } 4401 } 4402 } 4403 4404 4405 void SbRtl_FileExists(StarBASIC *, SbxArray & rPar, bool) 4406 { 4407 if ( rPar.Count() == 2 ) 4408 { 4409 OUString aStr = rPar.Get(1)->GetOUString(); 4410 bool bExists = false; 4411 4412 if( hasUno() ) 4413 { 4414 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess(); 4415 if( xSFI.is() ) 4416 { 4417 try 4418 { 4419 bExists = xSFI->exists( aStr ); 4420 } 4421 catch(const Exception & ) 4422 { 4423 StarBASIC::Error( ERRCODE_IO_GENERAL ); 4424 } 4425 } 4426 } 4427 else 4428 { 4429 DirectoryItem aItem; 4430 FileBase::RC nRet = DirectoryItem::get( getFullPath( aStr ), aItem ); 4431 bExists = (nRet == FileBase::E_None); 4432 } 4433 rPar.Get(0)->PutBool( bExists ); 4434 } 4435 else 4436 { 4437 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4438 } 4439 } 4440 4441 void SbRtl_Partition(StarBASIC *, SbxArray & rPar, bool) 4442 { 4443 if ( rPar.Count() != 5 ) 4444 { 4445 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4446 return; 4447 } 4448 4449 sal_Int32 nNumber = rPar.Get(1)->GetLong(); 4450 sal_Int32 nStart = rPar.Get(2)->GetLong(); 4451 sal_Int32 nStop = rPar.Get(3)->GetLong(); 4452 sal_Int32 nInterval = rPar.Get(4)->GetLong(); 4453 4454 if( nStart < 0 || nStop <= nStart || nInterval < 1 ) 4455 { 4456 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4457 return; 4458 } 4459 4460 // the Partition function inserts leading spaces before lowervalue and uppervalue 4461 // so that they both have the same number of characters as the string 4462 // representation of the value (Stop + 1). This ensures that if you use the output 4463 // of the Partition function with several values of Number, the resulting text 4464 // will be handled properly during any subsequent sort operation. 4465 4466 // calculate the maximun number of characters before lowervalue and uppervalue 4467 OUString aBeforeStart = OUString::number( nStart - 1 ); 4468 OUString aAfterStop = OUString::number( nStop + 1 ); 4469 sal_Int32 nLen1 = aBeforeStart.getLength(); 4470 sal_Int32 nLen2 = aAfterStop.getLength(); 4471 sal_Int32 nLen = nLen1 >= nLen2 ? nLen1:nLen2; 4472 4473 OUStringBuffer aRetStr( nLen * 2 + 1); 4474 OUString aLowerValue; 4475 OUString aUpperValue; 4476 if( nNumber < nStart ) 4477 { 4478 aUpperValue = aBeforeStart; 4479 } 4480 else if( nNumber > nStop ) 4481 { 4482 aLowerValue = aAfterStop; 4483 } 4484 else 4485 { 4486 sal_Int32 nLowerValue = nNumber; 4487 sal_Int32 nUpperValue = nLowerValue; 4488 if( nInterval > 1 ) 4489 { 4490 nLowerValue = ((( nNumber - nStart ) / nInterval ) * nInterval ) + nStart; 4491 nUpperValue = nLowerValue + nInterval - 1; 4492 } 4493 aLowerValue = OUString::number( nLowerValue ); 4494 aUpperValue = OUString::number( nUpperValue ); 4495 } 4496 4497 nLen1 = aLowerValue.getLength(); 4498 nLen2 = aUpperValue.getLength(); 4499 4500 if( nLen > nLen1 ) 4501 { 4502 // appending the leading spaces for the lowervalue 4503 for ( sal_Int32 i= (nLen - nLen1) ; i > 0; --i ) 4504 { 4505 aRetStr.append(" "); 4506 } 4507 } 4508 aRetStr.append( aLowerValue ).append(":"); 4509 if( nLen > nLen2 ) 4510 { 4511 // appending the leading spaces for the uppervalue 4512 for ( sal_Int32 i= (nLen - nLen2) ; i > 0; --i ) 4513 { 4514 aRetStr.append(" "); 4515 } 4516 } 4517 aRetStr.append( aUpperValue ); 4518 rPar.Get(0)->PutString( aRetStr.makeStringAndClear()); 4519 } 4520 4521 #endif 4522 4523 static long GetDayDiff( const Date& rDate ) 4524 { 4525 Date aRefDate( 1,1,1900 ); 4526 long nDiffDays; 4527 if ( aRefDate > rDate ) 4528 { 4529 nDiffDays = aRefDate - rDate; 4530 nDiffDays *= -1; 4531 } 4532 else 4533 { 4534 nDiffDays = rDate - aRefDate; 4535 } 4536 nDiffDays += 2; // adjustment VisualBasic: 1.Jan.1900 == 2 4537 return nDiffDays; 4538 } 4539 4540 sal_Int16 implGetDateYear( double aDate ) 4541 { 4542 Date aRefDate( 1,1,1900 ); 4543 long nDays = static_cast<long>(aDate); 4544 nDays -= 2; // standardize: 1.1.1900 => 0.0 4545 aRefDate.AddDays( nDays ); 4546 sal_Int16 nRet = aRefDate.GetYear(); 4547 return nRet; 4548 } 4549 4550 bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, 4551 bool bUseTwoDigitYear, SbDateCorrection eCorr, double& rdRet ) 4552 { 4553 // XXX NOTE: For VBA years<0 are invalid and years in the range 0..29 and 4554 // 30..99 can not be input as they are 2-digit for 2000..2029 and 4555 // 1930..1999, VBA mode overrides bUseTwoDigitYear (as if that was always 4556 // true). For VBA years > 9999 are invalid. 4557 // For StarBASIC, if bUseTwoDigitYear==true then years in the range 0..99 4558 // can not be input as they are 2-digit for 1900..1999, years<0 are 4559 // accepted. If bUseTwoDigitYear==false then all years are accepted, but 4560 // year 0 is invalid (last day BCE -0001-12-31, first day CE 0001-01-01). 4561 #if HAVE_FEATURE_SCRIPTING 4562 if ( (nYear < 0 || 9999 < nYear) && SbiRuntime::isVBAEnabled() ) 4563 { 4564 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4565 return false; 4566 } 4567 else if ( nYear < 30 && SbiRuntime::isVBAEnabled() ) 4568 { 4569 nYear += 2000; 4570 } 4571 else 4572 #endif 4573 { 4574 if ( 0 <= nYear && nYear < 100 && (bUseTwoDigitYear 4575 #if HAVE_FEATURE_SCRIPTING 4576 || SbiRuntime::isVBAEnabled() 4577 #endif 4578 ) ) 4579 { 4580 nYear += 1900; 4581 } 4582 } 4583 4584 sal_Int32 nAddMonths = 0; 4585 sal_Int32 nAddDays = 0; 4586 // Always sanitize values to set date and to use for validity detection. 4587 if (nMonth < 1 || 12 < nMonth) 4588 { 4589 sal_Int16 nM = ((nMonth < 1) ? (12 + (nMonth % 12)) : (nMonth % 12)); 4590 nAddMonths = nMonth - nM; 4591 nMonth = nM; 4592 } 4593 // Day 0 would already be normalized during Date::Normalize(), include 4594 // it in negative days, also to detect non-validity. The actual day of 4595 // month is 1+(nDay-1) 4596 if (nDay < 1) 4597 { 4598 nAddDays = nDay - 1; 4599 nDay = 1; 4600 } 4601 else if (nDay > 31) 4602 { 4603 nAddDays = nDay - 31; 4604 nDay = 31; 4605 } 4606 4607 Date aCurDate( nDay, nMonth, nYear ); 4608 4609 /* TODO: we could enable the same rollover mechanism for StarBASIC to be 4610 * compatible with VBA (just with our wider supported date range), then 4611 * documentation would need to be adapted. As is, the DateSerial() runtime 4612 * function works as dumb as documented.. (except that the resulting date 4613 * is checked for validity now and not just day<=31 and month<=12). 4614 * If change wanted then simply remove overriding RollOver here and adapt 4615 * documentation.*/ 4616 #if HAVE_FEATURE_SCRIPTING 4617 if (eCorr == SbDateCorrection::RollOver && !SbiRuntime::isVBAEnabled()) 4618 eCorr = SbDateCorrection::None; 4619 #endif 4620 4621 if (nYear == 0 || (eCorr == SbDateCorrection::None && (nAddMonths || nAddDays || !aCurDate.IsValidDate()))) 4622 { 4623 #if HAVE_FEATURE_SCRIPTING 4624 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 4625 #endif 4626 return false; 4627 } 4628 4629 if (eCorr != SbDateCorrection::None) 4630 { 4631 aCurDate.Normalize(); 4632 if (nAddMonths) 4633 aCurDate.AddMonths( nAddMonths); 4634 if (nAddDays) 4635 aCurDate.AddDays( nAddDays); 4636 if (eCorr == SbDateCorrection::TruncateToMonth && aCurDate.GetMonth() != nMonth) 4637 { 4638 if (aCurDate.GetYear() == SAL_MAX_INT16 && nMonth == 12) 4639 { 4640 // Roll over and back not possible, hard max. 4641 aCurDate.SetMonth(12); 4642 aCurDate.SetDay(31); 4643 } 4644 else 4645 { 4646 aCurDate.SetMonth(nMonth); 4647 aCurDate.SetDay(1); 4648 aCurDate.AddMonths(1); 4649 aCurDate.AddDays(-1); 4650 } 4651 } 4652 } 4653 4654 long nDiffDays = GetDayDiff( aCurDate ); 4655 rdRet = static_cast<double>(nDiffDays); 4656 return true; 4657 } 4658 4659 double implTimeSerial( sal_Int16 nHours, sal_Int16 nMinutes, sal_Int16 nSeconds ) 4660 { 4661 return 4662 static_cast<double>( nHours * ::tools::Time::secondPerHour + 4663 nMinutes * ::tools::Time::secondPerMinute + 4664 nSeconds) 4665 / 4666 static_cast<double>( ::tools::Time::secondPerDay ); 4667 } 4668 4669 bool implDateTimeSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, 4670 sal_Int16 nHour, sal_Int16 nMinute, sal_Int16 nSecond, 4671 double& rdRet ) 4672 { 4673 double dDate; 4674 if(!implDateSerial(nYear, nMonth, nDay, false/*bUseTwoDigitYear*/, SbDateCorrection::None, dDate)) 4675 return false; 4676 rdRet += dDate + implTimeSerial(nHour, nMinute, nSecond); 4677 return true; 4678 } 4679 4680 sal_Int16 implGetMinute( double dDate ) 4681 { 4682 double nFrac = dDate - floor( dDate ); 4683 nFrac *= 86400.0; 4684 sal_Int32 nSeconds = static_cast<sal_Int32>(nFrac + 0.5); 4685 sal_Int16 nTemp = static_cast<sal_Int16>(nSeconds % 3600); 4686 sal_Int16 nMin = nTemp / 60; 4687 return nMin; 4688 } 4689 4690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 4691
