bump product version to 5.0.4.1
[LibreOffice.git] / basic / source / runtime / methods.cxx
bloba2bb3467e015690836107a6f42db152681896f60
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
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/msgbox.hxx>
32 #include <basic/sbx.hxx>
33 #include <svl/zforlist.hxx>
34 #include <rtl/math.hxx>
35 #include <tools/urlobj.hxx>
36 #include <osl/time.h>
37 #include <unotools/charclass.hxx>
38 #include <unotools/ucbstreamhelper.hxx>
39 #include <tools/wldcrd.hxx>
40 #include <i18nlangtag/lang.h>
41 #include <rtl/string.hxx>
42 #include <rtl/strbuf.hxx>
44 #include "runtime.hxx"
45 #include "sbunoobj.hxx"
46 #include <osl/file.hxx>
47 #include "errobject.hxx"
49 #include <comphelper/processfactory.hxx>
50 #include <comphelper/string.hxx>
52 #include <com/sun/star/uno/Sequence.hxx>
53 #include <com/sun/star/util/DateTime.hpp>
54 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
55 #include <com/sun/star/lang/Locale.hpp>
56 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
57 #include <com/sun/star/script/XErrorQuery.hpp>
58 #include <ooo/vba/XHelperInterface.hpp>
59 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
60 #include <boost/scoped_array.hpp>
61 #include <boost/scoped_ptr.hpp>
63 #include <random>
65 using namespace comphelper;
66 using namespace osl;
67 using namespace com::sun::star;
68 using namespace com::sun::star::lang;
69 using namespace com::sun::star::uno;
71 #include "date.hxx"
72 #include "stdobj.hxx"
73 #include "sbstdobj.hxx"
74 #include "rtlproto.hxx"
75 #include "basrid.hxx"
76 #include "image.hxx"
77 #include "sb.hrc"
78 #include "iosys.hxx"
79 #include "ddectrl.hxx"
80 #include <sbintern.hxx>
81 #include <basic/vbahelper.hxx>
83 #include <list>
84 #include <math.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <ctype.h>
88 #include <errno.h>
90 #include "sbobjmod.hxx"
91 #include "sbxmod.hxx"
93 #ifdef WNT
94 #include <prewin.h>
95 #include <direct.h>
96 #include <io.h>
97 #include <postwin.h>
98 #endif
100 #if HAVE_FEATURE_SCRIPTING
102 static void FilterWhiteSpace( OUString& rStr )
104 if (rStr.isEmpty())
106 return;
108 OUStringBuffer aRet;
110 for (sal_Int32 i = 0; i < rStr.getLength(); ++i)
112 sal_Unicode cChar = rStr[i];
113 if ((cChar != ' ') && (cChar != '\t') &&
114 (cChar != '\n') && (cChar != '\r'))
116 aRet.append(cChar);
120 rStr = aRet.makeStringAndClear();
123 static long GetDayDiff( const Date& rDate );
125 static const CharClass& GetCharClass()
127 static bool bNeedsInit = true;
128 static LanguageTag aLanguageTag( LANGUAGE_SYSTEM);
129 if( bNeedsInit )
131 bNeedsInit = false;
132 aLanguageTag = Application::GetSettings().GetLanguageTag();
134 static CharClass aCharClass( aLanguageTag );
135 return aCharClass;
138 static inline bool isFolder( FileStatus::Type aType )
140 return ( aType == FileStatus::Directory || aType == FileStatus::Volume );
144 //*** UCB file access ***
146 // Converts possibly relative paths to absolute paths
147 // according to the setting done by ChDir/ChDrive
148 OUString getFullPath( const OUString& aRelPath )
150 OUString aFileURL;
152 // #80204 Try first if it already is a valid URL
153 INetURLObject aURLObj( aRelPath );
154 aFileURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE );
156 if( aFileURL.isEmpty() )
158 File::getFileURLFromSystemPath( aRelPath, aFileURL );
161 return aFileURL;
164 // TODO: -> SbiGlobals
165 static uno::Reference< ucb::XSimpleFileAccess3 > getFileAccess()
167 static uno::Reference< ucb::XSimpleFileAccess3 > xSFI;
168 if( !xSFI.is() )
170 xSFI = ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
172 return xSFI;
177 // Properties and methods lie down the return value at the Get (bPut = sal_False) in the
178 // element 0 of the Argv; the value of element 0 is saved at Put (bPut = sal_True)
180 // CreateObject( class )
182 RTLFUNC(CreateObject)
184 (void)bWrite;
186 OUString aClass( rPar.Get( 1 )->GetOUString() );
187 SbxObjectRef p = SbxBase::CreateObject( aClass );
188 if( !p )
189 StarBASIC::Error( SbERR_CANNOT_LOAD );
190 else
192 // Convenience: enter BASIC as parent
193 p->SetParent( pBasic );
194 rPar.Get( 0 )->PutObject( p );
198 // Error( n )
200 RTLFUNC(Error)
202 (void)bWrite;
204 if( !pBasic )
205 StarBASIC::Error( SbERR_INTERNAL_ERROR );
206 else
208 OUString aErrorMsg;
209 SbError nErr = 0L;
210 sal_Int32 nCode = 0;
211 if( rPar.Count() == 1 )
213 nErr = StarBASIC::GetErrBasic();
214 aErrorMsg = StarBASIC::GetErrorMsg();
216 else
218 nCode = rPar.Get( 1 )->GetLong();
219 if( nCode > 65535L )
221 StarBASIC::Error( SbERR_CONVERSION );
223 else
225 nErr = StarBASIC::GetSfxFromVBError( (sal_uInt16)nCode );
229 bool bVBA = SbiRuntime::isVBAEnabled();
230 OUString tmpErrMsg;
231 if( bVBA && !aErrorMsg.isEmpty())
233 tmpErrMsg = aErrorMsg;
235 else
237 StarBASIC::MakeErrorText( nErr, aErrorMsg );
238 tmpErrMsg = StarBASIC::GetErrorText();
240 // If this rtlfunc 'Error' passed a errcode the same as the active Err Objects's
241 // current err then return the description for the error message if it is set
242 // ( complicated isn't it ? )
243 if ( bVBA && rPar.Count() > 1 )
245 uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() );
246 if ( xErrObj.is() && xErrObj->getNumber() == nCode && !xErrObj->getDescription().isEmpty() )
248 tmpErrMsg = xErrObj->getDescription();
251 rPar.Get( 0 )->PutString( tmpErrMsg );
255 // Sinus
257 RTLFUNC(Sin)
259 (void)pBasic;
260 (void)bWrite;
262 if ( rPar.Count() < 2 )
263 StarBASIC::Error( SbERR_BAD_ARGUMENT );
264 else
266 SbxVariableRef pArg = rPar.Get( 1 );
267 rPar.Get( 0 )->PutDouble( sin( pArg->GetDouble() ) );
272 RTLFUNC(Cos)
274 (void)pBasic;
275 (void)bWrite;
277 if ( rPar.Count() < 2 )
278 StarBASIC::Error( SbERR_BAD_ARGUMENT );
279 else
281 SbxVariableRef pArg = rPar.Get( 1 );
282 rPar.Get( 0 )->PutDouble( cos( pArg->GetDouble() ) );
287 RTLFUNC(Atn)
289 (void)pBasic;
290 (void)bWrite;
292 if ( rPar.Count() < 2 )
293 StarBASIC::Error( SbERR_BAD_ARGUMENT );
294 else
296 SbxVariableRef pArg = rPar.Get( 1 );
297 rPar.Get( 0 )->PutDouble( atan( pArg->GetDouble() ) );
303 RTLFUNC(Abs)
305 (void)pBasic;
306 (void)bWrite;
308 if ( rPar.Count() < 2 )
310 StarBASIC::Error( SbERR_BAD_ARGUMENT );
312 else
314 SbxVariableRef pArg = rPar.Get( 1 );
315 rPar.Get( 0 )->PutDouble( fabs( pArg->GetDouble() ) );
320 RTLFUNC(Asc)
322 (void)pBasic;
323 (void)bWrite;
325 if ( rPar.Count() < 2 )
327 StarBASIC::Error( SbERR_BAD_ARGUMENT );
329 else
331 SbxVariableRef pArg = rPar.Get( 1 );
332 OUString aStr( pArg->GetOUString() );
333 if ( aStr.isEmpty())
335 StarBASIC::Error( SbERR_BAD_ARGUMENT );
336 rPar.Get(0)->PutEmpty();
338 else
340 sal_Unicode aCh = aStr[0];
341 rPar.Get(0)->PutLong( aCh );
346 void implChr( SbxArray& rPar, bool bChrW )
348 if ( rPar.Count() < 2 )
350 StarBASIC::Error( SbERR_BAD_ARGUMENT );
352 else
354 SbxVariableRef pArg = rPar.Get( 1 );
356 OUString aStr;
357 if( !bChrW && SbiRuntime::isVBAEnabled() )
359 sal_Char c = static_cast<sal_Char>(pArg->GetByte());
360 aStr = OUString(&c, 1, osl_getThreadTextEncoding());
362 else
364 sal_Unicode aCh = static_cast<sal_Unicode>(pArg->GetUShort());
365 aStr = OUString(aCh);
367 rPar.Get(0)->PutString( aStr );
371 RTLFUNC(Chr)
373 (void)pBasic;
374 (void)bWrite;
376 bool bChrW = false;
377 implChr( rPar, bChrW );
380 RTLFUNC(ChrW)
382 (void)pBasic;
383 (void)bWrite;
385 bool bChrW = true;
386 implChr( rPar, bChrW );
389 RTLFUNC(CurDir)
391 (void)pBasic;
392 (void)bWrite;
394 // #57064 Although this function doesn't work with DirEntry, it isn't touched
395 // by the adjustment to virtual URLs, as, using the DirEntry-functionality,
396 // there's no possibility to detect the current one in a way that a virtual URL
397 // could be delivered.
399 #if defined (WNT)
400 int nCurDir = 0; // Current dir // JSM
401 if ( rPar.Count() == 2 )
403 OUString aDrive = rPar.Get(1)->GetOUString();
404 if ( aDrive.getLength() != 1 )
406 StarBASIC::Error( SbERR_BAD_ARGUMENT );
407 return;
409 else
411 nCurDir = (int)aDrive[0];
412 if ( !isalpha( nCurDir ) )
414 StarBASIC::Error( SbERR_BAD_ARGUMENT );
415 return;
417 else
419 nCurDir -= ( 'A' - 1 );
423 char* pBuffer = new char[ _MAX_PATH ];
424 if ( _getdcwd( nCurDir, pBuffer, _MAX_PATH ) != 0 )
426 rPar.Get(0)->PutString( OUString::createFromAscii( pBuffer ) );
428 else
430 StarBASIC::Error( SbERR_NO_DEVICE );
432 delete [] pBuffer;
434 #else
436 const int PATH_INCR = 250;
438 int nSize = PATH_INCR;
439 boost::scoped_array<char> pMem;
440 while( true )
442 pMem.reset(new char[nSize]);
443 if( !pMem )
445 StarBASIC::Error( SbERR_NO_MEMORY );
446 return;
448 if( getcwd( pMem.get(), nSize-1 ) != NULL )
450 rPar.Get(0)->PutString( OUString::createFromAscii(pMem.get()) );
451 return;
453 if( errno != ERANGE )
455 StarBASIC::Error( SbERR_INTERNAL_ERROR );
456 return;
458 nSize += PATH_INCR;
461 #endif
464 RTLFUNC(ChDir)
466 (void)bWrite;
468 rPar.Get(0)->PutEmpty();
469 if (rPar.Count() == 2)
471 // VBA: track current directory per document type (separately for Writer, Calc, Impress, etc.)
472 if( SbiRuntime::isVBAEnabled() )
474 ::basic::vba::registerCurrentDirectory( getDocumentModel( pBasic ), rPar.Get(1)->GetOUString() );
477 else
479 StarBASIC::Error( SbERR_BAD_ARGUMENT );
483 RTLFUNC(ChDrive)
485 (void)pBasic;
486 (void)bWrite;
488 rPar.Get(0)->PutEmpty();
489 if (rPar.Count() != 2)
491 StarBASIC::Error( SbERR_BAD_ARGUMENT );
496 // Implementation of StepRENAME with UCB
497 void implStepRenameUCB( const OUString& aSource, const OUString& aDest )
499 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
500 if( xSFI.is() )
504 OUString aSourceFullPath = getFullPath( aSource );
505 if( !xSFI->exists( aSourceFullPath ) )
507 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
508 return;
511 OUString aDestFullPath = getFullPath( aDest );
512 if( xSFI->exists( aDestFullPath ) )
514 StarBASIC::Error( SbERR_FILE_EXISTS );
516 else
518 xSFI->move( aSourceFullPath, aDestFullPath );
521 catch(const Exception & )
523 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
528 // Implementation of StepRENAME with OSL
529 void implStepRenameOSL( const OUString& aSource, const OUString& aDest )
531 FileBase::RC nRet = File::move( getFullPath( aSource ), getFullPath( aDest ) );
532 if( nRet != FileBase::E_None )
534 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
538 RTLFUNC(FileCopy)
540 (void)pBasic;
541 (void)bWrite;
543 rPar.Get(0)->PutEmpty();
544 if (rPar.Count() == 3)
546 OUString aSource = rPar.Get(1)->GetOUString();
547 OUString aDest = rPar.Get(2)->GetOUString();
548 if( hasUno() )
550 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
551 if( xSFI.is() )
555 xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) );
557 catch(const Exception & )
559 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
563 else
565 FileBase::RC nRet = File::copy( getFullPath( aSource ), getFullPath( aDest ) );
566 if( nRet != FileBase::E_None )
568 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
572 else
573 StarBASIC::Error( SbERR_BAD_ARGUMENT );
576 RTLFUNC(Kill)
578 (void)pBasic;
579 (void)bWrite;
581 rPar.Get(0)->PutEmpty();
582 if (rPar.Count() == 2)
584 OUString aFileSpec = rPar.Get(1)->GetOUString();
586 if( hasUno() )
588 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
589 if( xSFI.is() )
591 OUString aFullPath = getFullPath( aFileSpec );
592 if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) )
594 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
595 return;
599 xSFI->kill( aFullPath );
601 catch(const Exception & )
603 StarBASIC::Error( ERRCODE_IO_GENERAL );
607 else
609 File::remove( getFullPath( aFileSpec ) );
612 else
614 StarBASIC::Error( SbERR_BAD_ARGUMENT );
618 RTLFUNC(MkDir)
620 (void)pBasic;
621 (void)bWrite;
623 rPar.Get(0)->PutEmpty();
624 if (rPar.Count() == 2)
626 OUString aPath = rPar.Get(1)->GetOUString();
627 if ( SbiRuntime::isVBAEnabled() )
629 // In vba if the full path is not specified then
630 // folder is created relative to the curdir
631 INetURLObject aURLObj( getFullPath( aPath ) );
632 if ( aURLObj.GetProtocol() != INetProtocol::File )
634 SbxArrayRef pPar = new SbxArray();
635 SbxVariableRef pResult = new SbxVariable();
636 SbxVariableRef pParam = new SbxVariable();
637 pPar->Insert( pResult, pPar->Count() );
638 pPar->Insert( pParam, pPar->Count() );
639 SbRtl_CurDir( pBasic, *pPar, bWrite );
641 rtl::OUString sCurPathURL;
642 File::getFileURLFromSystemPath( pPar->Get(0)->GetOUString(), sCurPathURL );
644 aURLObj.SetURL( sCurPathURL );
645 aURLObj.Append( aPath );
646 File::getSystemPathFromFileURL(aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI ),aPath ) ;
650 if( hasUno() )
652 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
653 if( xSFI.is() )
657 xSFI->createFolder( getFullPath( aPath ) );
659 catch(const Exception & )
661 StarBASIC::Error( ERRCODE_IO_GENERAL );
665 else
667 Directory::create( getFullPath( aPath ) );
670 else
672 StarBASIC::Error( SbERR_BAD_ARGUMENT );
677 // In OSL only empty directories can be deleted
678 // so we have to delete all files recursively
679 void implRemoveDirRecursive( const OUString& aDirPath )
681 DirectoryItem aItem;
682 FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem );
683 bool bExists = (nRet == FileBase::E_None);
685 FileStatus aFileStatus( osl_FileStatus_Mask_Type );
686 nRet = aItem.getFileStatus( aFileStatus );
687 FileStatus::Type aType = aFileStatus.getFileType();
688 bool bFolder = isFolder( aType );
690 if( !bExists || !bFolder )
692 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
693 return;
696 Directory aDir( aDirPath );
697 nRet = aDir.open();
698 if( nRet != FileBase::E_None )
700 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
701 return;
704 for( ;; )
706 DirectoryItem aItem2;
707 nRet = aDir.getNextItem( aItem2 );
708 if( nRet != FileBase::E_None )
710 break;
712 // Handle flags
713 FileStatus aFileStatus2( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL );
714 nRet = aItem2.getFileStatus( aFileStatus2 );
715 OUString aPath = aFileStatus2.getFileURL();
717 // Directory?
718 FileStatus::Type aType2 = aFileStatus2.getFileType();
719 bool bFolder2 = isFolder( aType2 );
720 if( bFolder2 )
722 implRemoveDirRecursive( aPath );
724 else
726 File::remove( aPath );
729 nRet = aDir.close();
731 nRet = Directory::remove( aDirPath );
735 RTLFUNC(RmDir)
737 (void)pBasic;
738 (void)bWrite;
740 rPar.Get(0)->PutEmpty();
741 if (rPar.Count() == 2)
743 OUString aPath = rPar.Get(1)->GetOUString();
744 if( hasUno() )
746 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
747 if( xSFI.is() )
751 if( !xSFI->isFolder( aPath ) )
753 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
754 return;
756 SbiInstance* pInst = GetSbData()->pInst;
757 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
758 if( bCompatibility )
760 Sequence< OUString > aContent = xSFI->getFolderContents( aPath, true );
761 sal_Int32 nCount = aContent.getLength();
762 if( nCount > 0 )
764 StarBASIC::Error( SbERR_ACCESS_ERROR );
765 return;
769 xSFI->kill( getFullPath( aPath ) );
771 catch(const Exception & )
773 StarBASIC::Error( ERRCODE_IO_GENERAL );
777 else
779 implRemoveDirRecursive( getFullPath( aPath ) );
782 else
784 StarBASIC::Error( SbERR_BAD_ARGUMENT );
788 RTLFUNC(SendKeys)
790 (void)pBasic;
791 (void)bWrite;
793 rPar.Get(0)->PutEmpty();
794 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
797 RTLFUNC(Exp)
799 (void)pBasic;
800 (void)bWrite;
802 if( rPar.Count() < 2 )
803 StarBASIC::Error( SbERR_BAD_ARGUMENT );
804 else
806 double aDouble = rPar.Get( 1 )->GetDouble();
807 aDouble = exp( aDouble );
808 checkArithmeticOverflow( aDouble );
809 rPar.Get( 0 )->PutDouble( aDouble );
813 RTLFUNC(FileLen)
815 (void)pBasic;
816 (void)bWrite;
818 if ( rPar.Count() < 2 )
820 StarBASIC::Error( SbERR_BAD_ARGUMENT );
822 else
824 SbxVariableRef pArg = rPar.Get( 1 );
825 OUString aStr( pArg->GetOUString() );
826 sal_Int32 nLen = 0;
827 if( hasUno() )
829 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
830 if( xSFI.is() )
834 nLen = xSFI->getSize( getFullPath( aStr ) );
836 catch(const Exception & )
838 StarBASIC::Error( ERRCODE_IO_GENERAL );
842 else
844 DirectoryItem aItem;
845 DirectoryItem::get( getFullPath( aStr ), aItem );
846 FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
847 aItem.getFileStatus( aFileStatus );
848 nLen = (sal_Int32)aFileStatus.getFileSize();
850 rPar.Get(0)->PutLong( (long)nLen );
855 RTLFUNC(Hex)
857 (void)pBasic;
858 (void)bWrite;
860 if ( rPar.Count() < 2 )
862 StarBASIC::Error( SbERR_BAD_ARGUMENT );
864 else
866 SbxVariableRef pArg = rPar.Get( 1 );
867 // converting value to unsigned and limit to 2 or 4 byte representation
868 sal_uInt32 nVal = pArg->IsInteger() ?
869 static_cast<sal_uInt16>(pArg->GetInteger()) :
870 static_cast<sal_uInt32>(pArg->GetLong());
871 OUString aStr(OUString::number( nVal, 16 ));
872 aStr = aStr.toAsciiUpperCase();
873 rPar.Get(0)->PutString( aStr );
877 RTLFUNC(FuncCaller)
879 (void)pBasic;
880 (void)bWrite;
881 if ( SbiRuntime::isVBAEnabled() && GetSbData()->pInst && GetSbData()->pInst->pRun )
883 if ( GetSbData()->pInst->pRun->GetExternalCaller() )
884 *rPar.Get(0) = *GetSbData()->pInst->pRun->GetExternalCaller();
885 else
887 SbxVariableRef pVar = new SbxVariable(SbxVARIANT);
888 *rPar.Get(0) = *pVar;
891 else
893 StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
897 // InStr( [start],string,string,[compare] )
899 RTLFUNC(InStr)
901 (void)pBasic;
902 (void)bWrite;
904 sal_Size nArgCount = rPar.Count()-1;
905 if ( nArgCount < 2 )
906 StarBASIC::Error( SbERR_BAD_ARGUMENT );
907 else
909 sal_Int32 nStartPos = 1;
910 sal_Int32 nFirstStringPos = 1;
912 if ( nArgCount >= 3 )
914 nStartPos = rPar.Get(1)->GetLong();
915 if( nStartPos <= 0 )
917 StarBASIC::Error( SbERR_BAD_ARGUMENT );
918 nStartPos = 1;
920 nFirstStringPos++;
923 SbiInstance* pInst = GetSbData()->pInst;
924 int bTextMode;
925 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
926 if( bCompatibility )
928 SbiRuntime* pRT = pInst->pRun;
929 bTextMode = pRT ? pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ) : sal_False;
931 else
933 bTextMode = 1;;
935 if ( nArgCount == 4 )
937 bTextMode = rPar.Get(4)->GetInteger();
939 sal_Int32 nPos;
940 const OUString& rToken = rPar.Get(nFirstStringPos+1)->GetOUString();
942 // #97545 Always find empty string
943 if( rToken.isEmpty() )
945 nPos = nStartPos;
947 else
949 if( !bTextMode )
951 const OUString& rStr1 = rPar.Get(nFirstStringPos)->GetOUString();
952 nPos = rStr1.indexOf( rToken, nStartPos - 1 ) + 1;
954 else
956 OUString aStr1 = rPar.Get(nFirstStringPos)->GetOUString();
957 OUString aToken = rToken;
959 aStr1 = aStr1.toAsciiUpperCase();
960 aToken = aToken.toAsciiUpperCase();
962 nPos = aStr1.indexOf( aToken, nStartPos-1 ) + 1;
965 rPar.Get(0)->PutLong( nPos );
970 // InstrRev(string1, string2[, start[, compare]])
972 RTLFUNC(InStrRev)
974 (void)pBasic;
975 (void)bWrite;
977 sal_Size nArgCount = rPar.Count()-1;
978 if ( nArgCount < 2 )
980 StarBASIC::Error( SbERR_BAD_ARGUMENT );
982 else
984 OUString aStr1 = rPar.Get(1)->GetOUString();
985 OUString aToken = rPar.Get(2)->GetOUString();
987 sal_Int32 nStartPos = -1;
988 if ( nArgCount >= 3 )
990 nStartPos = rPar.Get(3)->GetLong();
991 if( (nStartPos <= 0 && nStartPos != -1))
993 StarBASIC::Error( SbERR_BAD_ARGUMENT );
994 nStartPos = -1;
998 SbiInstance* pInst = GetSbData()->pInst;
999 int bTextMode;
1000 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1001 if( bCompatibility )
1003 SbiRuntime* pRT = pInst->pRun;
1004 bTextMode = pRT ? pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ) : sal_False;
1006 else
1008 bTextMode = 1;;
1010 if ( nArgCount == 4 )
1012 bTextMode = rPar.Get(4)->GetInteger();
1014 sal_Int32 nStrLen = aStr1.getLength();
1015 if( nStartPos == -1 )
1017 nStartPos = nStrLen;
1020 sal_Int32 nPos = 0;
1021 if( nStartPos <= nStrLen )
1023 sal_Int32 nTokenLen = aToken.getLength();
1024 if( !nTokenLen )
1026 // Always find empty string
1027 nPos = nStartPos;
1029 else if( nStrLen > 0 )
1031 if( !bTextMode )
1033 nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1;
1035 else
1037 aStr1 = aStr1.toAsciiUpperCase();
1038 aToken = aToken.toAsciiUpperCase();
1040 nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1;
1044 rPar.Get(0)->PutLong( nPos );
1050 Int( 2.8 ) = 2.0
1051 Int( -2.8 ) = -3.0
1052 Fix( 2.8 ) = 2.0
1053 Fix( -2.8 ) = -2.0 <- !!
1056 RTLFUNC(Int)
1058 (void)pBasic;
1059 (void)bWrite;
1061 if ( rPar.Count() < 2 )
1062 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1063 else
1065 SbxVariableRef pArg = rPar.Get( 1 );
1066 double aDouble= pArg->GetDouble();
1068 floor( 2.8 ) = 2.0
1069 floor( -2.8 ) = -3.0
1071 aDouble = floor( aDouble );
1072 rPar.Get(0)->PutDouble( aDouble );
1078 RTLFUNC(Fix)
1080 (void)pBasic;
1081 (void)bWrite;
1083 if ( rPar.Count() < 2 )
1084 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1085 else
1087 SbxVariableRef pArg = rPar.Get( 1 );
1088 double aDouble = pArg->GetDouble();
1089 if ( aDouble >= 0.0 )
1090 aDouble = floor( aDouble );
1091 else
1092 aDouble = ceil( aDouble );
1093 rPar.Get(0)->PutDouble( aDouble );
1098 RTLFUNC(LCase)
1100 (void)pBasic;
1101 (void)bWrite;
1103 if ( rPar.Count() < 2 )
1105 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1107 else
1109 const CharClass& rCharClass = GetCharClass();
1110 OUString aStr( rPar.Get(1)->GetOUString() );
1111 aStr = rCharClass.lowercase(aStr);
1112 rPar.Get(0)->PutString( aStr );
1116 RTLFUNC(Left)
1118 (void)pBasic;
1119 (void)bWrite;
1121 if ( rPar.Count() < 3 )
1123 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1125 else
1127 OUString aStr( rPar.Get(1)->GetOUString() );
1128 sal_Int32 nResultLen = rPar.Get(2)->GetLong();
1129 if( nResultLen < 0 )
1131 nResultLen = 0;
1132 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1134 else if(nResultLen > aStr.getLength())
1136 nResultLen = aStr.getLength();
1138 aStr = aStr.copy(0, nResultLen );
1139 rPar.Get(0)->PutString( aStr );
1143 RTLFUNC(Log)
1145 (void)pBasic;
1146 (void)bWrite;
1148 if ( rPar.Count() < 2 )
1150 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1152 else
1154 double aArg = rPar.Get(1)->GetDouble();
1155 if ( aArg > 0 )
1157 double d = log( aArg );
1158 checkArithmeticOverflow( d );
1159 rPar.Get( 0 )->PutDouble( d );
1161 else
1163 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1168 RTLFUNC(LTrim)
1170 (void)pBasic;
1171 (void)bWrite;
1173 if ( rPar.Count() < 2 )
1175 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1177 else
1179 OUString aStr(comphelper::string::stripStart(rPar.Get(1)->GetOUString(), ' '));
1180 rPar.Get(0)->PutString(aStr);
1185 // Mid( String, nStart, nLength )
1187 RTLFUNC(Mid)
1189 (void)pBasic;
1190 (void)bWrite;
1192 int nArgCount = rPar.Count()-1;
1193 if ( nArgCount < 2 )
1195 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1197 else
1199 // #23178: replicate the functionality of Mid$ as a command
1200 // by adding a replacement-string as a fourth parameter.
1201 // In contrast to the original the third parameter (nLength)
1202 // can't be left out here. That's considered in bWrite already.
1203 if( nArgCount == 4 )
1205 bWrite = true;
1207 OUString aArgStr = rPar.Get(1)->GetOUString();
1208 sal_Int32 nStartPos = rPar.Get(2)->GetLong();
1209 if ( nStartPos < 1 )
1211 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1213 else
1215 nStartPos--;
1216 sal_Int32 nLen = -1;
1217 bool bWriteNoLenParam = false;
1218 if ( nArgCount == 3 || bWrite )
1220 sal_Int32 n = rPar.Get(3)->GetLong();
1221 if( bWrite && n == -1 )
1223 bWriteNoLenParam = true;
1225 nLen = n;
1227 if ( bWrite )
1229 OUStringBuffer aResultStr;
1230 SbiInstance* pInst = GetSbData()->pInst;
1231 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1232 if( bCompatibility )
1234 sal_Int32 nArgLen = aArgStr.getLength();
1235 if( nStartPos + 1 > nArgLen )
1237 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1238 return;
1241 OUString aReplaceStr = rPar.Get(4)->GetOUString();
1242 sal_Int32 nReplaceStrLen = aReplaceStr.getLength();
1243 sal_Int32 nReplaceLen;
1244 if( bWriteNoLenParam )
1246 nReplaceLen = nReplaceStrLen;
1248 else
1250 nReplaceLen = nLen;
1251 if( nReplaceLen < 0 || nReplaceLen > nReplaceStrLen )
1253 nReplaceLen = nReplaceStrLen;
1257 sal_Int32 nReplaceEndPos = nStartPos + nReplaceLen;
1258 if( nReplaceEndPos > nArgLen )
1260 nReplaceLen -= (nReplaceEndPos - nArgLen);
1262 aResultStr = aArgStr;
1263 sal_Int32 nErase = nReplaceLen;
1264 aResultStr.remove( nStartPos, nErase );
1265 aResultStr.insert( nStartPos, aReplaceStr.getStr(), nReplaceLen);
1267 else
1269 aResultStr = aArgStr;
1270 sal_Int32 nTmpStartPos = nStartPos;
1271 if ( nTmpStartPos > aArgStr.getLength() )
1272 nTmpStartPos = aArgStr.getLength();
1273 else
1274 aResultStr.remove( nTmpStartPos, nLen );
1275 aResultStr.insert( nTmpStartPos, rPar.Get(4)->GetOUString().getStr(), std::min(nLen, rPar.Get(4)->GetOUString().getLength()));
1278 rPar.Get(1)->PutString( aResultStr.makeStringAndClear() );
1280 else
1282 OUString aResultStr;
1283 if (nStartPos > aArgStr.getLength())
1285 // do nothing
1287 else if(nArgCount == 2)
1289 aResultStr = aArgStr.copy( nStartPos);
1291 else
1293 if (nLen < 0)
1294 nLen = 0;
1295 if(nStartPos + nLen > aArgStr.getLength())
1297 nLen = aArgStr.getLength() - nStartPos;
1299 if (nLen > 0)
1300 aResultStr = aArgStr.copy( nStartPos, nLen );
1302 rPar.Get(0)->PutString( aResultStr );
1308 RTLFUNC(Oct)
1310 (void)pBasic;
1311 (void)bWrite;
1313 if ( rPar.Count() < 2 )
1315 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1317 else
1319 char aBuffer[16];
1320 SbxVariableRef pArg = rPar.Get( 1 );
1321 if ( pArg->IsInteger() )
1323 snprintf( aBuffer, sizeof(aBuffer), "%o", pArg->GetInteger() );
1325 else
1327 snprintf( aBuffer, sizeof(aBuffer), "%lo", static_cast<long unsigned int>(pArg->GetLong()) );
1329 rPar.Get(0)->PutString( OUString::createFromAscii( aBuffer ) );
1333 // Replace(expression, find, replace[, start[, count[, compare]]])
1335 RTLFUNC(Replace)
1337 (void)pBasic;
1338 (void)bWrite;
1340 sal_Size nArgCount = rPar.Count()-1;
1341 if ( nArgCount < 3 || nArgCount > 6 )
1343 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1345 else
1347 OUString aExpStr = rPar.Get(1)->GetOUString();
1348 OUString aFindStr = rPar.Get(2)->GetOUString();
1349 OUString aReplaceStr = rPar.Get(3)->GetOUString();
1351 sal_Int32 lStartPos = 1;
1352 if ( nArgCount >= 4 )
1354 if( rPar.Get(4)->GetType() != SbxEMPTY )
1356 lStartPos = rPar.Get(4)->GetLong();
1358 if( lStartPos < 1)
1360 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1361 lStartPos = 1;
1365 sal_Int32 lCount = -1;
1366 if( nArgCount >=5 )
1368 if( rPar.Get(5)->GetType() != SbxEMPTY )
1370 lCount = rPar.Get(5)->GetLong();
1372 if( lCount < -1)
1374 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1375 lCount = -1;
1379 SbiInstance* pInst = GetSbData()->pInst;
1380 int bTextMode;
1381 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1382 if( bCompatibility )
1384 SbiRuntime* pRT = pInst->pRun;
1385 bTextMode = pRT ? pRT->IsImageFlag( SbiImageFlags::COMPARETEXT ) : sal_False;
1387 else
1389 bTextMode = 1;
1391 if ( nArgCount == 6 )
1393 bTextMode = rPar.Get(6)->GetInteger();
1395 sal_Int32 nExpStrLen = aExpStr.getLength();
1396 sal_Int32 nFindStrLen = aFindStr.getLength();
1397 sal_Int32 nReplaceStrLen = aReplaceStr.getLength();
1399 if( lStartPos <= nExpStrLen )
1401 sal_Int32 nPos = lStartPos - 1;
1402 sal_Int32 nCounts = 0;
1403 while( lCount == -1 || lCount > nCounts )
1405 OUString aSrcStr( aExpStr );
1406 if( bTextMode )
1408 aSrcStr = aSrcStr.toAsciiUpperCase();
1409 aFindStr = aFindStr.toAsciiUpperCase();
1411 nPos = aSrcStr.indexOf( aFindStr, nPos );
1412 if( nPos >= 0 )
1414 aExpStr = aExpStr.replaceAt( nPos, nFindStrLen, aReplaceStr );
1415 nPos = nPos + nReplaceStrLen;
1416 nCounts++;
1418 else
1420 break;
1424 rPar.Get(0)->PutString( aExpStr.copy( lStartPos - 1 ) );
1428 RTLFUNC(Right)
1430 (void)pBasic;
1431 (void)bWrite;
1433 if ( rPar.Count() < 3 )
1435 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1437 else
1439 const OUString& rStr = rPar.Get(1)->GetOUString();
1440 int nResultLen = rPar.Get(2)->GetLong();
1441 if( nResultLen < 0 )
1443 nResultLen = 0;
1444 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1446 int nStrLen = rStr.getLength();
1447 if ( nResultLen > nStrLen )
1449 nResultLen = nStrLen;
1451 OUString aResultStr = rStr.copy( nStrLen - nResultLen );
1452 rPar.Get(0)->PutString( aResultStr );
1456 RTLFUNC(RTL)
1458 (void)pBasic;
1459 (void)bWrite;
1461 rPar.Get( 0 )->PutObject( pBasic->getRTL() );
1464 RTLFUNC(RTrim)
1466 (void)pBasic;
1467 (void)bWrite;
1469 if ( rPar.Count() < 2 )
1471 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1473 else
1475 OUString aStr(comphelper::string::stripEnd(rPar.Get(1)->GetOUString(), ' '));
1476 rPar.Get(0)->PutString(aStr);
1480 RTLFUNC(Sgn)
1482 (void)pBasic;
1483 (void)bWrite;
1485 if ( rPar.Count() < 2 )
1487 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1489 else
1491 double aDouble = rPar.Get(1)->GetDouble();
1492 sal_Int16 nResult = 0;
1493 if ( aDouble > 0 )
1495 nResult = 1;
1497 else if ( aDouble < 0 )
1499 nResult = -1;
1501 rPar.Get(0)->PutInteger( nResult );
1505 RTLFUNC(Space)
1507 (void)pBasic;
1508 (void)bWrite;
1510 if ( rPar.Count() < 2 )
1512 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1514 else
1516 OUStringBuffer aBuf;
1517 string::padToLength(aBuf, rPar.Get(1)->GetLong(), ' ');
1518 rPar.Get(0)->PutString(aBuf.makeStringAndClear());
1522 RTLFUNC(Spc)
1524 (void)pBasic;
1525 (void)bWrite;
1527 if ( rPar.Count() < 2 )
1529 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1531 else
1533 OUStringBuffer aBuf;
1534 string::padToLength(aBuf, rPar.Get(1)->GetLong(), ' ');
1535 rPar.Get(0)->PutString(aBuf.makeStringAndClear());
1539 RTLFUNC(Sqr)
1541 (void)pBasic;
1542 (void)bWrite;
1544 if ( rPar.Count() < 2 )
1546 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1548 else
1550 double aDouble = rPar.Get(1)->GetDouble();
1551 if ( aDouble >= 0 )
1553 rPar.Get(0)->PutDouble( sqrt( aDouble ));
1555 else
1557 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1562 RTLFUNC(Str)
1564 (void)pBasic;
1565 (void)bWrite;
1567 if ( rPar.Count() < 2 )
1569 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1571 else
1573 OUString aStr;
1574 OUString aStrNew("");
1575 SbxVariableRef pArg = rPar.Get( 1 );
1576 pArg->Format( aStr );
1578 // Numbers start with a space
1579 if( pArg->IsNumericRTL() )
1581 // replace commas by points so that it's symmetric to Val!
1582 aStr = aStr.replaceFirst( ",", "." );
1584 SbiInstance* pInst = GetSbData()->pInst;
1585 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1586 if( bCompatibility )
1588 sal_Int32 nLen = aStr.getLength();
1590 const sal_Unicode* pBuf = aStr.getStr();
1592 bool bNeg = ( pBuf[0] == '-' );
1593 sal_Int32 iZeroSearch = 0;
1594 if( bNeg )
1596 aStrNew += "-";
1597 iZeroSearch++;
1599 else
1601 if( pBuf[0] != ' ' )
1603 aStrNew += " ";
1606 sal_Int32 iNext = iZeroSearch + 1;
1607 if( pBuf[iZeroSearch] == '0' && nLen > iNext && pBuf[iNext] == '.' )
1609 iZeroSearch += 1;
1611 aStrNew += aStr.copy(iZeroSearch);
1613 else
1615 aStrNew = " " + aStr;
1618 else
1620 aStrNew = aStr;
1622 rPar.Get(0)->PutString( aStrNew );
1626 RTLFUNC(StrComp)
1628 (void)pBasic;
1629 (void)bWrite;
1631 if ( rPar.Count() < 3 )
1633 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1634 rPar.Get(0)->PutEmpty();
1635 return;
1637 const OUString& rStr1 = rPar.Get(1)->GetOUString();
1638 const OUString& rStr2 = rPar.Get(2)->GetOUString();
1640 SbiInstance* pInst = GetSbData()->pInst;
1641 bool nTextCompare;
1642 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1643 if( bCompatibility )
1645 SbiRuntime* pRT = pInst->pRun;
1646 nTextCompare = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT );
1648 else
1650 nTextCompare = true;
1652 if ( rPar.Count() == 4 )
1653 nTextCompare = rPar.Get(3)->GetInteger();
1655 if( !bCompatibility )
1657 nTextCompare = !nTextCompare;
1659 sal_Int32 nRetValue = 0;
1660 if( nTextCompare )
1662 ::utl::TransliterationWrapper* pTransliterationWrapper = GetSbData()->pTransliterationWrapper;
1663 if( !pTransliterationWrapper )
1665 uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
1666 pTransliterationWrapper = GetSbData()->pTransliterationWrapper =
1667 new ::utl::TransliterationWrapper( xContext,
1668 i18n::TransliterationModules_IGNORE_CASE |
1669 i18n::TransliterationModules_IGNORE_KANA |
1670 i18n::TransliterationModules_IGNORE_WIDTH );
1673 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
1674 pTransliterationWrapper->loadModuleIfNeeded( eLangType );
1675 nRetValue = pTransliterationWrapper->compareString( rStr1, rStr2 );
1677 else
1679 sal_Int32 aResult;
1680 aResult = rStr1.compareTo( rStr2 );
1681 if ( aResult < 0 )
1683 nRetValue = -1;
1685 else if ( aResult > 0)
1687 nRetValue = 1;
1690 rPar.Get(0)->PutInteger( sal::static_int_cast< sal_Int16 >( nRetValue ) );
1693 RTLFUNC(String)
1695 (void)pBasic;
1696 (void)bWrite;
1698 if ( rPar.Count() < 2 )
1700 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1702 else
1704 sal_Unicode aFiller;
1705 sal_Int32 lCount = rPar.Get(1)->GetLong();
1706 if( lCount < 0 || lCount > 0xffff )
1708 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1710 if( rPar.Get(2)->GetType() == SbxINTEGER )
1712 aFiller = (sal_Unicode)rPar.Get(2)->GetInteger();
1714 else
1716 const OUString& rStr = rPar.Get(2)->GetOUString();
1717 aFiller = rStr[0];
1719 OUStringBuffer aBuf(lCount);
1720 string::padToLength(aBuf, lCount, aFiller);
1721 rPar.Get(0)->PutString(aBuf.makeStringAndClear());
1725 RTLFUNC(Tan)
1727 (void)pBasic;
1728 (void)bWrite;
1730 if ( rPar.Count() < 2 )
1732 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1734 else
1736 SbxVariableRef pArg = rPar.Get( 1 );
1737 rPar.Get( 0 )->PutDouble( tan( pArg->GetDouble() ) );
1741 RTLFUNC(UCase)
1743 (void)pBasic;
1744 (void)bWrite;
1746 if ( rPar.Count() < 2 )
1748 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1750 else
1752 const CharClass& rCharClass = GetCharClass();
1753 OUString aStr( rPar.Get(1)->GetOUString() );
1754 aStr = rCharClass.uppercase( aStr );
1755 rPar.Get(0)->PutString( aStr );
1760 RTLFUNC(Val)
1762 (void)pBasic;
1763 (void)bWrite;
1765 if ( rPar.Count() < 2 )
1767 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1769 else
1771 double nResult = 0.0;
1772 char* pEndPtr;
1774 OUString aStr( rPar.Get(1)->GetOUString() );
1776 FilterWhiteSpace( aStr );
1777 if ( aStr[0] == '&' && aStr.getLength() > 1 )
1779 int nRadix = 10;
1780 char aChar = (char)aStr[1];
1781 if ( aChar == 'h' || aChar == 'H' )
1783 nRadix = 16;
1785 else if ( aChar == 'o' || aChar == 'O' )
1787 nRadix = 8;
1789 if ( nRadix != 10 )
1791 OString aByteStr(OUStringToOString(aStr, osl_getThreadTextEncoding()));
1792 sal_Int16 nlResult = (sal_Int16)strtol( aByteStr.getStr()+2, &pEndPtr, nRadix);
1793 nResult = (double)nlResult;
1796 else
1798 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
1799 sal_Int32 nParseEnd = 0;
1800 nResult = ::rtl::math::stringToDouble( aStr, '.', ',', &eStatus, &nParseEnd );
1801 if ( eStatus != rtl_math_ConversionStatus_Ok )
1802 StarBASIC::Error( SbERR_MATH_OVERFLOW );
1803 /* TODO: we should check whether all characters were parsed here,
1804 * but earlier code silently ignored trailing nonsense such as "1x"
1805 * resulting in 1 with the side effect that any alpha-only-string
1806 * like "x" resulted in 0. Not changing that now (2013-03-22) as
1807 * user macros may rely on it. */
1808 #if 0
1809 else if ( nParseEnd != aStr.getLength() )
1810 StarBASIC::Error( SbERR_CONVERSION );
1811 #endif
1814 rPar.Get(0)->PutDouble( nResult );
1819 // Helper functions for date conversion
1820 sal_Int16 implGetDateDay( double aDate )
1822 aDate -= 2.0; // standardize: 1.1.1900 => 0.0
1823 Date aRefDate( 1, 1, 1900 );
1824 if ( aDate >= 0.0 )
1826 aDate = floor( aDate );
1827 aRefDate += static_cast<long>(aDate);
1829 else
1831 aDate = ceil( aDate );
1832 aRefDate -= static_cast<long>(-1.0 * aDate);
1835 sal_Int16 nRet = (sal_Int16)( aRefDate.GetDay() );
1836 return nRet;
1839 sal_Int16 implGetDateMonth( double aDate )
1841 Date aRefDate( 1,1,1900 );
1842 long nDays = (long)aDate;
1843 nDays -= 2; // standardize: 1.1.1900 => 0.0
1844 aRefDate += nDays;
1845 sal_Int16 nRet = (sal_Int16)( aRefDate.GetMonth() );
1846 return nRet;
1849 ::com::sun::star::util::Date SbxDateToUNODate( const SbxValue* const pVal )
1851 double aDate = pVal->GetDate();
1853 com::sun::star::util::Date aUnoDate;
1854 aUnoDate.Day = implGetDateDay ( aDate );
1855 aUnoDate.Month = implGetDateMonth( aDate );
1856 aUnoDate.Year = implGetDateYear ( aDate );
1858 return aUnoDate;
1861 void SbxDateFromUNODate( SbxValue *pVal, const ::com::sun::star::util::Date& aUnoDate)
1863 double dDate;
1864 if( implDateSerial( aUnoDate.Year, aUnoDate.Month, aUnoDate.Day, dDate ) )
1866 pVal->PutDate( dDate );
1870 // Function to convert date to UNO date (com.sun.star.util.Date)
1871 RTLFUNC(CDateToUnoDate)
1873 (void)pBasic;
1874 (void)bWrite;
1876 if ( rPar.Count() != 2 )
1878 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1879 return;
1882 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNODate(rPar.Get(1))));
1885 // Function to convert date from UNO date (com.sun.star.util.Date)
1886 RTLFUNC(CDateFromUnoDate)
1888 (void)pBasic;
1889 (void)bWrite;
1891 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT )
1893 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1894 return;
1897 Any aAny (sbxToUnoValue(rPar.Get(1), cppu::UnoType<com::sun::star::util::Date>::get()));
1898 com::sun::star::util::Date aUnoDate;
1899 if(aAny >>= aUnoDate)
1900 SbxDateFromUNODate(rPar.Get(0), aUnoDate);
1901 else
1902 SbxBase::SetError( SbxERR_CONVERSION );
1905 ::com::sun::star::util::Time SbxDateToUNOTime( const SbxValue* const pVal )
1907 double aDate = pVal->GetDate();
1909 com::sun::star::util::Time aUnoTime;
1910 aUnoTime.Hours = implGetHour ( aDate );
1911 aUnoTime.Minutes = implGetMinute ( aDate );
1912 aUnoTime.Seconds = implGetSecond ( aDate );
1913 aUnoTime.NanoSeconds = 0;
1915 return aUnoTime;
1918 void SbxDateFromUNOTime( SbxValue *pVal, const ::com::sun::star::util::Time& aUnoTime)
1920 pVal->PutDate( implTimeSerial(aUnoTime.Hours, aUnoTime.Minutes, aUnoTime.Seconds) );
1923 // Function to convert date to UNO time (com.sun.star.util.Time)
1924 RTLFUNC(CDateToUnoTime)
1926 (void)pBasic;
1927 (void)bWrite;
1929 if ( rPar.Count() != 2 )
1931 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1932 return;
1935 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNOTime(rPar.Get(1))));
1938 // Function to convert date from UNO time (com.sun.star.util.Time)
1939 RTLFUNC(CDateFromUnoTime)
1941 (void)pBasic;
1942 (void)bWrite;
1944 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT )
1946 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1947 return;
1950 Any aAny (sbxToUnoValue(rPar.Get(1), cppu::UnoType<com::sun::star::util::Time>::get()));
1951 com::sun::star::util::Time aUnoTime;
1952 if(aAny >>= aUnoTime)
1953 SbxDateFromUNOTime(rPar.Get(0), aUnoTime);
1954 else
1955 SbxBase::SetError( SbxERR_CONVERSION );
1958 ::com::sun::star::util::DateTime SbxDateToUNODateTime( const SbxValue* const pVal )
1960 double aDate = pVal->GetDate();
1962 com::sun::star::util::DateTime aUnoDT;
1963 aUnoDT.Day = implGetDateDay ( aDate );
1964 aUnoDT.Month = implGetDateMonth( aDate );
1965 aUnoDT.Year = implGetDateYear ( aDate );
1966 aUnoDT.Hours = implGetHour ( aDate );
1967 aUnoDT.Minutes = implGetMinute ( aDate );
1968 aUnoDT.Seconds = implGetSecond ( aDate );
1969 aUnoDT.NanoSeconds = 0;
1971 return aUnoDT;
1974 void SbxDateFromUNODateTime( SbxValue *pVal, const ::com::sun::star::util::DateTime& aUnoDT)
1976 double dDate(0.0);
1977 if( implDateTimeSerial( aUnoDT.Year, aUnoDT.Month, aUnoDT.Day,
1978 aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds,
1979 dDate ) )
1981 pVal->PutDate( dDate );
1985 // Function to convert date to UNO date (com.sun.star.util.Date)
1986 RTLFUNC(CDateToUnoDateTime)
1988 (void)pBasic;
1989 (void)bWrite;
1991 if ( rPar.Count() != 2 )
1993 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1994 return;
1997 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNODateTime(rPar.Get(1))));
2000 // Function to convert date from UNO date (com.sun.star.util.Date)
2001 RTLFUNC(CDateFromUnoDateTime)
2003 (void)pBasic;
2004 (void)bWrite;
2006 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT )
2008 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2009 return;
2012 Any aAny (sbxToUnoValue(rPar.Get(1), cppu::UnoType<com::sun::star::util::DateTime>::get()));
2013 com::sun::star::util::DateTime aUnoDT;
2014 if(aAny >>= aUnoDT)
2015 SbxDateFromUNODateTime(rPar.Get(0), aUnoDT);
2016 else
2017 SbxBase::SetError( SbxERR_CONVERSION );
2020 // Function to convert date to ISO 8601 date format
2021 RTLFUNC(CDateToIso)
2023 (void)pBasic;
2024 (void)bWrite;
2026 if ( rPar.Count() == 2 )
2028 double aDate = rPar.Get(1)->GetDate();
2030 char Buffer[9];
2031 snprintf( Buffer, sizeof( Buffer ), "%04d%02d%02d",
2032 implGetDateYear( aDate ),
2033 implGetDateMonth( aDate ),
2034 implGetDateDay( aDate ) );
2035 OUString aRetStr = OUString::createFromAscii( Buffer );
2036 rPar.Get(0)->PutString( aRetStr );
2038 else
2040 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2044 // Function to convert date from ISO 8601 date format
2045 RTLFUNC(CDateFromIso)
2047 (void)pBasic;
2048 (void)bWrite;
2050 if ( rPar.Count() == 2 )
2052 OUString aStr = rPar.Get(1)->GetOUString();
2053 sal_Int16 iMonthStart = aStr.getLength() - 4;
2054 OUString aYearStr = aStr.copy( 0, iMonthStart );
2055 OUString aMonthStr = aStr.copy( iMonthStart, 2 );
2056 OUString aDayStr = aStr.copy( iMonthStart+2, 2 );
2058 double dDate;
2059 if( implDateSerial( (sal_Int16)aYearStr.toInt32(),
2060 (sal_Int16)aMonthStr.toInt32(), (sal_Int16)aDayStr.toInt32(), dDate ) )
2062 rPar.Get(0)->PutDate( dDate );
2065 else
2067 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2071 RTLFUNC(DateSerial)
2073 (void)pBasic;
2074 (void)bWrite;
2076 if ( rPar.Count() < 4 )
2078 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2079 return;
2081 sal_Int16 nYear = rPar.Get(1)->GetInteger();
2082 sal_Int16 nMonth = rPar.Get(2)->GetInteger();
2083 sal_Int16 nDay = rPar.Get(3)->GetInteger();
2085 double dDate;
2086 if( implDateSerial( nYear, nMonth, nDay, dDate ) )
2088 rPar.Get(0)->PutDate( dDate );
2092 RTLFUNC(TimeSerial)
2094 (void)pBasic;
2095 (void)bWrite;
2097 if ( rPar.Count() < 4 )
2099 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2100 return;
2102 sal_Int16 nHour = rPar.Get(1)->GetInteger();
2103 if ( nHour == 24 )
2105 nHour = 0; // because of UNO DateTimes, which go till 24 o'clock
2107 sal_Int16 nMinute = rPar.Get(2)->GetInteger();
2108 sal_Int16 nSecond = rPar.Get(3)->GetInteger();
2109 if ((nHour < 0 || nHour > 23) ||
2110 (nMinute < 0 || nMinute > 59 ) ||
2111 (nSecond < 0 || nSecond > 59 ))
2113 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2114 return;
2117 rPar.Get(0)->PutDate( implTimeSerial(nHour, nMinute, nSecond) ); // JSM
2120 RTLFUNC(DateValue)
2122 (void)pBasic;
2123 (void)bWrite;
2125 if ( rPar.Count() < 2 )
2127 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2129 else
2131 // #39629 check GetSbData()->pInst, can be called from the URL line
2132 SvNumberFormatter* pFormatter = NULL;
2133 if( GetSbData()->pInst )
2135 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2137 else
2139 sal_uInt32 n; // Dummy
2140 SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n );
2143 sal_uInt32 nIndex = 0;
2144 double fResult;
2145 OUString aStr( rPar.Get(1)->GetOUString() );
2146 bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult );
2147 short nType = pFormatter->GetType( nIndex );
2149 // DateValue("February 12, 1969") raises error if the system locale is not en_US
2150 // by using SbiInstance::GetNumberFormatter.
2151 // It seems that both locale number formatter and English number formatter
2152 // are supported in Visual Basic.
2153 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
2154 if( !bSuccess && ( eLangType != LANGUAGE_ENGLISH_US ) )
2156 // Create a new SvNumberFormatter by using LANGUAGE_ENGLISH to get the date value;
2157 SvNumberFormatter aFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US );
2158 nIndex = 0;
2159 bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, fResult );
2160 nType = aFormatter.GetType( nIndex );
2163 if(bSuccess && (nType==css::util::NumberFormat::DATE || nType==css::util::NumberFormat::DATETIME))
2165 if ( nType == css::util::NumberFormat::DATETIME )
2167 // cut time
2168 if ( fResult > 0.0 )
2170 fResult = floor( fResult );
2172 else
2174 fResult = ceil( fResult );
2177 rPar.Get(0)->PutDate( fResult );
2179 else
2181 StarBASIC::Error( SbERR_CONVERSION );
2183 // #39629 pFormatter can be requested itself
2184 if( !GetSbData()->pInst )
2186 delete pFormatter;
2191 RTLFUNC(TimeValue)
2193 (void)pBasic;
2194 (void)bWrite;
2196 if ( rPar.Count() < 2 )
2198 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2200 else
2202 SvNumberFormatter* pFormatter = NULL;
2203 if( GetSbData()->pInst )
2204 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2205 else
2207 sal_uInt32 n;
2208 SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n );
2211 sal_uInt32 nIndex = 0;
2212 double fResult;
2213 bool bSuccess = pFormatter->IsNumberFormat( rPar.Get(1)->GetOUString(),
2214 nIndex, fResult );
2215 short nType = pFormatter->GetType(nIndex);
2216 if(bSuccess && (nType==css::util::NumberFormat::TIME||nType==css::util::NumberFormat::DATETIME))
2218 if ( nType == css::util::NumberFormat::DATETIME )
2220 // cut days
2221 fResult = fmod( fResult, 1 );
2223 rPar.Get(0)->PutDate( fResult );
2225 else
2227 StarBASIC::Error( SbERR_CONVERSION );
2229 if( !GetSbData()->pInst )
2231 delete pFormatter;
2236 RTLFUNC(Day)
2238 (void)pBasic;
2239 (void)bWrite;
2241 if ( rPar.Count() < 2 )
2243 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2245 else
2247 SbxVariableRef pArg = rPar.Get( 1 );
2248 double aDate = pArg->GetDate();
2250 sal_Int16 nDay = implGetDateDay( aDate );
2251 rPar.Get(0)->PutInteger( nDay );
2255 RTLFUNC(Year)
2257 (void)pBasic;
2258 (void)bWrite;
2260 if ( rPar.Count() < 2 )
2262 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2264 else
2266 sal_Int16 nYear = implGetDateYear( rPar.Get(1)->GetDate() );
2267 rPar.Get(0)->PutInteger( nYear );
2271 sal_Int16 implGetHour( double dDate )
2273 if( dDate < 0.0 )
2275 dDate *= -1.0;
2277 double nFrac = dDate - floor( dDate );
2278 nFrac *= 86400.0;
2279 sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2280 sal_Int16 nHour = (sal_Int16)(nSeconds / 3600);
2281 return nHour;
2284 RTLFUNC(Hour)
2286 (void)pBasic;
2287 (void)bWrite;
2289 if ( rPar.Count() < 2 )
2291 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2293 else
2295 double nArg = rPar.Get(1)->GetDate();
2296 sal_Int16 nHour = implGetHour( nArg );
2297 rPar.Get(0)->PutInteger( nHour );
2301 RTLFUNC(Minute)
2303 (void)pBasic;
2304 (void)bWrite;
2306 if ( rPar.Count() < 2 )
2308 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2310 else
2312 double nArg = rPar.Get(1)->GetDate();
2313 sal_Int16 nMin = implGetMinute( nArg );
2314 rPar.Get(0)->PutInteger( nMin );
2318 RTLFUNC(Month)
2320 (void)pBasic;
2321 (void)bWrite;
2323 if ( rPar.Count() < 2 )
2325 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2327 else
2329 sal_Int16 nMonth = implGetDateMonth( rPar.Get(1)->GetDate() );
2330 rPar.Get(0)->PutInteger( nMonth );
2334 sal_Int16 implGetSecond( double dDate )
2336 if( dDate < 0.0 )
2338 dDate *= -1.0;
2340 double nFrac = dDate - floor( dDate );
2341 nFrac *= 86400.0;
2342 sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2343 sal_Int16 nTemp = (sal_Int16)(nSeconds / 3600);
2344 nSeconds -= nTemp * 3600;
2345 nTemp = (sal_Int16)(nSeconds / 60);
2346 nSeconds -= nTemp * 60;
2348 sal_Int16 nRet = (sal_Int16)nSeconds;
2349 return nRet;
2352 RTLFUNC(Second)
2354 (void)pBasic;
2355 (void)bWrite;
2357 if ( rPar.Count() < 2 )
2359 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2361 else
2363 double nArg = rPar.Get(1)->GetDate();
2364 sal_Int16 nSecond = implGetSecond( nArg );
2365 rPar.Get(0)->PutInteger( nSecond );
2369 double Now_Impl()
2371 Date aDate( Date::SYSTEM );
2372 tools::Time aTime( tools::Time::SYSTEM );
2373 double aSerial = (double)GetDayDiff( aDate );
2374 long nSeconds = aTime.GetHour();
2375 nSeconds *= 3600;
2376 nSeconds += aTime.GetMin() * 60;
2377 nSeconds += aTime.GetSec();
2378 double nDays = ((double)nSeconds) / (double)(24.0*3600.0);
2379 aSerial += nDays;
2380 return aSerial;
2383 // Date Now()
2385 RTLFUNC(Now)
2387 (void)pBasic;
2388 (void)bWrite;
2389 rPar.Get(0)->PutDate( Now_Impl() );
2392 // Date Time()
2394 RTLFUNC(Time)
2396 (void)pBasic;
2398 if ( !bWrite )
2400 tools::Time aTime( tools::Time::SYSTEM );
2401 SbxVariable* pMeth = rPar.Get( 0 );
2402 OUString aRes;
2403 if( pMeth->IsFixed() )
2405 // Time$: hh:mm:ss
2406 char buf[ 20 ];
2407 snprintf( buf, sizeof(buf), "%02d:%02d:%02d",
2408 aTime.GetHour(), aTime.GetMin(), aTime.GetSec() );
2409 aRes = OUString::createFromAscii( buf );
2411 else
2413 // Time: system dependent
2414 long nSeconds=aTime.GetHour();
2415 nSeconds *= 3600;
2416 nSeconds += aTime.GetMin() * 60;
2417 nSeconds += aTime.GetSec();
2418 double nDays = (double)nSeconds * ( 1.0 / (24.0*3600.0) );
2419 Color* pCol;
2421 SvNumberFormatter* pFormatter = NULL;
2422 sal_uInt32 nIndex;
2423 if( GetSbData()->pInst )
2425 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2426 nIndex = GetSbData()->pInst->GetStdTimeIdx();
2428 else
2430 sal_uInt32 n; // Dummy
2431 SbiInstance::PrepareNumberFormatter( pFormatter, n, nIndex, n );
2434 pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
2436 if( !GetSbData()->pInst )
2438 delete pFormatter;
2441 pMeth->PutString( aRes );
2443 else
2445 StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
2449 RTLFUNC(Timer)
2451 (void)pBasic;
2452 (void)bWrite;
2454 tools::Time aTime( tools::Time::SYSTEM );
2455 long nSeconds = aTime.GetHour();
2456 nSeconds *= 3600;
2457 nSeconds += aTime.GetMin() * 60;
2458 nSeconds += aTime.GetSec();
2459 rPar.Get(0)->PutDate( (double)nSeconds );
2463 RTLFUNC(Date)
2465 (void)pBasic;
2466 (void)bWrite;
2468 if ( !bWrite )
2470 Date aToday( Date::SYSTEM );
2471 double nDays = (double)GetDayDiff( aToday );
2472 SbxVariable* pMeth = rPar.Get( 0 );
2473 if( pMeth->IsString() )
2475 OUString aRes;
2476 Color* pCol;
2478 SvNumberFormatter* pFormatter = NULL;
2479 sal_uInt32 nIndex;
2480 if( GetSbData()->pInst )
2482 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2483 nIndex = GetSbData()->pInst->GetStdDateIdx();
2485 else
2487 sal_uInt32 n;
2488 SbiInstance::PrepareNumberFormatter( pFormatter, nIndex, n, n );
2491 pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
2492 pMeth->PutString( aRes );
2494 if( !GetSbData()->pInst )
2496 delete pFormatter;
2499 else
2501 pMeth->PutDate( nDays );
2504 else
2506 StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
2510 RTLFUNC(IsArray)
2512 (void)pBasic;
2513 (void)bWrite;
2515 if ( rPar.Count() < 2 )
2517 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2519 else
2521 rPar.Get(0)->PutBool((rPar.Get(1)->GetType() & SbxARRAY) != 0);
2525 RTLFUNC(IsObject)
2527 (void)pBasic;
2528 (void)bWrite;
2530 if ( rPar.Count() < 2 )
2532 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2534 else
2536 SbxVariable* pVar = rPar.Get(1);
2537 SbxBase* pObj = pVar->GetObject();
2539 // #100385: GetObject can result in an error, so reset it
2540 SbxBase::ResetError();
2542 SbUnoClass* pUnoClass;
2543 bool bObject;
2544 if( pObj && NULL != ( pUnoClass=PTR_CAST(SbUnoClass,pObj) ) )
2546 bObject = pUnoClass->getUnoClass().is();
2548 else
2550 bObject = pVar->IsObject();
2552 rPar.Get( 0 )->PutBool( bObject );
2556 RTLFUNC(IsDate)
2558 (void)pBasic;
2559 (void)bWrite;
2561 if ( rPar.Count() < 2 )
2563 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2565 else
2567 // #46134 only string is converted, all other types result in sal_False
2568 SbxVariableRef xArg = rPar.Get( 1 );
2569 SbxDataType eType = xArg->GetType();
2570 bool bDate = false;
2572 if( eType == SbxDATE )
2574 bDate = true;
2576 else if( eType == SbxSTRING )
2578 SbxError nPrevError = SbxBase::GetError();
2579 SbxBase::ResetError();
2581 // force conversion of the parameter to SbxDATE
2582 xArg->SbxValue::GetDate();
2584 bDate = !SbxBase::IsError();
2586 SbxBase::ResetError();
2587 SbxBase::SetError( nPrevError );
2589 rPar.Get( 0 )->PutBool( bDate );
2593 RTLFUNC(IsEmpty)
2595 (void)pBasic;
2596 (void)bWrite;
2598 if ( rPar.Count() < 2 )
2600 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2602 else
2604 SbxVariable* pVar = NULL;
2605 if( SbiRuntime::isVBAEnabled() )
2607 pVar = getDefaultProp( rPar.Get(1) );
2609 if ( pVar )
2611 pVar->Broadcast( SBX_HINT_DATAWANTED );
2612 rPar.Get( 0 )->PutBool( pVar->IsEmpty() );
2614 else
2616 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsEmpty() );
2621 RTLFUNC(IsError)
2623 (void)pBasic;
2624 (void)bWrite;
2626 if ( rPar.Count() < 2 )
2628 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2630 else
2632 SbxVariable* pVar =rPar.Get( 1 );
2633 SbUnoObject* pObj = PTR_CAST(SbUnoObject,pVar );
2634 if ( !pObj )
2636 if ( SbxBase* pBaseObj = pVar->GetObject() )
2638 pObj = PTR_CAST(SbUnoObject, pBaseObj );
2641 uno::Reference< script::XErrorQuery > xError;
2642 if ( pObj )
2644 xError.set( pObj->getUnoAny(), uno::UNO_QUERY );
2646 if ( xError.is() )
2648 rPar.Get( 0 )->PutBool( xError->hasError() );
2650 else
2652 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() );
2657 RTLFUNC(IsNull)
2659 (void)pBasic;
2660 (void)bWrite;
2662 if ( rPar.Count() < 2 )
2664 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2666 else
2668 // #51475 because of Uno-objects return true
2669 // even if the pObj value is NULL
2670 SbxVariableRef pArg = rPar.Get( 1 );
2671 bool bNull = rPar.Get(1)->IsNull();
2672 if( !bNull && pArg->GetType() == SbxOBJECT )
2674 SbxBase* pObj = pArg->GetObject();
2675 if( !pObj )
2677 bNull = true;
2680 rPar.Get( 0 )->PutBool( bNull );
2684 RTLFUNC(IsNumeric)
2686 (void)pBasic;
2687 (void)bWrite;
2689 if ( rPar.Count() < 2 )
2691 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2693 else
2695 rPar.Get( 0 )->PutBool( rPar.Get( 1 )->IsNumericRTL() );
2701 RTLFUNC(IsMissing)
2703 (void)pBasic;
2704 (void)bWrite;
2706 if ( rPar.Count() < 2 )
2708 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2710 else
2712 // #57915 Missing is reported by an error
2713 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() );
2717 // Function looks for wildcards, removes them and always returns the pure path
2718 OUString implSetupWildcard( const OUString& rFileParam, SbiRTLData* pRTLData )
2720 static sal_Char cDelim1 = (sal_Char)'/';
2721 static sal_Char cDelim2 = (sal_Char)'\\';
2722 static sal_Char cWild1 = '*';
2723 static sal_Char cWild2 = '?';
2725 delete pRTLData->pWildCard;
2726 pRTLData->pWildCard = NULL;
2727 pRTLData->sFullNameToBeChecked.clear();
2729 OUString aFileParam = rFileParam;
2730 sal_Int32 nLastWild = aFileParam.lastIndexOf( cWild1 );
2731 if( nLastWild < 0 )
2733 nLastWild = aFileParam.lastIndexOf( cWild2 );
2735 bool bHasWildcards = ( nLastWild >= 0 );
2738 sal_Int32 nLastDelim = aFileParam.lastIndexOf( cDelim1 );
2739 if( nLastDelim < 0 )
2741 nLastDelim = aFileParam.lastIndexOf( cDelim2 );
2743 if( bHasWildcards )
2745 // Wildcards in path?
2746 if( nLastDelim >= 0 && nLastDelim > nLastWild )
2748 return aFileParam;
2751 else
2753 OUString aPathStr = getFullPath( aFileParam );
2754 if( nLastDelim != aFileParam.getLength() - 1 )
2756 pRTLData->sFullNameToBeChecked = aPathStr;
2758 return aPathStr;
2761 OUString aPureFileName;
2762 if( nLastDelim < 0 )
2764 aPureFileName = aFileParam;
2765 aFileParam.clear();
2767 else
2769 aPureFileName = aFileParam.copy( nLastDelim + 1 );
2770 aFileParam = aFileParam.copy( 0, nLastDelim );
2773 // Try again to get a valid URL/UNC-path with only the path
2774 OUString aPathStr = getFullPath( aFileParam );
2776 // Is there a pure file name left? Otherwise the path is
2777 // invalid anyway because it was not accepted by OSL before
2778 if (!string::equals(aPureFileName, '*'))
2780 pRTLData->pWildCard = new WildCard( aPureFileName );
2782 return aPathStr;
2785 inline bool implCheckWildcard( const OUString& rName, SbiRTLData* pRTLData )
2787 bool bMatch = true;
2789 if( pRTLData->pWildCard )
2791 bMatch = pRTLData->pWildCard->Matches( rName );
2793 return bMatch;
2797 bool isRootDir( const OUString& aDirURLStr )
2799 INetURLObject aDirURLObj( aDirURLStr );
2800 bool bRoot = false;
2802 // Check if it's a root directory
2803 sal_Int32 nCount = aDirURLObj.getSegmentCount();
2805 // No segment means Unix root directory "file:///"
2806 if( nCount == 0 )
2808 bRoot = true;
2810 // Exactly one segment needs further checking, because it
2811 // can be Unix "file:///foo/" -> no root
2812 // or Windows "file:///c:/" -> root
2813 else if( nCount == 1 )
2815 OUString aSeg1 = aDirURLObj.getName( 0, true,
2816 INetURLObject::DECODE_WITH_CHARSET );
2817 if( aSeg1[1] == (sal_Unicode)':' )
2819 bRoot = true;
2822 // More than one segments can never be root
2823 // so bRoot remains false
2825 return bRoot;
2828 RTLFUNC(Dir)
2830 (void)pBasic;
2831 (void)bWrite;
2833 OUString aPath;
2835 sal_uInt16 nParCount = rPar.Count();
2836 if( nParCount > 3 )
2838 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2840 else
2842 SbiRTLData* pRTLData = GetSbData()->pInst->GetRTLData();
2844 // #34645: can also be called from the URL line via 'macro: Dir'
2845 // there's no pRTLDate existing in that case and the method must be left
2846 if( !pRTLData )
2848 return;
2850 if( hasUno() )
2852 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
2853 if( xSFI.is() )
2855 if ( nParCount >= 2 )
2857 OUString aFileParam = rPar.Get(1)->GetOUString();
2859 OUString aFileURLStr = implSetupWildcard( aFileParam, pRTLData );
2860 if( !pRTLData->sFullNameToBeChecked.isEmpty())
2862 bool bExists = false;
2863 try { bExists = xSFI->exists( aFileURLStr ); }
2864 catch(const Exception & ) {}
2866 OUString aNameOnlyStr;
2867 if( bExists )
2869 INetURLObject aFileURL( aFileURLStr );
2870 aNameOnlyStr = aFileURL.getName( INetURLObject::LAST_SEGMENT,
2871 true, INetURLObject::DECODE_WITH_CHARSET );
2873 rPar.Get(0)->PutString( aNameOnlyStr );
2874 return;
2879 OUString aDirURLStr;
2880 bool bFolder = xSFI->isFolder( aFileURLStr );
2882 if( bFolder )
2884 aDirURLStr = aFileURLStr;
2886 else
2888 OUString aEmptyStr;
2889 rPar.Get(0)->PutString( aEmptyStr );
2892 sal_uInt16 nFlags = 0;
2893 if ( nParCount > 2 )
2895 pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
2897 else
2899 pRTLData->nDirFlags = 0;
2901 // Read directory
2902 bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0);
2903 pRTLData->aDirSeq = xSFI->getFolderContents( aDirURLStr, bIncludeFolders );
2904 pRTLData->nCurDirPos = 0;
2906 // #78651 Add "." and ".." directories for VB compatibility
2907 if( bIncludeFolders )
2909 bool bRoot = isRootDir( aDirURLStr );
2911 // If it's no root directory we flag the need for
2912 // the "." and ".." directories by the value -2
2913 // for the actual position. Later for -2 will be
2914 // returned "." and for -1 ".."
2915 if( !bRoot )
2917 pRTLData->nCurDirPos = -2;
2921 catch(const Exception & )
2927 if( pRTLData->aDirSeq.getLength() > 0 )
2929 bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0);
2931 SbiInstance* pInst = GetSbData()->pInst;
2932 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
2933 for( ;; )
2935 if( pRTLData->nCurDirPos < 0 )
2937 if( pRTLData->nCurDirPos == -2 )
2939 aPath = ".";
2941 else if( pRTLData->nCurDirPos == -1 )
2943 aPath = "..";
2945 pRTLData->nCurDirPos++;
2947 else if( pRTLData->nCurDirPos >= pRTLData->aDirSeq.getLength() )
2949 pRTLData->aDirSeq.realloc( 0 );
2950 aPath.clear();
2951 break;
2953 else
2955 OUString aFile = pRTLData->aDirSeq.getConstArray()[pRTLData->nCurDirPos++];
2957 if( bCompatibility )
2959 if( !bFolderFlag )
2961 bool bFolder = xSFI->isFolder( aFile );
2962 if( bFolder )
2964 continue;
2968 else
2970 // Only directories
2971 if( bFolderFlag )
2973 bool bFolder = xSFI->isFolder( aFile );
2974 if( !bFolder )
2976 continue;
2981 INetURLObject aURL( aFile );
2982 aPath = aURL.getName( INetURLObject::LAST_SEGMENT, true,
2983 INetURLObject::DECODE_WITH_CHARSET );
2986 bool bMatch = implCheckWildcard( aPath, pRTLData );
2987 if( !bMatch )
2989 continue;
2991 break;
2994 rPar.Get(0)->PutString( aPath );
2997 else
2999 // TODO: OSL
3000 if ( nParCount >= 2 )
3002 OUString aFileParam = rPar.Get(1)->GetOUString();
3004 OUString aDirURL = implSetupWildcard( aFileParam, pRTLData );
3006 sal_uInt16 nFlags = 0;
3007 if ( nParCount > 2 )
3009 pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
3011 else
3013 pRTLData->nDirFlags = 0;
3016 // Read directory
3017 bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0);
3018 pRTLData->pDir = new Directory( aDirURL );
3019 FileBase::RC nRet = pRTLData->pDir->open();
3020 if( nRet != FileBase::E_None )
3022 delete pRTLData->pDir;
3023 pRTLData->pDir = NULL;
3024 rPar.Get(0)->PutString( OUString() );
3025 return;
3028 // #86950 Add "." and ".." directories for VB compatibility
3029 pRTLData->nCurDirPos = 0;
3030 if( bIncludeFolders )
3032 bool bRoot = isRootDir( aDirURL );
3034 // If it's no root directory we flag the need for
3035 // the "." and ".." directories by the value -2
3036 // for the actual position. Later for -2 will be
3037 // returned "." and for -1 ".."
3038 if( !bRoot )
3040 pRTLData->nCurDirPos = -2;
3046 if( pRTLData->pDir )
3048 bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0);
3049 for( ;; )
3051 if( pRTLData->nCurDirPos < 0 )
3053 if( pRTLData->nCurDirPos == -2 )
3055 aPath = ".";
3057 else if( pRTLData->nCurDirPos == -1 )
3059 aPath = "..";
3061 pRTLData->nCurDirPos++;
3063 else
3065 DirectoryItem aItem;
3066 FileBase::RC nRet = pRTLData->pDir->getNextItem( aItem );
3067 if( nRet != FileBase::E_None )
3069 delete pRTLData->pDir;
3070 pRTLData->pDir = NULL;
3071 aPath.clear();
3072 break;
3075 // Handle flags
3076 FileStatus aFileStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName );
3077 nRet = aItem.getFileStatus( aFileStatus );
3079 // Only directories?
3080 if( bFolderFlag )
3082 FileStatus::Type aType = aFileStatus.getFileType();
3083 bool bFolder = isFolder( aType );
3084 if( !bFolder )
3086 continue;
3090 aPath = aFileStatus.getFileName();
3093 bool bMatch = implCheckWildcard( aPath, pRTLData );
3094 if( !bMatch )
3096 continue;
3098 break;
3101 rPar.Get(0)->PutString( aPath );
3107 RTLFUNC(GetAttr)
3109 (void)pBasic;
3110 (void)bWrite;
3112 if ( rPar.Count() == 2 )
3114 sal_Int16 nFlags = 0;
3116 // In Windows, we want to use Windows API to get the file attributes
3117 // for VBA interoperability.
3118 #if defined( WNT )
3119 if( SbiRuntime::isVBAEnabled() )
3121 OUString aPathURL = getFullPath( rPar.Get(1)->GetOUString() );
3122 OUString aPath;
3123 FileBase::getSystemPathFromFileURL( aPathURL, aPath );
3124 OString aSystemPath(OUStringToOString(aPath, osl_getThreadTextEncoding()));
3125 DWORD nRealFlags = GetFileAttributes (aSystemPath.getStr());
3126 if (nRealFlags != 0xffffffff)
3128 if (nRealFlags == FILE_ATTRIBUTE_NORMAL)
3130 nRealFlags = 0;
3132 nFlags = (sal_Int16) (nRealFlags);
3134 else
3136 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3138 rPar.Get(0)->PutInteger( nFlags );
3140 return;
3142 #endif
3144 if( hasUno() )
3146 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
3147 if( xSFI.is() )
3151 OUString aPath = getFullPath( rPar.Get(1)->GetOUString() );
3152 bool bExists = false;
3153 try { bExists = xSFI->exists( aPath ); }
3154 catch(const Exception & ) {}
3155 if( !bExists )
3157 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3158 return;
3161 bool bReadOnly = xSFI->isReadOnly( aPath );
3162 bool bHidden = xSFI->isHidden( aPath );
3163 bool bDirectory = xSFI->isFolder( aPath );
3164 if( bReadOnly )
3166 nFlags |= Sb_ATTR_READONLY;
3168 if( bHidden )
3170 nFlags |= Sb_ATTR_HIDDEN;
3172 if( bDirectory )
3174 nFlags |= Sb_ATTR_DIRECTORY;
3177 catch(const Exception & )
3179 StarBASIC::Error( ERRCODE_IO_GENERAL );
3183 else
3185 DirectoryItem aItem;
3186 DirectoryItem::get( getFullPath( rPar.Get(1)->GetOUString() ), aItem );
3187 FileStatus aFileStatus( osl_FileStatus_Mask_Attributes | osl_FileStatus_Mask_Type );
3188 aItem.getFileStatus( aFileStatus );
3189 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3190 bool bReadOnly = (nAttributes & osl_File_Attribute_ReadOnly) != 0;
3192 FileStatus::Type aType = aFileStatus.getFileType();
3193 bool bDirectory = isFolder( aType );
3194 if( bReadOnly )
3196 nFlags |= Sb_ATTR_READONLY;
3198 if( bDirectory )
3200 nFlags |= Sb_ATTR_DIRECTORY;
3203 rPar.Get(0)->PutInteger( nFlags );
3205 else
3207 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3212 RTLFUNC(FileDateTime)
3214 (void)pBasic;
3215 (void)bWrite;
3217 if ( rPar.Count() != 2 )
3219 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3221 else
3223 OUString aPath = rPar.Get(1)->GetOUString();
3224 tools::Time aTime( tools::Time::EMPTY );
3225 Date aDate( Date::EMPTY );
3226 if( hasUno() )
3228 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
3229 if( xSFI.is() )
3233 util::DateTime aUnoDT = xSFI->getDateTimeModified( aPath );
3234 aTime = tools::Time( aUnoDT );
3235 aDate = Date( aUnoDT );
3237 catch(const Exception & )
3239 StarBASIC::Error( ERRCODE_IO_GENERAL );
3243 else
3245 DirectoryItem aItem;
3246 DirectoryItem::get( getFullPath( aPath ), aItem );
3247 FileStatus aFileStatus( osl_FileStatus_Mask_ModifyTime );
3248 aItem.getFileStatus( aFileStatus );
3249 TimeValue aTimeVal = aFileStatus.getModifyTime();
3250 oslDateTime aDT;
3251 osl_getDateTimeFromTimeValue( &aTimeVal, &aDT );
3253 aTime = tools::Time( aDT.Hours, aDT.Minutes, aDT.Seconds, aDT.NanoSeconds );
3254 aDate = Date( aDT.Day, aDT.Month, aDT.Year );
3257 double fSerial = (double)GetDayDiff( aDate );
3258 long nSeconds = aTime.GetHour();
3259 nSeconds *= 3600;
3260 nSeconds += aTime.GetMin() * 60;
3261 nSeconds += aTime.GetSec();
3262 double nDays = ((double)nSeconds) / (double)(24.0*3600.0);
3263 fSerial += nDays;
3265 Color* pCol;
3267 SvNumberFormatter* pFormatter = NULL;
3268 sal_uInt32 nIndex;
3269 if( GetSbData()->pInst )
3271 pFormatter = GetSbData()->pInst->GetNumberFormatter();
3272 nIndex = GetSbData()->pInst->GetStdDateTimeIdx();
3274 else
3276 sal_uInt32 n;
3277 SbiInstance::PrepareNumberFormatter( pFormatter, n, n, nIndex );
3280 OUString aRes;
3281 pFormatter->GetOutputString( fSerial, nIndex, aRes, &pCol );
3282 rPar.Get(0)->PutString( aRes );
3284 if( !GetSbData()->pInst )
3286 delete pFormatter;
3292 RTLFUNC(EOF)
3294 (void)pBasic;
3295 (void)bWrite;
3297 // No changes for UCB
3298 if ( rPar.Count() != 2 )
3300 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3302 else
3304 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3305 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3306 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3307 if ( !pSbStrm )
3309 StarBASIC::Error( SbERR_BAD_CHANNEL );
3310 return;
3312 bool bIsEof;
3313 SvStream* pSvStrm = pSbStrm->GetStrm();
3314 if ( pSbStrm->IsText() )
3316 char cBla;
3317 (*pSvStrm).ReadChar( cBla ); // can we read another character?
3318 bIsEof = pSvStrm->IsEof();
3319 if ( !bIsEof )
3321 pSvStrm->SeekRel( -1 );
3324 else
3326 bIsEof = pSvStrm->IsEof(); // for binary data!
3328 rPar.Get(0)->PutBool( bIsEof );
3332 RTLFUNC(FileAttr)
3334 (void)pBasic;
3335 (void)bWrite;
3337 // No changes for UCB
3338 // #57064 Although this function doesn't operate with DirEntry, it is
3339 // not touched by the adjustment to virtual URLs, as it only works on
3340 // already opened files and the name doesn't matter there.
3342 if ( rPar.Count() != 3 )
3344 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3346 else
3348 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3349 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3350 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3351 if ( !pSbStrm )
3353 StarBASIC::Error( SbERR_BAD_CHANNEL );
3354 return;
3356 sal_Int16 nRet;
3357 if ( rPar.Get(2)->GetInteger() == 1 )
3359 nRet = (sal_Int16)(pSbStrm->GetMode());
3361 else
3363 nRet = 0; // System file handle not supported
3365 rPar.Get(0)->PutInteger( nRet );
3368 RTLFUNC(Loc)
3370 (void)pBasic;
3371 (void)bWrite;
3373 // No changes for UCB
3374 if ( rPar.Count() != 2 )
3376 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3378 else
3380 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3381 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3382 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3383 if ( !pSbStrm )
3385 StarBASIC::Error( SbERR_BAD_CHANNEL );
3386 return;
3388 SvStream* pSvStrm = pSbStrm->GetStrm();
3389 sal_Size nPos;
3390 if( pSbStrm->IsRandom())
3392 short nBlockLen = pSbStrm->GetBlockLen();
3393 nPos = nBlockLen ? (pSvStrm->Tell() / nBlockLen) : 0;
3394 nPos++; // block positions starting at 1
3396 else if ( pSbStrm->IsText() )
3398 nPos = pSbStrm->GetLine();
3400 else if( pSbStrm->IsBinary() )
3402 nPos = pSvStrm->Tell();
3404 else if ( pSbStrm->IsSeq() )
3406 nPos = ( pSvStrm->Tell()+1 ) / 128;
3408 else
3410 nPos = pSvStrm->Tell();
3412 rPar.Get(0)->PutLong( (sal_Int32)nPos );
3416 RTLFUNC(Lof)
3418 (void)pBasic;
3419 (void)bWrite;
3421 // No changes for UCB
3422 if ( rPar.Count() != 2 )
3424 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3426 else
3428 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3429 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3430 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3431 if ( !pSbStrm )
3433 StarBASIC::Error( SbERR_BAD_CHANNEL );
3434 return;
3436 SvStream* pSvStrm = pSbStrm->GetStrm();
3437 sal_Size nOldPos = pSvStrm->Tell();
3438 sal_Size nLen = pSvStrm->Seek( STREAM_SEEK_TO_END );
3439 pSvStrm->Seek( nOldPos );
3440 rPar.Get(0)->PutLong( (sal_Int32)nLen );
3445 RTLFUNC(Seek)
3447 (void)pBasic;
3448 (void)bWrite;
3450 // No changes for UCB
3451 int nArgs = (int)rPar.Count();
3452 if ( nArgs < 2 || nArgs > 3 )
3454 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3455 return;
3457 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3458 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3459 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3460 if ( !pSbStrm )
3462 StarBASIC::Error( SbERR_BAD_CHANNEL );
3463 return;
3465 SvStream* pStrm = pSbStrm->GetStrm();
3467 if ( nArgs == 2 ) // Seek-Function
3469 sal_Size nPos = pStrm->Tell();
3470 if( pSbStrm->IsRandom() )
3472 nPos = nPos / pSbStrm->GetBlockLen();
3474 nPos++; // Basic counts from 1
3475 rPar.Get(0)->PutLong( (sal_Int32)nPos );
3477 else // Seek-Statement
3479 sal_Int32 nPos = rPar.Get(2)->GetLong();
3480 if ( nPos < 1 )
3482 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3483 return;
3485 nPos--; // Basic counts from 1, SvStreams count from 0
3486 pSbStrm->SetExpandOnWriteTo( 0 );
3487 if ( pSbStrm->IsRandom() )
3489 nPos *= pSbStrm->GetBlockLen();
3491 pStrm->Seek( (sal_Size)nPos );
3492 pSbStrm->SetExpandOnWriteTo( nPos );
3496 RTLFUNC(Format)
3498 (void)pBasic;
3499 (void)bWrite;
3501 sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
3502 if ( nArgCount < 2 || nArgCount > 3 )
3504 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3506 else
3508 OUString aResult;
3509 if( nArgCount == 2 )
3511 rPar.Get(1)->Format( aResult );
3513 else
3515 OUString aFmt( rPar.Get(2)->GetOUString() );
3516 rPar.Get(1)->Format( aResult, &aFmt );
3518 rPar.Get(0)->PutString( aResult );
3522 namespace {
3524 // note: BASIC does not use comphelper::random, because
3525 // Randomize(int) must be supported and should not affect non-BASIC random use
3526 struct RandomNumberGenerator
3528 std::mt19937 global_rng;
3530 RandomNumberGenerator()
3534 std::random_device rd;
3535 // initialises the state of the global random number generator
3536 // should only be called once.
3537 // (note, a few std::variate_generator<> (like normal) have their
3538 // own state which would need a reset as well to guarantee identical
3539 // sequence of numbers, e.g. via myrand.distribution().reset())
3540 global_rng.seed(rd() ^ time(nullptr));
3542 catch (std::runtime_error& e)
3544 SAL_WARN("basic", "Using std::random_device failed: " << e.what());
3545 global_rng.seed(time(nullptr));
3550 class theRandomNumberGenerator : public rtl::Static<RandomNumberGenerator, theRandomNumberGenerator> {};
3554 RTLFUNC(Randomize)
3556 (void)pBasic;
3557 (void)bWrite;
3559 if ( rPar.Count() > 2 )
3561 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3563 int nSeed;
3564 if( rPar.Count() == 2 )
3566 nSeed = (int)rPar.Get(1)->GetInteger();
3567 theRandomNumberGenerator::get().global_rng.seed(nSeed);
3569 // without parameter, no need to do anything - RNG is seeded at first use
3572 RTLFUNC(Rnd)
3574 (void)pBasic;
3575 (void)bWrite;
3577 if ( rPar.Count() > 2 )
3579 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3581 else
3583 std::uniform_real_distribution<double> dist(0.0, 1.0);
3584 double const tmp(dist(theRandomNumberGenerator::get().global_rng));
3585 rPar.Get(0)->PutDouble(tmp);
3590 // Syntax: Shell("Path",[ Window-Style,[ "Params", [ bSync = sal_False ]]])
3591 // WindowStyles (VBA-kompatibel):
3592 // 2 == Minimized
3593 // 3 == Maximized
3594 // 10 == Full-Screen (text mode applications OS/2, WIN95, WNT)
3595 // HACK: The WindowStyle will be passed to
3596 // Application::StartApp in Creator. Format: "xxxx2"
3599 RTLFUNC(Shell)
3601 (void)pBasic;
3602 (void)bWrite;
3604 // No shell command for "virtual" portal users
3605 if( needSecurityRestrictions() )
3607 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3608 return;
3611 sal_Size nArgCount = rPar.Count();
3612 if ( nArgCount < 2 || nArgCount > 5 )
3614 rPar.Get(0)->PutLong(0);
3615 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3617 else
3619 oslProcessOption nOptions = osl_Process_SEARCHPATH | osl_Process_DETACHED;
3621 OUString aCmdLine = rPar.Get(1)->GetOUString();
3622 // attach additional parameters - everything must be parsed anyway
3623 if( nArgCount >= 4 )
3625 OUString tmp = rPar.Get(3)->GetOUString().trim();
3626 if (!tmp.isEmpty())
3628 aCmdLine += " ";
3629 aCmdLine += tmp;
3632 else if( aCmdLine.isEmpty() )
3634 // avaoid special treatment (empty list)
3635 aCmdLine += " ";
3637 sal_Int32 nLen = aCmdLine.getLength();
3639 // #55735 if there are parameters, they have to be separated
3640 // #72471 also separate the single parameters
3641 std::list<OUString> aTokenList;
3642 OUString aToken;
3643 sal_Int32 i = 0;
3644 sal_Unicode c;
3645 while( i < nLen )
3647 for ( ;; ++i )
3649 c = aCmdLine[ i ];
3650 if ( c != ' ' && c != '\t' )
3652 break;
3656 if( c == '\"' || c == '\'' )
3658 sal_Int32 iFoundPos = aCmdLine.indexOf( c, i + 1 );
3660 if( iFoundPos < 0 )
3662 aToken = aCmdLine.copy( i);
3663 i = nLen;
3665 else
3667 aToken = aCmdLine.copy( i + 1, (iFoundPos - i - 1) );
3668 i = iFoundPos + 1;
3671 else
3673 sal_Int32 iFoundSpacePos = aCmdLine.indexOf( ' ', i );
3674 sal_Int32 iFoundTabPos = aCmdLine.indexOf( '\t', i );
3675 sal_Int32 iFoundPos = iFoundSpacePos >= 0 ? iFoundTabPos >= 0 ? std::min( iFoundSpacePos, iFoundTabPos ) : iFoundSpacePos : -1;
3677 if( iFoundPos < 0 )
3679 aToken = aCmdLine.copy( i );
3680 i = nLen;
3682 else
3684 aToken = aCmdLine.copy( i, (iFoundPos - i) );
3685 i = iFoundPos;
3689 // insert into the list
3690 aTokenList.push_back( aToken );
3692 // #55735 / #72471 end
3694 sal_Int16 nWinStyle = 0;
3695 if( nArgCount >= 3 )
3697 nWinStyle = rPar.Get(2)->GetInteger();
3698 switch( nWinStyle )
3700 case 2:
3701 nOptions |= osl_Process_MINIMIZED;
3702 break;
3703 case 3:
3704 nOptions |= osl_Process_MAXIMIZED;
3705 break;
3706 case 10:
3707 nOptions |= osl_Process_FULLSCREEN;
3708 break;
3711 bool bSync = false;
3712 if( nArgCount >= 5 )
3714 bSync = rPar.Get(4)->GetBool();
3716 if( bSync )
3718 nOptions |= osl_Process_WAIT;
3722 // #72471 work parameter(s) up
3723 std::list<OUString>::const_iterator iter = aTokenList.begin();
3724 const OUString& rStr = *iter;
3725 OUString aOUStrProg( rStr.getStr(), rStr.getLength() );
3726 OUString aOUStrProgURL = getFullPath( aOUStrProg );
3728 ++iter;
3730 sal_uInt16 nParamCount = sal::static_int_cast< sal_uInt16 >(aTokenList.size() - 1 );
3731 rtl_uString** pParamList = NULL;
3732 if( nParamCount )
3734 pParamList = new rtl_uString*[nParamCount];
3735 for(int iList = 0; iter != aTokenList.end(); ++iList, ++iter)
3737 const OUString& rParamStr = (*iter);
3738 const OUString aTempStr( rParamStr.getStr(), rParamStr.getLength());
3739 pParamList[iList] = NULL;
3740 rtl_uString_assign(&(pParamList[iList]), aTempStr.pData);
3744 oslProcess pApp;
3745 bool bSucc = osl_executeProcess(
3746 aOUStrProgURL.pData,
3747 pParamList,
3748 nParamCount,
3749 nOptions,
3750 NULL,
3751 NULL,
3752 NULL, 0,
3753 &pApp ) == osl_Process_E_None;
3755 // 53521 only free process handle on success
3756 if (bSucc)
3758 osl_freeProcessHandle( pApp );
3761 for(int j = 0; j < nParamCount; ++j)
3763 rtl_uString_release(pParamList[j]);
3766 delete [] pParamList;
3768 if( !bSucc )
3770 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3772 else
3774 rPar.Get(0)->PutLong( 0 );
3779 RTLFUNC(VarType)
3781 (void)pBasic;
3782 (void)bWrite;
3784 if ( rPar.Count() != 2 )
3786 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3788 else
3790 SbxDataType eType = rPar.Get(1)->GetType();
3791 rPar.Get(0)->PutInteger( (sal_Int16)eType );
3795 // Exported function
3796 OUString getBasicTypeName( SbxDataType eType )
3798 static const char* pTypeNames[] =
3800 "Empty", // SbxEMPTY
3801 "Null", // SbxNULL
3802 "Integer", // SbxINTEGER
3803 "Long", // SbxLONG
3804 "Single", // SbxSINGLE
3805 "Double", // SbxDOUBLE
3806 "Currency", // SbxCURRENCY
3807 "Date", // SbxDATE
3808 "String", // SbxSTRING
3809 "Object", // SbxOBJECT
3810 "Error", // SbxERROR
3811 "Boolean", // SbxBOOL
3812 "Variant", // SbxVARIANT
3813 "DataObject", // SbxDATAOBJECT
3814 "Unknown Type",
3815 "Unknown Type",
3816 "Char", // SbxCHAR
3817 "Byte", // SbxBYTE
3818 "UShort", // SbxUSHORT
3819 "ULong", // SbxULONG
3820 "Long64", // SbxLONG64
3821 "ULong64", // SbxULONG64
3822 "Int", // SbxINT
3823 "UInt", // SbxUINT
3824 "Void", // SbxVOID
3825 "HResult", // SbxHRESULT
3826 "Pointer", // SbxPOINTER
3827 "DimArray", // SbxDIMARRAY
3828 "CArray", // SbxCARRAY
3829 "Userdef", // SbxUSERDEF
3830 "Lpstr", // SbxLPSTR
3831 "Lpwstr", // SbxLPWSTR
3832 "Unknown Type", // SbxCoreSTRING
3833 "WString", // SbxWSTRING
3834 "WChar", // SbxWCHAR
3835 "Int64", // SbxSALINT64
3836 "UInt64", // SbxSALUINT64
3837 "Decimal", // SbxDECIMAL
3840 int nPos = ((int)eType) & 0x0FFF;
3841 sal_uInt16 nTypeNameCount = sizeof( pTypeNames ) / sizeof( char* );
3842 if ( nPos < 0 || nPos >= nTypeNameCount )
3844 nPos = nTypeNameCount - 1;
3846 return OUString::createFromAscii(pTypeNames[nPos]);
3849 OUString getObjectTypeName( SbxVariable* pVar )
3851 OUString sRet( "Object" );
3852 if ( pVar )
3854 SbxBase* pObj = pVar->GetObject();
3855 if( !pObj )
3857 sRet = "Nothing";
3859 else
3861 SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pVar );
3862 if ( !pUnoObj )
3864 if ( SbxBase* pBaseObj = pVar->GetObject() )
3866 pUnoObj = PTR_CAST(SbUnoObject, pBaseObj );
3869 if ( pUnoObj )
3871 Any aObj = pUnoObj->getUnoAny();
3872 // For upstreaming unless we start to build oovbaapi by default
3873 // we need to get detect the vba-ness of the object in some
3874 // other way
3875 // note: Automation objects do not support XServiceInfo
3876 uno::Reference< XServiceInfo > xServInfo( aObj, uno::UNO_QUERY );
3877 if ( xServInfo.is() )
3879 // is this a VBA object ?
3880 uno::Reference< ooo::vba::XHelperInterface > xVBA( aObj, uno::UNO_QUERY );
3881 Sequence< OUString > sServices = xServInfo->getSupportedServiceNames();
3882 if ( sServices.getLength() )
3884 sRet = sServices[ 0 ];
3887 else
3889 uno::Reference< bridge::oleautomation::XAutomationObject > xAutoMation( aObj, uno::UNO_QUERY );
3890 if ( xAutoMation.is() )
3892 uno::Reference< script::XInvocation > xInv( aObj, uno::UNO_QUERY );
3893 if ( xInv.is() )
3897 xInv->getValue( OUString( "$GetTypeName" ) ) >>= sRet;
3899 catch(const Exception& )
3905 sal_Int32 nDot = sRet.lastIndexOf( '.' );
3906 if ( nDot != -1 && nDot < sRet.getLength() )
3908 sRet = sRet.copy( nDot + 1 );
3913 return sRet;
3916 RTLFUNC(TypeName)
3918 (void)pBasic;
3919 (void)bWrite;
3921 if ( rPar.Count() != 2 )
3923 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3925 else
3927 SbxDataType eType = rPar.Get(1)->GetType();
3928 bool bIsArray = ( ( eType & SbxARRAY ) != 0 );
3930 OUString aRetStr;
3931 if ( SbiRuntime::isVBAEnabled() && eType == SbxOBJECT )
3933 aRetStr = getObjectTypeName( rPar.Get(1) );
3935 else
3937 aRetStr = getBasicTypeName( eType );
3939 if( bIsArray )
3941 aRetStr += "()";
3943 rPar.Get(0)->PutString( aRetStr );
3947 RTLFUNC(Len)
3949 (void)pBasic;
3950 (void)bWrite;
3952 if ( rPar.Count() != 2 )
3954 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3956 else
3958 const OUString& rStr = rPar.Get(1)->GetOUString();
3959 rPar.Get(0)->PutLong( rStr.getLength() );
3963 RTLFUNC(DDEInitiate)
3965 (void)pBasic;
3966 (void)bWrite;
3968 // No DDE for "virtual" portal users
3969 if( needSecurityRestrictions() )
3971 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3972 return;
3975 int nArgs = (int)rPar.Count();
3976 if ( nArgs != 3 )
3978 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3979 return;
3981 const OUString& rApp = rPar.Get(1)->GetOUString();
3982 const OUString& rTopic = rPar.Get(2)->GetOUString();
3984 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
3985 size_t nChannel;
3986 SbError nDdeErr = pDDE->Initiate( rApp, rTopic, nChannel );
3987 if( nDdeErr )
3989 StarBASIC::Error( nDdeErr );
3991 else
3993 rPar.Get(0)->PutInteger( (int)nChannel );
3997 RTLFUNC(DDETerminate)
3999 (void)pBasic;
4000 (void)bWrite;
4002 // No DDE for "virtual" portal users
4003 if( needSecurityRestrictions() )
4005 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4006 return;
4009 rPar.Get(0)->PutEmpty();
4010 int nArgs = (int)rPar.Count();
4011 if ( nArgs != 2 )
4013 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4014 return;
4016 size_t nChannel = rPar.Get(1)->GetInteger();
4017 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4018 SbError nDdeErr = pDDE->Terminate( nChannel );
4019 if( nDdeErr )
4021 StarBASIC::Error( nDdeErr );
4025 RTLFUNC(DDETerminateAll)
4027 (void)pBasic;
4028 (void)bWrite;
4030 // No DDE for "virtual" portal users
4031 if( needSecurityRestrictions() )
4033 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4034 return;
4037 rPar.Get(0)->PutEmpty();
4038 int nArgs = (int)rPar.Count();
4039 if ( nArgs != 1 )
4041 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4042 return;
4045 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4046 SbError nDdeErr = pDDE->TerminateAll();
4047 if( nDdeErr )
4049 StarBASIC::Error( nDdeErr );
4053 RTLFUNC(DDERequest)
4055 (void)pBasic;
4056 (void)bWrite;
4058 // No DDE for "virtual" portal users
4059 if( needSecurityRestrictions() )
4061 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4062 return;
4065 int nArgs = (int)rPar.Count();
4066 if ( nArgs != 3 )
4068 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4069 return;
4071 size_t nChannel = rPar.Get(1)->GetInteger();
4072 const OUString& rItem = rPar.Get(2)->GetOUString();
4073 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4074 OUString aResult;
4075 SbError nDdeErr = pDDE->Request( nChannel, rItem, aResult );
4076 if( nDdeErr )
4078 StarBASIC::Error( nDdeErr );
4080 else
4082 rPar.Get(0)->PutString( aResult );
4086 RTLFUNC(DDEExecute)
4088 (void)pBasic;
4089 (void)bWrite;
4091 // No DDE for "virtual" portal users
4092 if( needSecurityRestrictions() )
4094 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4095 return;
4098 rPar.Get(0)->PutEmpty();
4099 int nArgs = (int)rPar.Count();
4100 if ( nArgs != 3 )
4102 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4103 return;
4105 size_t nChannel = rPar.Get(1)->GetInteger();
4106 const OUString& rCommand = rPar.Get(2)->GetOUString();
4107 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4108 SbError nDdeErr = pDDE->Execute( nChannel, rCommand );
4109 if( nDdeErr )
4111 StarBASIC::Error( nDdeErr );
4115 RTLFUNC(DDEPoke)
4117 (void)pBasic;
4118 (void)bWrite;
4120 // No DDE for "virtual" portal users
4121 if( needSecurityRestrictions() )
4123 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4124 return;
4127 rPar.Get(0)->PutEmpty();
4128 int nArgs = (int)rPar.Count();
4129 if ( nArgs != 4 )
4131 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4132 return;
4134 size_t nChannel = rPar.Get(1)->GetInteger();
4135 const OUString& rItem = rPar.Get(2)->GetOUString();
4136 const OUString& rData = rPar.Get(3)->GetOUString();
4137 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4138 SbError nDdeErr = pDDE->Poke( nChannel, rItem, rData );
4139 if( nDdeErr )
4141 StarBASIC::Error( nDdeErr );
4146 RTLFUNC(FreeFile)
4148 (void)pBasic;
4149 (void)bWrite;
4151 if ( rPar.Count() != 1 )
4153 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4154 return;
4156 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
4157 short nChannel = 1;
4158 while( nChannel < CHANNELS )
4160 SbiStream* pStrm = pIO->GetStream( nChannel );
4161 if( !pStrm )
4163 rPar.Get(0)->PutInteger( nChannel );
4164 return;
4166 nChannel++;
4168 StarBASIC::Error( SbERR_TOO_MANY_FILES );
4171 RTLFUNC(LBound)
4173 (void)pBasic;
4174 (void)bWrite;
4176 sal_uInt16 nParCount = rPar.Count();
4177 if ( nParCount != 3 && nParCount != 2 )
4179 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4180 return;
4182 SbxBase* pParObj = rPar.Get(1)->GetObject();
4183 SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj);
4184 if( pArr )
4186 sal_Int32 nLower, nUpper;
4187 short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1;
4188 if( !pArr->GetDim32( nDim, nLower, nUpper ) )
4189 StarBASIC::Error( SbERR_OUT_OF_RANGE );
4190 else
4191 rPar.Get(0)->PutLong( nLower );
4193 else
4194 StarBASIC::Error( SbERR_MUST_HAVE_DIMS );
4197 RTLFUNC(UBound)
4199 (void)pBasic;
4200 (void)bWrite;
4202 sal_uInt16 nParCount = rPar.Count();
4203 if ( nParCount != 3 && nParCount != 2 )
4205 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4206 return;
4209 SbxBase* pParObj = rPar.Get(1)->GetObject();
4210 SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj);
4211 if( pArr )
4213 sal_Int32 nLower, nUpper;
4214 short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1;
4215 if( !pArr->GetDim32( nDim, nLower, nUpper ) )
4216 StarBASIC::Error( SbERR_OUT_OF_RANGE );
4217 else
4218 rPar.Get(0)->PutLong( nUpper );
4220 else
4221 StarBASIC::Error( SbERR_MUST_HAVE_DIMS );
4224 RTLFUNC(RGB)
4226 (void)pBasic;
4227 (void)bWrite;
4229 if ( rPar.Count() != 4 )
4231 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4232 return;
4235 sal_Int32 nRed = rPar.Get(1)->GetInteger() & 0xFF;
4236 sal_Int32 nGreen = rPar.Get(2)->GetInteger() & 0xFF;
4237 sal_Int32 nBlue = rPar.Get(3)->GetInteger() & 0xFF;
4238 sal_Int32 nRGB;
4240 SbiInstance* pInst = GetSbData()->pInst;
4241 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
4242 if( bCompatibility )
4244 nRGB = (nBlue << 16) | (nGreen << 8) | nRed;
4246 else
4248 nRGB = (nRed << 16) | (nGreen << 8) | nBlue;
4250 rPar.Get(0)->PutLong( nRGB );
4253 RTLFUNC(QBColor)
4255 (void)pBasic;
4256 (void)bWrite;
4258 static const sal_Int32 pRGB[] =
4260 0x000000,
4261 0x800000,
4262 0x008000,
4263 0x808000,
4264 0x000080,
4265 0x800080,
4266 0x008080,
4267 0xC0C0C0,
4268 0x808080,
4269 0xFF0000,
4270 0x00FF00,
4271 0xFFFF00,
4272 0x0000FF,
4273 0xFF00FF,
4274 0x00FFFF,
4275 0xFFFFFF,
4278 if ( rPar.Count() != 2 )
4280 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4281 return;
4284 sal_Int16 nCol = rPar.Get(1)->GetInteger();
4285 if( nCol < 0 || nCol > 15 )
4287 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4288 return;
4290 sal_Int32 nRGB = pRGB[ nCol ];
4291 rPar.Get(0)->PutLong( nRGB );
4294 // StrConv(string, conversion, LCID)
4295 RTLFUNC(StrConv)
4297 (void)pBasic;
4298 (void)bWrite;
4300 sal_Size nArgCount = rPar.Count()-1;
4301 if( nArgCount < 2 || nArgCount > 3 )
4303 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4304 return;
4307 OUString aOldStr = rPar.Get(1)->GetOUString();
4308 sal_Int32 nConversion = rPar.Get(2)->GetLong();
4310 sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
4312 sal_Int32 nOldLen = aOldStr.getLength();
4313 if( nOldLen == 0 )
4315 // null string,return
4316 rPar.Get(0)->PutString(aOldStr);
4317 return;
4320 sal_Int32 nType = 0;
4321 if ( (nConversion & 0x03) == 3 ) // vbProperCase
4323 const CharClass& rCharClass = GetCharClass();
4324 aOldStr = rCharClass.titlecase( aOldStr.toAsciiLowerCase(), 0, nOldLen );
4326 else if ( (nConversion & 0x01) == 1 ) // vbUpperCase
4328 nType |= i18n::TransliterationModules_LOWERCASE_UPPERCASE;
4330 else if ( (nConversion & 0x02) == 2 ) // vbLowerCase
4332 nType |= i18n::TransliterationModules_UPPERCASE_LOWERCASE;
4334 if ( (nConversion & 0x04) == 4 ) // vbWide
4336 nType |= i18n::TransliterationModules_HALFWIDTH_FULLWIDTH;
4338 else if ( (nConversion & 0x08) == 8 ) // vbNarrow
4340 nType |= i18n::TransliterationModules_FULLWIDTH_HALFWIDTH;
4342 if ( (nConversion & 0x10) == 16) // vbKatakana
4344 nType |= i18n::TransliterationModules_HIRAGANA_KATAKANA;
4346 else if ( (nConversion & 0x20) == 32 ) // vbHiragana
4348 nType |= i18n::TransliterationModules_KATAKANA_HIRAGANA;
4350 OUString aNewStr( aOldStr );
4351 if( nType != 0 )
4353 uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
4354 ::utl::TransliterationWrapper aTransliterationWrapper( xContext, nType );
4355 uno::Sequence<sal_Int32> aOffsets;
4356 aTransliterationWrapper.loadModuleIfNeeded( nLanguage );
4357 aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
4360 if ( (nConversion & 0x40) == 64 ) // vbUnicode
4362 // convert the string to byte string, preserving unicode (2 bytes per character)
4363 sal_Int32 nSize = aNewStr.getLength()*2;
4364 const sal_Unicode* pSrc = aNewStr.getStr();
4365 sal_Char* pChar = new sal_Char[nSize+1];
4366 for( sal_Int32 i=0; i < nSize; i++ )
4368 pChar[i] = static_cast< sal_Char >( (i%2) ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff );
4369 if( i%2 )
4371 pSrc++;
4374 pChar[nSize] = '\0';
4375 OString aOStr(pChar);
4376 delete[] pChar;
4378 // there is no concept about default codepage in unix. so it is incorrectly in unix
4379 OUString aOUStr = OStringToOUString(aOStr, osl_getThreadTextEncoding());
4380 rPar.Get(0)->PutString( aOUStr );
4381 return;
4383 else if ( (nConversion & 0x80) == 128 ) // vbFromUnicode
4385 // there is no concept about default codepage in unix. so it is incorrectly in unix
4386 OString aOStr = OUStringToOString(aNewStr,osl_getThreadTextEncoding());
4387 const sal_Char* pChar = aOStr.getStr();
4388 sal_Int32 nArraySize = aOStr.getLength();
4389 SbxDimArray* pArray = new SbxDimArray(SbxBYTE);
4390 bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() );
4391 if(nArraySize)
4393 if( bIncIndex )
4395 pArray->AddDim( 1, nArraySize );
4397 else
4399 pArray->AddDim( 0, nArraySize-1 );
4402 else
4404 pArray->unoAddDim( 0, -1 );
4407 for( sal_Int32 i=0; i< nArraySize; i++)
4409 SbxVariable* pNew = new SbxVariable( SbxBYTE );
4410 pNew->PutByte(*pChar);
4411 pChar++;
4412 pNew->SetFlag( SBX_WRITE );
4413 short index = i;
4414 if( bIncIndex )
4416 ++index;
4418 // coverity[callee_ptr_arith]
4419 pArray->Put( pNew, &index );
4422 SbxVariableRef refVar = rPar.Get(0);
4423 SbxFlagBits nFlags = refVar->GetFlags();
4424 refVar->ResetFlag( SBX_FIXED );
4425 refVar->PutObject( pArray );
4426 refVar->SetFlags( nFlags );
4427 refVar->SetParameters( NULL );
4428 return;
4430 rPar.Get(0)->PutString(aNewStr);
4434 RTLFUNC(Beep)
4436 (void)pBasic;
4437 (void)bWrite;
4439 if ( rPar.Count() != 1 )
4441 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4442 return;
4444 Sound::Beep();
4447 RTLFUNC(Load)
4449 (void)pBasic;
4450 (void)bWrite;
4452 if( rPar.Count() != 2 )
4454 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4455 return;
4459 SbxBase* pObj = static_cast<SbxObject*>(rPar.Get(1)->GetObject());
4460 if ( pObj )
4462 if( pObj->IsA( TYPE( SbUserFormModule ) ) )
4464 static_cast<SbUserFormModule*>(pObj)->Load();
4466 else if( pObj->IsA( TYPE( SbxObject ) ) )
4468 SbxVariable* pVar = static_cast<SbxObject*>(pObj)->Find( OUString("Load"), SbxCLASS_METHOD );
4469 if( pVar )
4471 pVar->GetInteger();
4477 RTLFUNC(Unload)
4479 (void)pBasic;
4480 (void)bWrite;
4482 rPar.Get(0)->PutEmpty();
4483 if( rPar.Count() != 2 )
4485 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4486 return;
4490 SbxBase* pObj = static_cast<SbxObject*>(rPar.Get(1)->GetObject());
4491 if ( pObj )
4493 if( pObj->IsA( TYPE( SbUserFormModule ) ) )
4495 SbUserFormModule* pFormModule = static_cast<SbUserFormModule*>(pObj);
4496 pFormModule->Unload();
4498 else if( pObj->IsA( TYPE( SbxObject ) ) )
4500 SbxVariable* pVar = static_cast<SbxObject*>(pObj)->Find( OUString("Unload"), SbxCLASS_METHOD );
4501 if( pVar )
4503 pVar->GetInteger();
4509 RTLFUNC(LoadPicture)
4511 (void)pBasic;
4512 (void)bWrite;
4514 if( rPar.Count() != 2 )
4516 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4517 return;
4520 OUString aFileURL = getFullPath( rPar.Get(1)->GetOUString() );
4521 boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aFileURL, StreamMode::READ ));
4522 if( pStream )
4524 Bitmap aBmp;
4525 ReadDIB(aBmp, *pStream, true);
4526 Graphic aGraphic(aBmp);
4528 SbxObjectRef xRef = new SbStdPicture;
4529 static_cast<SbStdPicture*>((SbxObject*)xRef)->SetGraphic( aGraphic );
4530 rPar.Get(0)->PutObject( xRef );
4534 RTLFUNC(SavePicture)
4536 (void)pBasic;
4537 (void)bWrite;
4539 rPar.Get(0)->PutEmpty();
4540 if( rPar.Count() != 3 )
4542 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4543 return;
4546 SbxBase* pObj = static_cast<SbxObject*>(rPar.Get(1)->GetObject());
4547 if( pObj->IsA( TYPE( SbStdPicture ) ) )
4549 SvFileStream aOStream( rPar.Get(2)->GetOUString(), StreamMode::WRITE | StreamMode::TRUNC );
4550 Graphic aGraphic = static_cast<SbStdPicture*>(pObj)->GetGraphic();
4551 WriteGraphic( aOStream, aGraphic );
4558 RTLFUNC(MsgBox)
4560 (void)pBasic;
4561 (void)bWrite;
4563 static const WinBits nStyleMap[] =
4565 WB_OK, // MB_OK
4566 WB_OK_CANCEL, // MB_OKCANCEL
4567 WB_ABORT_RETRY_IGNORE, // MB_ABORTRETRYIGNORE
4568 WB_YES_NO_CANCEL, // MB_YESNOCANCEL
4569 WB_YES_NO, // MB_YESNO
4570 WB_RETRY_CANCEL // MB_RETRYCANCEL
4572 static const sal_Int16 nButtonMap[] =
4574 2, // RET_CANCEL is 0
4575 1, // RET_OK is 1
4576 6, // RET_YES is 2
4577 7, // RET_NO is 3
4578 4 // RET_RETRY is 4
4582 sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
4583 if( nArgCount < 2 || nArgCount > 6 )
4585 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4586 return;
4588 WinBits nWinBits;
4589 WinBits nType = 0; // MB_OK
4590 if( nArgCount >= 3 )
4591 nType = (WinBits)rPar.Get(2)->GetInteger();
4592 WinBits nStyle = nType;
4593 nStyle &= 15; // delete bits 4-16
4594 if( nStyle > 5 )
4596 nStyle = 0;
4598 nWinBits = nStyleMap[ nStyle ];
4600 WinBits nWinDefBits;
4601 nWinDefBits = (WB_DEF_OK | WB_DEF_RETRY | WB_DEF_YES);
4602 if( nType & 256 )
4604 if( nStyle == 5 )
4606 nWinDefBits = WB_DEF_CANCEL;
4608 else if( nStyle == 2 )
4610 nWinDefBits = WB_DEF_RETRY;
4612 else
4614 nWinDefBits = (WB_DEF_CANCEL | WB_DEF_RETRY | WB_DEF_NO);
4617 else if( nType & 512 )
4619 if( nStyle == 2)
4621 nWinDefBits = WB_DEF_IGNORE;
4623 else
4625 nWinDefBits = WB_DEF_CANCEL;
4628 else if( nStyle == 2)
4630 nWinDefBits = WB_DEF_CANCEL;
4632 nWinBits |= nWinDefBits;
4634 OUString aMsg = rPar.Get(1)->GetOUString();
4635 OUString aTitle;
4636 if( nArgCount >= 4 )
4638 aTitle = rPar.Get(3)->GetOUString();
4640 else
4642 aTitle = Application::GetAppName();
4645 nType &= (16+32+64);
4646 VclPtr<MessBox> pBox;
4648 SolarMutexGuard aSolarGuard;
4650 vcl::Window* pParent = Application::GetDefDialogParent();
4651 switch( nType )
4653 case 16:
4654 pBox.reset(VclPtr<ErrorBox>::Create( pParent, nWinBits, aMsg ));
4655 break;
4656 case 32:
4657 pBox.reset(VclPtr<QueryBox>::Create( pParent, nWinBits, aMsg ));
4658 break;
4659 case 48:
4660 pBox.reset(VclPtr<WarningBox>::Create( pParent, nWinBits, aMsg ));
4661 break;
4662 case 64:
4663 pBox.reset(VclPtr<InfoBox>::Create( pParent, nWinBits, aMsg ));
4664 break;
4665 default:
4666 pBox.reset(VclPtr<MessBox>::Create( pParent, nWinBits, aTitle, aMsg ));
4668 pBox->SetText( aTitle );
4669 short nRet = pBox->Execute();
4670 sal_Int16 nMappedRet;
4671 if( nStyle == 2 )
4673 nMappedRet = nRet;
4674 if( nMappedRet == 0 )
4676 nMappedRet = 3; // Abort
4679 else
4681 nMappedRet = nButtonMap[ nRet ];
4683 rPar.Get(0)->PutInteger( nMappedRet );
4684 pBox.disposeAndClear();
4687 RTLFUNC(SetAttr)
4689 (void)pBasic;
4690 (void)bWrite;
4692 rPar.Get(0)->PutEmpty();
4693 if ( rPar.Count() == 3 )
4695 OUString aStr = rPar.Get(1)->GetOUString();
4696 sal_Int16 nFlags = rPar.Get(2)->GetInteger();
4698 if( hasUno() )
4700 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
4701 if( xSFI.is() )
4705 bool bReadOnly = (nFlags & Sb_ATTR_READONLY) != 0;
4706 xSFI->setReadOnly( aStr, bReadOnly );
4707 bool bHidden = (nFlags & Sb_ATTR_HIDDEN) != 0;
4708 xSFI->setHidden( aStr, bHidden );
4710 catch(const Exception & )
4712 StarBASIC::Error( ERRCODE_IO_GENERAL );
4717 else
4719 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4723 RTLFUNC(Reset)
4725 (void)pBasic;
4726 (void)bWrite;
4727 (void)rPar;
4729 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
4730 if (pIO)
4732 pIO->CloseAll();
4736 RTLFUNC(DumpAllObjects)
4738 (void)pBasic;
4739 (void)bWrite;
4741 sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
4742 if( nArgCount < 2 || nArgCount > 3 )
4744 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4746 else if( !pBasic )
4748 StarBASIC::Error( SbERR_INTERNAL_ERROR );
4750 else
4752 SbxObject* p = pBasic;
4753 while( p->GetParent() )
4755 p = p->GetParent();
4757 SvFileStream aStrm( rPar.Get( 1 )->GetOUString(),
4758 StreamMode::WRITE | StreamMode::TRUNC );
4759 p->Dump( aStrm, rPar.Get( 2 )->GetBool() );
4760 aStrm.Close();
4761 if( aStrm.GetError() != SVSTREAM_OK )
4763 StarBASIC::Error( SbERR_IO_ERROR );
4769 RTLFUNC(FileExists)
4771 (void)pBasic;
4772 (void)bWrite;
4774 if ( rPar.Count() == 2 )
4776 OUString aStr = rPar.Get(1)->GetOUString();
4777 bool bExists = false;
4779 if( hasUno() )
4781 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
4782 if( xSFI.is() )
4786 bExists = xSFI->exists( aStr );
4788 catch(const Exception & )
4790 StarBASIC::Error( ERRCODE_IO_GENERAL );
4794 else
4796 DirectoryItem aItem;
4797 FileBase::RC nRet = DirectoryItem::get( getFullPath( aStr ), aItem );
4798 bExists = (nRet == FileBase::E_None);
4800 rPar.Get(0)->PutBool( bExists );
4802 else
4804 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4808 RTLFUNC(Partition)
4810 (void)pBasic;
4811 (void)bWrite;
4813 if ( rPar.Count() != 5 )
4815 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4816 return;
4819 sal_Int32 nNumber = rPar.Get(1)->GetLong();
4820 sal_Int32 nStart = rPar.Get(2)->GetLong();
4821 sal_Int32 nStop = rPar.Get(3)->GetLong();
4822 sal_Int32 nInterval = rPar.Get(4)->GetLong();
4824 if( nStart < 0 || nStop <= nStart || nInterval < 1 )
4826 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4827 return;
4830 // the Partition function inserts leading spaces before lowervalue and uppervalue
4831 // so that they both have the same number of characters as the string
4832 // representation of the value (Stop + 1). This ensures that if you use the output
4833 // of the Partition function with several values of Number, the resulting text
4834 // will be handled properly during any subsequent sort operation.
4836 // calculate the maximun number of characters before lowervalue and uppervalue
4837 OUString aBeforeStart = OUString::number( nStart - 1 );
4838 OUString aAfterStop = OUString::number( nStop + 1 );
4839 sal_Int32 nLen1 = aBeforeStart.getLength();
4840 sal_Int32 nLen2 = aAfterStop.getLength();
4841 sal_Int32 nLen = nLen1 >= nLen2 ? nLen1:nLen2;
4843 OUStringBuffer aRetStr( nLen * 2 + 1);
4844 OUString aLowerValue;
4845 OUString aUpperValue;
4846 if( nNumber < nStart )
4848 aUpperValue = aBeforeStart;
4850 else if( nNumber > nStop )
4852 aLowerValue = aAfterStop;
4854 else
4856 sal_Int32 nLowerValue = nNumber;
4857 sal_Int32 nUpperValue = nLowerValue;
4858 if( nInterval > 1 )
4860 nLowerValue = ((( nNumber - nStart ) / nInterval ) * nInterval ) + nStart;
4861 nUpperValue = nLowerValue + nInterval - 1;
4863 aLowerValue = OUString::number( nLowerValue );
4864 aUpperValue = OUString::number( nUpperValue );
4867 nLen1 = aLowerValue.getLength();
4868 nLen2 = aUpperValue.getLength();
4870 if( nLen > nLen1 )
4872 // appending the leading spaces for the lowervalue
4873 for ( sal_Int32 i= (nLen - nLen1) ; i > 0; --i )
4875 aRetStr.appendAscii(" ");
4878 aRetStr.append( aLowerValue ).appendAscii(":");
4879 if( nLen > nLen2 )
4881 // appending the leading spaces for the uppervalue
4882 for ( sal_Int32 i= (nLen - nLen2) ; i > 0; --i )
4884 aRetStr.appendAscii(" ");
4887 aRetStr.append( aUpperValue );
4888 rPar.Get(0)->PutString( aRetStr.makeStringAndClear());
4891 #endif
4893 static long GetDayDiff( const Date& rDate )
4895 Date aRefDate( 1,1,1900 );
4896 long nDiffDays;
4897 if ( aRefDate > rDate )
4899 nDiffDays = (long)(aRefDate - rDate);
4900 nDiffDays *= -1;
4902 else
4904 nDiffDays = (long)(rDate - aRefDate);
4906 nDiffDays += 2; // adjustment VisualBasic: 1.Jan.1900 == 2
4907 return nDiffDays;
4910 sal_Int16 implGetDateYear( double aDate )
4912 Date aRefDate( 1,1,1900 );
4913 long nDays = (long) aDate;
4914 nDays -= 2; // standardize: 1.1.1900 => 0.0
4915 aRefDate += nDays;
4916 sal_Int16 nRet = (sal_Int16)( aRefDate.GetYear() );
4917 return nRet;
4920 bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, double& rdRet )
4922 #if HAVE_FEATURE_SCRIPTING
4923 if ( nYear < 30 && SbiRuntime::isVBAEnabled() )
4925 nYear += 2000;
4927 else
4928 #endif
4930 if ( nYear < 100 )
4932 nYear += 1900;
4935 Date aCurDate( nDay, nMonth, nYear );
4936 if ((nYear < 100 || nYear > 9999) )
4938 #if HAVE_FEATURE_SCRIPTING
4939 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4940 #endif
4941 return false;
4944 #if HAVE_FEATURE_SCRIPTING
4945 if ( !SbiRuntime::isVBAEnabled() )
4946 #endif
4948 if ( (nMonth < 1 || nMonth > 12 )||
4949 (nDay < 1 || nDay > 31 ) )
4951 #if HAVE_FEATURE_SCRIPTING
4952 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4953 #endif
4954 return false;
4957 #if HAVE_FEATURE_SCRIPTING
4958 else
4960 // grab the year & month
4961 aCurDate = Date( 1, (( nMonth % 12 ) > 0 ) ? ( nMonth % 12 ) : 12 + ( nMonth % 12 ), nYear );
4963 // adjust year based on month value
4964 // e.g. 2000, 0, xx = 1999, 12, xx ( or December of the previous year )
4965 // 2000, 13, xx = 2001, 1, xx ( or January of the following year )
4966 if( ( nMonth < 1 ) || ( nMonth > 12 ) )
4968 // inacurrate around leap year, don't use days to calculate,
4969 // just modify the months directory
4970 sal_Int16 nYearAdj = ( nMonth /12 ); // default to positive months inputed
4971 if ( nMonth <=0 )
4973 nYearAdj = ( ( nMonth -12 ) / 12 );
4975 aCurDate.SetYear( aCurDate.GetYear() + nYearAdj );
4978 // adjust day value,
4979 // e.g. 2000, 2, 0 = 2000, 1, 31 or the last day of the previous month
4980 // 2000, 1, 32 = 2000, 2, 1 or the first day of the following month
4981 if( ( nDay < 1 ) || ( nDay > aCurDate.GetDaysInMonth() ) )
4983 aCurDate += nDay - 1;
4985 else
4987 aCurDate.SetDay( nDay );
4990 #endif
4992 long nDiffDays = GetDayDiff( aCurDate );
4993 rdRet = (double)nDiffDays;
4994 return true;
4997 double implTimeSerial( sal_Int16 nHours, sal_Int16 nMinutes, sal_Int16 nSeconds )
4999 return
5000 static_cast<double>( nHours * ::tools::Time::secondPerHour +
5001 nMinutes * ::tools::Time::secondPerMinute +
5002 nSeconds)
5004 static_cast<double>( ::tools::Time::secondPerDay );
5007 bool implDateTimeSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
5008 sal_Int16 nHour, sal_Int16 nMinute, sal_Int16 nSecond,
5009 double& rdRet )
5011 double dDate;
5012 if(!implDateSerial(nYear, nMonth, nDay, dDate))
5013 return false;
5014 rdRet += dDate + implTimeSerial(nHour, nMinute, nSecond);
5015 return true;
5018 sal_Int16 implGetMinute( double dDate )
5020 if( dDate < 0.0 )
5022 dDate *= -1.0;
5024 double nFrac = dDate - floor( dDate );
5025 nFrac *= 86400.0;
5026 sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
5027 sal_Int16 nTemp = (sal_Int16)(nSeconds % 3600);
5028 sal_Int16 nMin = nTemp / 60;
5029 return nMin;
5032 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */