fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / basic / source / runtime / methods.cxx
blob31825c8277dcc13140cfab7cf1a74e59fb2a3eee
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 <tools/date.hxx>
21 #include <basic/sbxvar.hxx>
22 #include <basic/sbuno.hxx>
23 #include <osl/process.h>
24 #include <vcl/svapp.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/sound.hxx>
27 #include <tools/wintypes.hxx>
28 #include <vcl/msgbox.hxx>
29 #include <basic/sbx.hxx>
30 #include <svl/zforlist.hxx>
31 #include <rtl/math.hxx>
32 #include <tools/urlobj.hxx>
33 #include <osl/time.h>
34 #include <unotools/charclass.hxx>
35 #include <unotools/ucbstreamhelper.hxx>
36 #include <tools/wldcrd.hxx>
37 #include <i18nlangtag/lang.h>
38 #include <rtl/string.hxx>
39 #include <rtl/strbuf.hxx>
41 #include "runtime.hxx"
42 #include "sbunoobj.hxx"
43 #include <osl/file.hxx>
44 #include "errobject.hxx"
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/string.hxx>
49 #include <com/sun/star/uno/Sequence.hxx>
50 #include <com/sun/star/util/DateTime.hpp>
51 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
52 #include <com/sun/star/lang/Locale.hpp>
53 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
54 #include <com/sun/star/script/XErrorQuery.hpp>
55 #include <ooo/vba/XHelperInterface.hpp>
56 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
58 using namespace comphelper;
59 using namespace osl;
60 using namespace com::sun::star;
61 using namespace com::sun::star::lang;
62 using namespace com::sun::star::uno;
64 #include "date.hxx"
65 #include "stdobj.hxx"
66 #include <basic/sbstdobj.hxx>
67 #include "rtlproto.hxx"
68 #include "basrid.hxx"
69 #include "image.hxx"
70 #include "sb.hrc"
71 #include "iosys.hxx"
72 #include "ddectrl.hxx"
73 #include <sbintern.hxx>
74 #include <basic/vbahelper.hxx>
76 #include <list>
77 #include <math.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <ctype.h>
82 SbxVariable* getDefaultProp( SbxVariable* pRef );
84 #if defined (WNT)
85 #include <direct.h> // _getdcwd get current work directory, _chdrive
86 #endif
88 #ifdef UNX
89 #include <errno.h>
90 #include <unistd.h>
91 #endif
93 #include <basic/sbobjmod.hxx>
95 #ifdef WNT
96 #if defined _MSC_VER
97 #pragma warning (push, 1)
98 #pragma warning (disable: 4005)
99 #endif
100 #include <windows.h>
101 #if defined _MSC_VER
102 #pragma warning (pop)
103 #endif
104 #include <io.h>
105 #undef GetObject
106 #undef GradientSyle_RECT
107 #endif
109 #ifndef DISABLE_SCRIPTING
111 // from source/classes/sbxmod.cxx
112 uno::Reference< frame::XModel > getDocumentModel( StarBASIC* );
114 static void FilterWhiteSpace( OUString& rStr )
116 if (rStr.isEmpty())
118 return;
120 OUStringBuffer aRet;
122 for (sal_Int32 i = 0; i < rStr.getLength(); ++i)
124 sal_Unicode cChar = rStr[i];
125 if ((cChar != ' ') && (cChar != '\t') &&
126 (cChar != '\n') && (cChar != '\r'))
128 aRet.append(cChar);
132 rStr = aRet.makeStringAndClear();
135 static long GetDayDiff( const Date& rDate );
137 static const CharClass& GetCharClass( void )
139 static bool bNeedsInit = true;
140 static LanguageTag aLanguageTag( LANGUAGE_SYSTEM);
141 if( bNeedsInit )
143 bNeedsInit = false;
144 aLanguageTag = Application::GetSettings().GetLanguageTag();
146 static CharClass aCharClass( aLanguageTag );
147 return aCharClass;
150 static inline bool isFolder( FileStatus::Type aType )
152 return ( aType == FileStatus::Directory || aType == FileStatus::Volume );
156 //*** UCB file access ***
158 // Converts possibly relative paths to absolute paths
159 // according to the setting done by ChDir/ChDrive
160 OUString getFullPath( const OUString& aRelPath )
162 OUString aFileURL;
164 // #80204 Try first if it already is a valid URL
165 INetURLObject aURLObj( aRelPath );
166 aFileURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE );
168 if( aFileURL.isEmpty() )
170 File::getFileURLFromSystemPath( aRelPath, aFileURL );
173 return aFileURL;
176 // TODO: -> SbiGlobals
177 static uno::Reference< ucb::XSimpleFileAccess3 > getFileAccess( void )
179 static uno::Reference< ucb::XSimpleFileAccess3 > xSFI;
180 if( !xSFI.is() )
182 xSFI = ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
184 return xSFI;
189 // Properties and methods lie down the return value at the Get (bPut = sal_False) in the
190 // element 0 of the Argv; the value of element 0 is saved at Put (bPut = sal_True)
192 // CreateObject( class )
194 RTLFUNC(CreateObject)
196 (void)bWrite;
198 OUString aClass( rPar.Get( 1 )->GetOUString() );
199 SbxObjectRef p = SbxBase::CreateObject( aClass );
200 if( !p )
201 StarBASIC::Error( SbERR_CANNOT_LOAD );
202 else
204 // Convenience: enter BASIC as parent
205 p->SetParent( pBasic );
206 rPar.Get( 0 )->PutObject( p );
210 // Error( n )
212 RTLFUNC(Error)
214 (void)bWrite;
216 if( !pBasic )
217 StarBASIC::Error( SbERR_INTERNAL_ERROR );
218 else
220 OUString aErrorMsg;
221 SbError nErr = 0L;
222 sal_Int32 nCode = 0;
223 if( rPar.Count() == 1 )
225 nErr = StarBASIC::GetErrBasic();
226 aErrorMsg = StarBASIC::GetErrorMsg();
228 else
230 nCode = rPar.Get( 1 )->GetLong();
231 if( nCode > 65535L )
233 StarBASIC::Error( SbERR_CONVERSION );
235 else
237 nErr = StarBASIC::GetSfxFromVBError( (sal_uInt16)nCode );
241 bool bVBA = SbiRuntime::isVBAEnabled();
242 OUString tmpErrMsg;
243 if( bVBA && !aErrorMsg.isEmpty())
245 tmpErrMsg = aErrorMsg;
247 else
249 pBasic->MakeErrorText( nErr, aErrorMsg );
250 tmpErrMsg = pBasic->GetErrorText();
252 // If this rtlfunc 'Error' passed a errcode the same as the active Err Objects's
253 // current err then return the description for the error message if it is set
254 // ( complicated isn't it ? )
255 if ( bVBA && rPar.Count() > 1 )
257 uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() );
258 if ( xErrObj.is() && xErrObj->getNumber() == nCode && !xErrObj->getDescription().isEmpty() )
260 tmpErrMsg = xErrObj->getDescription();
263 rPar.Get( 0 )->PutString( tmpErrMsg );
267 // Sinus
269 RTLFUNC(Sin)
271 (void)pBasic;
272 (void)bWrite;
274 if ( rPar.Count() < 2 )
275 StarBASIC::Error( SbERR_BAD_ARGUMENT );
276 else
278 SbxVariableRef pArg = rPar.Get( 1 );
279 rPar.Get( 0 )->PutDouble( sin( pArg->GetDouble() ) );
284 RTLFUNC(Cos)
286 (void)pBasic;
287 (void)bWrite;
289 if ( rPar.Count() < 2 )
290 StarBASIC::Error( SbERR_BAD_ARGUMENT );
291 else
293 SbxVariableRef pArg = rPar.Get( 1 );
294 rPar.Get( 0 )->PutDouble( cos( pArg->GetDouble() ) );
299 RTLFUNC(Atn)
301 (void)pBasic;
302 (void)bWrite;
304 if ( rPar.Count() < 2 )
305 StarBASIC::Error( SbERR_BAD_ARGUMENT );
306 else
308 SbxVariableRef pArg = rPar.Get( 1 );
309 rPar.Get( 0 )->PutDouble( atan( pArg->GetDouble() ) );
315 RTLFUNC(Abs)
317 (void)pBasic;
318 (void)bWrite;
320 if ( rPar.Count() < 2 )
322 StarBASIC::Error( SbERR_BAD_ARGUMENT );
324 else
326 SbxVariableRef pArg = rPar.Get( 1 );
327 rPar.Get( 0 )->PutDouble( fabs( pArg->GetDouble() ) );
332 RTLFUNC(Asc)
334 (void)pBasic;
335 (void)bWrite;
337 if ( rPar.Count() < 2 )
339 StarBASIC::Error( SbERR_BAD_ARGUMENT );
341 else
343 SbxVariableRef pArg = rPar.Get( 1 );
344 OUString aStr( pArg->GetOUString() );
345 if ( aStr.isEmpty())
347 StarBASIC::Error( SbERR_BAD_ARGUMENT );
348 rPar.Get(0)->PutEmpty();
350 else
352 sal_Unicode aCh = aStr[0];
353 rPar.Get(0)->PutLong( aCh );
358 void implChr( SbxArray& rPar, bool bChrW )
360 if ( rPar.Count() < 2 )
362 StarBASIC::Error( SbERR_BAD_ARGUMENT );
364 else
366 SbxVariableRef pArg = rPar.Get( 1 );
368 OUString aStr;
369 if( !bChrW && SbiRuntime::isVBAEnabled() )
371 sal_Char c = static_cast<sal_Char>(pArg->GetByte());
372 aStr = OUString(&c, 1, osl_getThreadTextEncoding());
374 else
376 sal_Unicode aCh = static_cast<sal_Unicode>(pArg->GetUShort());
377 aStr = OUString(aCh);
379 rPar.Get(0)->PutString( aStr );
383 RTLFUNC(Chr)
385 (void)pBasic;
386 (void)bWrite;
388 bool bChrW = false;
389 implChr( rPar, bChrW );
392 RTLFUNC(ChrW)
394 (void)pBasic;
395 (void)bWrite;
397 bool bChrW = true;
398 implChr( rPar, bChrW );
402 #ifdef UNX
403 #define _PATH_INCR 250
404 #endif
406 RTLFUNC(CurDir)
408 (void)pBasic;
409 (void)bWrite;
411 // #57064 Although this function doesn't work with DirEntry, it isn't touched
412 // by the adjustment to virtual URLs, as, using the DirEntry-functionality,
413 // there's no possibility to detect the current one in a way that a virtual URL
414 // could be delivered.
416 #if defined (WNT)
417 int nCurDir = 0; // Current dir // JSM
418 if ( rPar.Count() == 2 )
420 OUString aDrive = rPar.Get(1)->GetOUString();
421 if ( aDrive.getLength() != 1 )
423 StarBASIC::Error( SbERR_BAD_ARGUMENT );
424 return;
426 else
428 nCurDir = (int)aDrive[0];
429 if ( !isalpha( nCurDir ) )
431 StarBASIC::Error( SbERR_BAD_ARGUMENT );
432 return;
434 else
436 nCurDir -= ( 'A' - 1 );
440 char* pBuffer = new char[ _MAX_PATH ];
441 if ( _getdcwd( nCurDir, pBuffer, _MAX_PATH ) != 0 )
443 rPar.Get(0)->PutString( OUString::createFromAscii( pBuffer ) );
445 else
447 StarBASIC::Error( SbERR_NO_DEVICE );
449 delete [] pBuffer;
451 #elif defined( UNX )
453 int nSize = _PATH_INCR;
454 char* pMem;
455 while( true )
457 pMem = new char[nSize];
458 if( !pMem )
460 StarBASIC::Error( SbERR_NO_MEMORY );
461 return;
463 if( getcwd( pMem, nSize-1 ) != NULL )
465 rPar.Get(0)->PutString( OUString::createFromAscii(pMem) );
466 delete [] pMem;
467 return;
469 if( errno != ERANGE )
471 StarBASIC::Error( SbERR_INTERNAL_ERROR );
472 delete [] pMem;
473 return;
475 delete [] pMem;
476 nSize += _PATH_INCR;
479 #endif
482 RTLFUNC(ChDir)
484 (void)bWrite;
486 rPar.Get(0)->PutEmpty();
487 if (rPar.Count() == 2)
489 // VBA: track current directory per document type (separately for Writer, Calc, Impress, etc.)
490 if( SbiRuntime::isVBAEnabled() )
492 ::basic::vba::registerCurrentDirectory( getDocumentModel( pBasic ), rPar.Get(1)->GetOUString() );
495 else
497 StarBASIC::Error( SbERR_BAD_ARGUMENT );
501 RTLFUNC(ChDrive)
503 (void)pBasic;
504 (void)bWrite;
506 rPar.Get(0)->PutEmpty();
507 if (rPar.Count() != 2)
509 StarBASIC::Error( SbERR_BAD_ARGUMENT );
514 // Implementation of StepRENAME with UCB
515 void implStepRenameUCB( const OUString& aSource, const OUString& aDest )
517 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
518 if( xSFI.is() )
522 OUString aSourceFullPath = getFullPath( aSource );
523 if( !xSFI->exists( aSourceFullPath ) )
525 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
526 return;
529 OUString aDestFullPath = getFullPath( aDest );
530 if( xSFI->exists( aDestFullPath ) )
532 StarBASIC::Error( SbERR_FILE_EXISTS );
534 else
536 xSFI->move( aSourceFullPath, aDestFullPath );
539 catch(const Exception & )
541 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
546 // Implementation of StepRENAME with OSL
547 void implStepRenameOSL( const OUString& aSource, const OUString& aDest )
549 FileBase::RC nRet = File::move( getFullPath( aSource ), getFullPath( aDest ) );
550 if( nRet != FileBase::E_None )
552 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
556 RTLFUNC(FileCopy)
558 (void)pBasic;
559 (void)bWrite;
561 rPar.Get(0)->PutEmpty();
562 if (rPar.Count() == 3)
564 OUString aSource = rPar.Get(1)->GetOUString();
565 OUString aDest = rPar.Get(2)->GetOUString();
566 if( hasUno() )
568 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
569 if( xSFI.is() )
573 xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) );
575 catch(const Exception & )
577 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
581 else
583 FileBase::RC nRet = File::copy( getFullPath( aSource ), getFullPath( aDest ) );
584 if( nRet != FileBase::E_None )
586 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
590 else
591 StarBASIC::Error( SbERR_BAD_ARGUMENT );
594 RTLFUNC(Kill)
596 (void)pBasic;
597 (void)bWrite;
599 rPar.Get(0)->PutEmpty();
600 if (rPar.Count() == 2)
602 OUString aFileSpec = rPar.Get(1)->GetOUString();
604 if( hasUno() )
606 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
607 if( xSFI.is() )
609 OUString aFullPath = getFullPath( aFileSpec );
610 if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) )
612 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
613 return;
617 xSFI->kill( aFullPath );
619 catch(const Exception & )
621 StarBASIC::Error( ERRCODE_IO_GENERAL );
625 else
627 File::remove( getFullPath( aFileSpec ) );
630 else
632 StarBASIC::Error( SbERR_BAD_ARGUMENT );
636 RTLFUNC(MkDir)
638 (void)pBasic;
639 (void)bWrite;
641 rPar.Get(0)->PutEmpty();
642 if (rPar.Count() == 2)
644 OUString aPath = rPar.Get(1)->GetOUString();
645 if ( SbiRuntime::isVBAEnabled() )
647 // In vba if the full path is not specified then
648 // folder is created relative to the curdir
649 INetURLObject aURLObj( getFullPath( aPath ) );
650 if ( aURLObj.GetProtocol() != INET_PROT_FILE )
652 SbxArrayRef pPar = new SbxArray();
653 SbxVariableRef pResult = new SbxVariable();
654 SbxVariableRef pParam = new SbxVariable();
655 pPar->Insert( pResult, pPar->Count() );
656 pPar->Insert( pParam, pPar->Count() );
657 SbRtl_CurDir( pBasic, *pPar, bWrite );
659 rtl::OUString sCurPathURL;
660 File::getFileURLFromSystemPath( pPar->Get(0)->GetOUString(), sCurPathURL );
662 aURLObj.SetURL( sCurPathURL );
663 aURLObj.Append( aPath );
664 File::getSystemPathFromFileURL(aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI ),aPath ) ;
668 if( hasUno() )
670 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
671 if( xSFI.is() )
675 xSFI->createFolder( getFullPath( aPath ) );
677 catch(const Exception & )
679 StarBASIC::Error( ERRCODE_IO_GENERAL );
683 else
685 Directory::create( getFullPath( aPath ) );
688 else
690 StarBASIC::Error( SbERR_BAD_ARGUMENT );
695 // In OSL only empty directories can be deleted
696 // so we have to delete all files recursively
697 void implRemoveDirRecursive( const OUString& aDirPath )
699 DirectoryItem aItem;
700 FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem );
701 bool bExists = (nRet == FileBase::E_None);
703 FileStatus aFileStatus( osl_FileStatus_Mask_Type );
704 nRet = aItem.getFileStatus( aFileStatus );
705 FileStatus::Type aType = aFileStatus.getFileType();
706 bool bFolder = isFolder( aType );
708 if( !bExists || !bFolder )
710 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
711 return;
714 Directory aDir( aDirPath );
715 nRet = aDir.open();
716 if( nRet != FileBase::E_None )
718 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
719 return;
722 for( ;; )
724 DirectoryItem aItem2;
725 nRet = aDir.getNextItem( aItem2 );
726 if( nRet != FileBase::E_None )
728 break;
730 // Handle flags
731 FileStatus aFileStatus2( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL );
732 nRet = aItem2.getFileStatus( aFileStatus2 );
733 OUString aPath = aFileStatus2.getFileURL();
735 // Directory?
736 FileStatus::Type aType2 = aFileStatus2.getFileType();
737 bool bFolder2 = isFolder( aType2 );
738 if( bFolder2 )
740 implRemoveDirRecursive( aPath );
742 else
744 File::remove( aPath );
747 nRet = aDir.close();
749 nRet = Directory::remove( aDirPath );
753 RTLFUNC(RmDir)
755 (void)pBasic;
756 (void)bWrite;
758 rPar.Get(0)->PutEmpty();
759 if (rPar.Count() == 2)
761 OUString aPath = rPar.Get(1)->GetOUString();
762 if( hasUno() )
764 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
765 if( xSFI.is() )
769 if( !xSFI->isFolder( aPath ) )
771 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
772 return;
774 SbiInstance* pInst = GetSbData()->pInst;
775 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
776 if( bCompatibility )
778 Sequence< OUString > aContent = xSFI->getFolderContents( aPath, true );
779 sal_Int32 nCount = aContent.getLength();
780 if( nCount > 0 )
782 StarBASIC::Error( SbERR_ACCESS_ERROR );
783 return;
787 xSFI->kill( getFullPath( aPath ) );
789 catch(const Exception & )
791 StarBASIC::Error( ERRCODE_IO_GENERAL );
795 else
797 implRemoveDirRecursive( getFullPath( aPath ) );
800 else
802 StarBASIC::Error( SbERR_BAD_ARGUMENT );
806 RTLFUNC(SendKeys)
808 (void)pBasic;
809 (void)bWrite;
811 rPar.Get(0)->PutEmpty();
812 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
815 RTLFUNC(Exp)
817 (void)pBasic;
818 (void)bWrite;
820 if( rPar.Count() < 2 )
821 StarBASIC::Error( SbERR_BAD_ARGUMENT );
822 else
824 double aDouble = rPar.Get( 1 )->GetDouble();
825 aDouble = exp( aDouble );
826 checkArithmeticOverflow( aDouble );
827 rPar.Get( 0 )->PutDouble( aDouble );
831 RTLFUNC(FileLen)
833 (void)pBasic;
834 (void)bWrite;
836 if ( rPar.Count() < 2 )
838 StarBASIC::Error( SbERR_BAD_ARGUMENT );
840 else
842 SbxVariableRef pArg = rPar.Get( 1 );
843 OUString aStr( pArg->GetOUString() );
844 sal_Int32 nLen = 0;
845 if( hasUno() )
847 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
848 if( xSFI.is() )
852 nLen = xSFI->getSize( getFullPath( aStr ) );
854 catch(const Exception & )
856 StarBASIC::Error( ERRCODE_IO_GENERAL );
860 else
862 DirectoryItem aItem;
863 DirectoryItem::get( getFullPath( aStr ), aItem );
864 FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
865 aItem.getFileStatus( aFileStatus );
866 nLen = (sal_Int32)aFileStatus.getFileSize();
868 rPar.Get(0)->PutLong( (long)nLen );
873 RTLFUNC(Hex)
875 (void)pBasic;
876 (void)bWrite;
878 if ( rPar.Count() < 2 )
880 StarBASIC::Error( SbERR_BAD_ARGUMENT );
882 else
884 SbxVariableRef pArg = rPar.Get( 1 );
885 // converting value to unsigned and limit to 2 or 4 byte representation
886 sal_uInt32 nVal = pArg->IsInteger() ?
887 static_cast<sal_uInt16>(pArg->GetInteger()) :
888 static_cast<sal_uInt32>(pArg->GetLong());
889 OUString aStr(OUString::valueOf( sal_Int64(nVal), 16 ));
890 aStr = aStr.toAsciiUpperCase();
891 rPar.Get(0)->PutString( aStr );
895 RTLFUNC(FuncCaller)
897 (void)pBasic;
898 (void)bWrite;
899 if ( SbiRuntime::isVBAEnabled() && GetSbData()->pInst && GetSbData()->pInst->pRun )
901 if ( GetSbData()->pInst->pRun->GetExternalCaller() )
902 *rPar.Get(0) = *GetSbData()->pInst->pRun->GetExternalCaller();
903 else
905 SbxVariableRef pVar = new SbxVariable(SbxVARIANT);
906 *rPar.Get(0) = *pVar;
909 else
911 StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
915 // InStr( [start],string,string,[compare] )
917 RTLFUNC(InStr)
919 (void)pBasic;
920 (void)bWrite;
922 sal_uIntPtr nArgCount = rPar.Count()-1;
923 if ( nArgCount < 2 )
924 StarBASIC::Error( SbERR_BAD_ARGUMENT );
925 else
927 sal_Int32 nStartPos = 1;
928 sal_Int32 nFirstStringPos = 1;
930 if ( nArgCount >= 3 )
932 nStartPos = rPar.Get(1)->GetLong();
933 if( nStartPos <= 0 )
935 StarBASIC::Error( SbERR_BAD_ARGUMENT );
936 nStartPos = 1;
938 nFirstStringPos++;
941 SbiInstance* pInst = GetSbData()->pInst;
942 int bTextMode;
943 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
944 if( bCompatibility )
946 SbiRuntime* pRT = pInst->pRun;
947 bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
949 else
951 bTextMode = 1;;
953 if ( nArgCount == 4 )
955 bTextMode = rPar.Get(4)->GetInteger();
957 sal_Int32 nPos;
958 const OUString& rToken = rPar.Get(nFirstStringPos+1)->GetOUString();
960 // #97545 Always find empty string
961 if( rToken.isEmpty() )
963 nPos = nStartPos;
965 else
967 if( !bTextMode )
969 const OUString& rStr1 = rPar.Get(nFirstStringPos)->GetOUString();
970 nPos = rStr1.indexOf( rToken, nStartPos - 1 ) + 1;
972 else
974 OUString aStr1 = rPar.Get(nFirstStringPos)->GetOUString();
975 OUString aToken = rToken;
977 aStr1 = aStr1.toAsciiUpperCase();
978 aToken = aToken.toAsciiUpperCase();
980 nPos = aStr1.indexOf( aToken, nStartPos-1 ) + 1;
983 rPar.Get(0)->PutLong( nPos );
988 // InstrRev(string1, string2[, start[, compare]])
990 RTLFUNC(InStrRev)
992 (void)pBasic;
993 (void)bWrite;
995 sal_uIntPtr nArgCount = rPar.Count()-1;
996 if ( nArgCount < 2 )
998 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1000 else
1002 OUString aStr1 = rPar.Get(1)->GetOUString();
1003 OUString aToken = rPar.Get(2)->GetOUString();
1005 sal_Int32 nStartPos = -1;
1006 if ( nArgCount >= 3 )
1008 nStartPos = rPar.Get(3)->GetLong();
1009 if( (nStartPos <= 0 && nStartPos != -1))
1011 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1012 nStartPos = -1;
1016 SbiInstance* pInst = GetSbData()->pInst;
1017 int bTextMode;
1018 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1019 if( bCompatibility )
1021 SbiRuntime* pRT = pInst->pRun;
1022 bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
1024 else
1026 bTextMode = 1;;
1028 if ( nArgCount == 4 )
1030 bTextMode = rPar.Get(4)->GetInteger();
1032 sal_Int32 nStrLen = aStr1.getLength();
1033 if( nStartPos == -1 )
1035 nStartPos = nStrLen;
1038 sal_Int32 nPos = 0;
1039 if( nStartPos <= nStrLen )
1041 sal_Int32 nTokenLen = aToken.getLength();
1042 if( !nTokenLen )
1044 // Always find empty string
1045 nPos = nStartPos;
1047 else if( nStrLen > 0 )
1049 if( !bTextMode )
1051 nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1;
1053 else
1055 aStr1 = aStr1.toAsciiUpperCase();
1056 aToken = aToken.toAsciiUpperCase();
1058 nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1;
1062 rPar.Get(0)->PutLong( nPos );
1068 Int( 2.8 ) = 2.0
1069 Int( -2.8 ) = -3.0
1070 Fix( 2.8 ) = 2.0
1071 Fix( -2.8 ) = -2.0 <- !!
1074 RTLFUNC(Int)
1076 (void)pBasic;
1077 (void)bWrite;
1079 if ( rPar.Count() < 2 )
1080 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1081 else
1083 SbxVariableRef pArg = rPar.Get( 1 );
1084 double aDouble= pArg->GetDouble();
1086 floor( 2.8 ) = 2.0
1087 floor( -2.8 ) = -3.0
1089 aDouble = floor( aDouble );
1090 rPar.Get(0)->PutDouble( aDouble );
1096 RTLFUNC(Fix)
1098 (void)pBasic;
1099 (void)bWrite;
1101 if ( rPar.Count() < 2 )
1102 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1103 else
1105 SbxVariableRef pArg = rPar.Get( 1 );
1106 double aDouble = pArg->GetDouble();
1107 if ( aDouble >= 0.0 )
1108 aDouble = floor( aDouble );
1109 else
1110 aDouble = ceil( aDouble );
1111 rPar.Get(0)->PutDouble( aDouble );
1116 RTLFUNC(LCase)
1118 (void)pBasic;
1119 (void)bWrite;
1121 if ( rPar.Count() < 2 )
1123 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1125 else
1127 const CharClass& rCharClass = GetCharClass();
1128 OUString aStr( rPar.Get(1)->GetOUString() );
1129 aStr = rCharClass.lowercase(aStr);
1130 rPar.Get(0)->PutString( aStr );
1134 RTLFUNC(Left)
1136 (void)pBasic;
1137 (void)bWrite;
1139 if ( rPar.Count() < 3 )
1141 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1143 else
1145 OUString aStr( rPar.Get(1)->GetOUString() );
1146 sal_Int32 nResultLen = rPar.Get(2)->GetLong();
1147 if( nResultLen < 0 )
1149 nResultLen = 0;
1150 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1152 else if(nResultLen > aStr.getLength())
1154 nResultLen = aStr.getLength();
1156 aStr = aStr.copy(0, nResultLen );
1157 rPar.Get(0)->PutString( aStr );
1161 RTLFUNC(Log)
1163 (void)pBasic;
1164 (void)bWrite;
1166 if ( rPar.Count() < 2 )
1168 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1170 else
1172 double aArg = rPar.Get(1)->GetDouble();
1173 if ( aArg > 0 )
1175 double d = log( aArg );
1176 checkArithmeticOverflow( d );
1177 rPar.Get( 0 )->PutDouble( d );
1179 else
1181 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1186 RTLFUNC(LTrim)
1188 (void)pBasic;
1189 (void)bWrite;
1191 if ( rPar.Count() < 2 )
1193 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1195 else
1197 OUString aStr(comphelper::string::stripStart(rPar.Get(1)->GetOUString(), ' '));
1198 rPar.Get(0)->PutString(aStr);
1203 // Mid( String, nStart, nLength )
1205 RTLFUNC(Mid)
1207 (void)pBasic;
1208 (void)bWrite;
1210 int nArgCount = rPar.Count()-1;
1211 if ( nArgCount < 2 )
1213 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1215 else
1217 // #23178: replicate the functionality of Mid$ as a command
1218 // by adding a replacement-string as a fourth parameter.
1219 // In contrast to the original the third parameter (nLength)
1220 // can't be left out here. That's considered in bWrite already.
1221 if( nArgCount == 4 )
1223 bWrite = sal_True;
1225 OUString aArgStr = rPar.Get(1)->GetOUString();
1226 sal_Int32 nStartPos = rPar.Get(2)->GetLong();
1227 if ( nStartPos == 0 )
1229 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1231 else
1233 nStartPos--;
1234 sal_Int32 nLen = -1;
1235 bool bWriteNoLenParam = false;
1236 if ( nArgCount == 3 || bWrite )
1238 sal_Int32 n = rPar.Get(3)->GetLong();
1239 if( bWrite && n == -1 )
1241 bWriteNoLenParam = true;
1243 nLen = n;
1245 if ( bWrite )
1247 OUStringBuffer aResultStr;
1248 SbiInstance* pInst = GetSbData()->pInst;
1249 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1250 if( bCompatibility )
1252 sal_Int32 nArgLen = aArgStr.getLength();
1253 if( nStartPos + 1 > nArgLen )
1255 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1256 return;
1259 OUString aReplaceStr = rPar.Get(4)->GetOUString();
1260 sal_Int32 nReplaceStrLen = aReplaceStr.getLength();
1261 sal_Int32 nReplaceLen;
1262 if( bWriteNoLenParam )
1264 nReplaceLen = nReplaceStrLen;
1266 else
1268 nReplaceLen = nLen;
1269 if( nReplaceLen < 0 || nReplaceLen > nReplaceStrLen )
1271 nReplaceLen = nReplaceStrLen;
1275 sal_Int32 nReplaceEndPos = nStartPos + nReplaceLen;
1276 if( nReplaceEndPos > nArgLen )
1278 nReplaceLen -= (nReplaceEndPos - nArgLen);
1280 aResultStr = aArgStr;
1281 sal_Int32 nErase = nReplaceLen;
1282 aResultStr.remove( nStartPos, nErase );
1283 aResultStr.insert( nStartPos, aReplaceStr.getStr(), nReplaceLen);
1285 else
1287 aResultStr = aArgStr;
1288 sal_Int32 nTmpStartPos = nStartPos;
1289 if ( nTmpStartPos > aArgStr.getLength() )
1290 nTmpStartPos = aArgStr.getLength();
1291 else
1292 aResultStr.remove( nTmpStartPos, nLen );
1293 aResultStr.insert( nTmpStartPos, rPar.Get(4)->GetOUString().getStr(), std::min(nLen, rPar.Get(4)->GetOUString().getLength()));
1296 rPar.Get(1)->PutString( aResultStr.makeStringAndClear() );
1298 else
1300 OUString aResultStr;
1301 if(nLen < 0)
1303 aResultStr = aArgStr.copy( nStartPos);
1305 else
1307 if(nStartPos + nLen > aArgStr.getLength())
1309 nLen = aArgStr.getLength() - nStartPos;
1311 if (nLen > 0)
1312 aResultStr = aArgStr.copy( nStartPos, nLen );
1314 rPar.Get(0)->PutString( aResultStr );
1320 RTLFUNC(Oct)
1322 (void)pBasic;
1323 (void)bWrite;
1325 if ( rPar.Count() < 2 )
1327 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1329 else
1331 char aBuffer[16];
1332 SbxVariableRef pArg = rPar.Get( 1 );
1333 if ( pArg->IsInteger() )
1335 snprintf( aBuffer, sizeof(aBuffer), "%o", pArg->GetInteger() );
1337 else
1339 snprintf( aBuffer, sizeof(aBuffer), "%lo", static_cast<long unsigned int>(pArg->GetLong()) );
1341 rPar.Get(0)->PutString( OUString::createFromAscii( aBuffer ) );
1345 // Replace(expression, find, replace[, start[, count[, compare]]])
1347 RTLFUNC(Replace)
1349 (void)pBasic;
1350 (void)bWrite;
1352 sal_uIntPtr nArgCount = rPar.Count()-1;
1353 if ( nArgCount < 3 || nArgCount > 6 )
1355 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1357 else
1359 OUString aExpStr = rPar.Get(1)->GetOUString();
1360 OUString aFindStr = rPar.Get(2)->GetOUString();
1361 OUString aReplaceStr = rPar.Get(3)->GetOUString();
1363 sal_Int32 lStartPos = 1;
1364 if ( nArgCount >= 4 )
1366 if( rPar.Get(4)->GetType() != SbxEMPTY )
1368 lStartPos = rPar.Get(4)->GetLong();
1370 if( lStartPos < 1)
1372 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1373 lStartPos = 1;
1377 sal_Int32 lCount = -1;
1378 if( nArgCount >=5 )
1380 if( rPar.Get(5)->GetType() != SbxEMPTY )
1382 lCount = rPar.Get(5)->GetLong();
1384 if( lCount < -1)
1386 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1387 lCount = -1;
1391 SbiInstance* pInst = GetSbData()->pInst;
1392 int bTextMode;
1393 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1394 if( bCompatibility )
1396 SbiRuntime* pRT = pInst->pRun;
1397 bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
1399 else
1401 bTextMode = 1;
1403 if ( nArgCount == 6 )
1405 bTextMode = rPar.Get(6)->GetInteger();
1407 sal_Int32 nExpStrLen = aExpStr.getLength();
1408 sal_Int32 nFindStrLen = aFindStr.getLength();
1409 sal_Int32 nReplaceStrLen = aReplaceStr.getLength();
1411 if( lStartPos <= nExpStrLen )
1413 sal_Int32 nPos = lStartPos - 1;
1414 sal_Int32 nCounts = 0;
1415 while( lCount == -1 || lCount > nCounts )
1417 OUString aSrcStr( aExpStr );
1418 if( bTextMode )
1420 aSrcStr = aSrcStr.toAsciiUpperCase();
1421 aFindStr = aFindStr.toAsciiUpperCase();
1423 nPos = aSrcStr.indexOf( aFindStr, nPos );
1424 if( nPos >= 0 )
1426 aExpStr = aExpStr.replaceAt( nPos, nFindStrLen, aReplaceStr );
1427 nPos = nPos - nFindStrLen + nReplaceStrLen + 1;
1428 nCounts++;
1430 else
1432 break;
1436 rPar.Get(0)->PutString( aExpStr.copy( lStartPos - 1 ) );
1440 RTLFUNC(Right)
1442 (void)pBasic;
1443 (void)bWrite;
1445 if ( rPar.Count() < 3 )
1447 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1449 else
1451 const OUString& rStr = rPar.Get(1)->GetOUString();
1452 int nResultLen = rPar.Get(2)->GetLong();
1453 if( nResultLen < 0 )
1455 nResultLen = 0;
1456 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1458 int nStrLen = rStr.getLength();
1459 if ( nResultLen > nStrLen )
1461 nResultLen = nStrLen;
1463 OUString aResultStr = rStr.copy( nStrLen - nResultLen );
1464 rPar.Get(0)->PutString( aResultStr );
1468 RTLFUNC(RTL)
1470 (void)pBasic;
1471 (void)bWrite;
1473 rPar.Get( 0 )->PutObject( pBasic->getRTL() );
1476 RTLFUNC(RTrim)
1478 (void)pBasic;
1479 (void)bWrite;
1481 if ( rPar.Count() < 2 )
1483 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1485 else
1487 OUString aStr(comphelper::string::stripEnd(rPar.Get(1)->GetOUString(), ' '));
1488 rPar.Get(0)->PutString(aStr);
1492 RTLFUNC(Sgn)
1494 (void)pBasic;
1495 (void)bWrite;
1497 if ( rPar.Count() < 2 )
1499 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1501 else
1503 double aDouble = rPar.Get(1)->GetDouble();
1504 sal_Int16 nResult = 0;
1505 if ( aDouble > 0 )
1507 nResult = 1;
1509 else if ( aDouble < 0 )
1511 nResult = -1;
1513 rPar.Get(0)->PutInteger( nResult );
1517 RTLFUNC(Space)
1519 (void)pBasic;
1520 (void)bWrite;
1522 if ( rPar.Count() < 2 )
1524 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1526 else
1528 OUStringBuffer aBuf;
1529 string::padToLength(aBuf, rPar.Get(1)->GetLong(), ' ');
1530 rPar.Get(0)->PutString(aBuf.makeStringAndClear());
1534 RTLFUNC(Spc)
1536 (void)pBasic;
1537 (void)bWrite;
1539 if ( rPar.Count() < 2 )
1541 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1543 else
1545 OUStringBuffer aBuf;
1546 string::padToLength(aBuf, rPar.Get(1)->GetLong(), ' ');
1547 rPar.Get(0)->PutString(aBuf.makeStringAndClear());
1551 RTLFUNC(Sqr)
1553 (void)pBasic;
1554 (void)bWrite;
1556 if ( rPar.Count() < 2 )
1558 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1560 else
1562 double aDouble = rPar.Get(1)->GetDouble();
1563 if ( aDouble >= 0 )
1565 rPar.Get(0)->PutDouble( sqrt( aDouble ));
1567 else
1569 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1574 RTLFUNC(Str)
1576 (void)pBasic;
1577 (void)bWrite;
1579 if ( rPar.Count() < 2 )
1581 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1583 else
1585 OUString aStr;
1586 OUString aStrNew("");
1587 SbxVariableRef pArg = rPar.Get( 1 );
1588 pArg->Format( aStr );
1590 // Numbers start with a space
1591 if( pArg->IsNumericRTL() )
1593 // replace commas by points so that it's symmetric to Val!
1594 aStr = aStr.replaceFirst( ",", "." );
1596 SbiInstance* pInst = GetSbData()->pInst;
1597 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1598 if( bCompatibility )
1600 sal_Int32 nLen = aStr.getLength();
1602 const sal_Unicode* pBuf = aStr.getStr();
1604 bool bNeg = ( pBuf[0] == '-' );
1605 sal_Int32 iZeroSearch = 0;
1606 if( bNeg )
1608 aStrNew += "-";
1609 iZeroSearch++;
1611 else
1613 if( pBuf[0] != ' ' )
1615 aStrNew += " ";
1618 sal_Int32 iNext = iZeroSearch + 1;
1619 if( pBuf[iZeroSearch] == '0' && nLen > iNext && pBuf[iNext] == '.' )
1621 iZeroSearch += 1;
1623 aStrNew += aStr.copy(iZeroSearch);
1625 else
1627 aStrNew = " " + aStr;
1630 else
1632 aStrNew = aStr;
1634 rPar.Get(0)->PutString( aStrNew );
1638 RTLFUNC(StrComp)
1640 (void)pBasic;
1641 (void)bWrite;
1643 if ( rPar.Count() < 3 )
1645 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1646 rPar.Get(0)->PutEmpty();
1647 return;
1649 const OUString& rStr1 = rPar.Get(1)->GetOUString();
1650 const OUString& rStr2 = rPar.Get(2)->GetOUString();
1652 SbiInstance* pInst = GetSbData()->pInst;
1653 sal_Int16 nTextCompare;
1654 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1655 if( bCompatibility )
1657 SbiRuntime* pRT = pInst->pRun;
1658 nTextCompare = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
1660 else
1662 nTextCompare = sal_True;
1664 if ( rPar.Count() == 4 )
1665 nTextCompare = rPar.Get(3)->GetInteger();
1667 if( !bCompatibility )
1669 nTextCompare = !nTextCompare;
1671 sal_Int32 nRetValue = 0;
1672 if( nTextCompare )
1674 ::utl::TransliterationWrapper* pTransliterationWrapper = GetSbData()->pTransliterationWrapper;
1675 if( !pTransliterationWrapper )
1677 uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
1678 pTransliterationWrapper = GetSbData()->pTransliterationWrapper =
1679 new ::utl::TransliterationWrapper( xContext,
1680 i18n::TransliterationModules_IGNORE_CASE |
1681 i18n::TransliterationModules_IGNORE_KANA |
1682 i18n::TransliterationModules_IGNORE_WIDTH );
1685 LanguageType eLangType = GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
1686 pTransliterationWrapper->loadModuleIfNeeded( eLangType );
1687 nRetValue = pTransliterationWrapper->compareString( rStr1, rStr2 );
1689 else
1691 sal_Int32 aResult;
1692 aResult = rStr1.compareTo( rStr2 );
1693 if ( aResult < 0 )
1695 nRetValue = -1;
1697 else if ( aResult > 0)
1699 nRetValue = 1;
1702 rPar.Get(0)->PutInteger( sal::static_int_cast< sal_Int16 >( nRetValue ) );
1705 RTLFUNC(String)
1707 (void)pBasic;
1708 (void)bWrite;
1710 if ( rPar.Count() < 2 )
1712 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1714 else
1716 sal_Unicode aFiller;
1717 sal_Int32 lCount = rPar.Get(1)->GetLong();
1718 if( lCount < 0 || lCount > 0xffff )
1720 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1722 if( rPar.Get(2)->GetType() == SbxINTEGER )
1724 aFiller = (sal_Unicode)rPar.Get(2)->GetInteger();
1726 else
1728 const OUString& rStr = rPar.Get(2)->GetOUString();
1729 aFiller = rStr[0];
1731 OUStringBuffer aBuf(lCount);
1732 string::padToLength(aBuf, lCount, aFiller);
1733 rPar.Get(0)->PutString(aBuf.makeStringAndClear());
1737 RTLFUNC(Tan)
1739 (void)pBasic;
1740 (void)bWrite;
1742 if ( rPar.Count() < 2 )
1744 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1746 else
1748 SbxVariableRef pArg = rPar.Get( 1 );
1749 rPar.Get( 0 )->PutDouble( tan( pArg->GetDouble() ) );
1753 RTLFUNC(UCase)
1755 (void)pBasic;
1756 (void)bWrite;
1758 if ( rPar.Count() < 2 )
1760 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1762 else
1764 const CharClass& rCharClass = GetCharClass();
1765 OUString aStr( rPar.Get(1)->GetOUString() );
1766 aStr = rCharClass.uppercase( aStr );
1767 rPar.Get(0)->PutString( aStr );
1772 RTLFUNC(Val)
1774 (void)pBasic;
1775 (void)bWrite;
1777 if ( rPar.Count() < 2 )
1779 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1781 else
1783 double nResult = 0.0;
1784 char* pEndPtr;
1786 OUString aStr( rPar.Get(1)->GetOUString() );
1788 FilterWhiteSpace( aStr );
1789 if ( aStr[0] == '&' && aStr.getLength() > 1 )
1791 int nRadix = 10;
1792 char aChar = (char)aStr[1];
1793 if ( aChar == 'h' || aChar == 'H' )
1795 nRadix = 16;
1797 else if ( aChar == 'o' || aChar == 'O' )
1799 nRadix = 8;
1801 if ( nRadix != 10 )
1803 OString aByteStr(OUStringToOString(aStr, osl_getThreadTextEncoding()));
1804 sal_Int16 nlResult = (sal_Int16)strtol( aByteStr.getStr()+2, &pEndPtr, nRadix);
1805 nResult = (double)nlResult;
1808 else
1810 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
1811 sal_Int32 nParseEnd = 0;
1812 nResult = ::rtl::math::stringToDouble( aStr, '.', ',', &eStatus, &nParseEnd );
1813 if ( eStatus != rtl_math_ConversionStatus_Ok )
1814 StarBASIC::Error( SbERR_MATH_OVERFLOW );
1815 /* TODO: we should check whether all characters were parsed here,
1816 * but earlier code silently ignored trailing nonsense such as "1x"
1817 * resulting in 1 with the side effect that any alpha-only-string
1818 * like "x" resulted in 0. Not changing that now (2013-03-22) as
1819 * user macros may rely on it. */
1820 #if 0
1821 else if ( nParseEnd != aStr.getLength() )
1822 StarBASIC::Error( SbERR_CONVERSION );
1823 #endif
1826 rPar.Get(0)->PutDouble( nResult );
1831 // Helper functions for date conversion
1832 sal_Int16 implGetDateDay( double aDate )
1834 aDate -= 2.0; // standardize: 1.1.1900 => 0.0
1835 Date aRefDate( 1, 1, 1900 );
1836 if ( aDate >= 0.0 )
1838 aDate = floor( aDate );
1839 aRefDate += (sal_uIntPtr)aDate;
1841 else
1843 aDate = ceil( aDate );
1844 aRefDate -= (sal_uIntPtr)(-1.0 * aDate);
1847 sal_Int16 nRet = (sal_Int16)( aRefDate.GetDay() );
1848 return nRet;
1851 sal_Int16 implGetDateMonth( double aDate )
1853 Date aRefDate( 1,1,1900 );
1854 long nDays = (long)aDate;
1855 nDays -= 2; // standardize: 1.1.1900 => 0.0
1856 aRefDate += nDays;
1857 sal_Int16 nRet = (sal_Int16)( aRefDate.GetMonth() );
1858 return nRet;
1861 ::com::sun::star::util::Date SbxDateToUNODate( const SbxValue* const pVal )
1863 double aDate = pVal->GetDate();
1865 com::sun::star::util::Date aUnoDate;
1866 aUnoDate.Day = implGetDateDay ( aDate );
1867 aUnoDate.Month = implGetDateMonth( aDate );
1868 aUnoDate.Year = implGetDateYear ( aDate );
1870 return aUnoDate;
1873 void SbxDateFromUNODate( SbxValue *pVal, const ::com::sun::star::util::Date& aUnoDate)
1875 double dDate;
1876 if( implDateSerial( aUnoDate.Year, aUnoDate.Month, aUnoDate.Day, dDate ) )
1878 pVal->PutDate( dDate );
1882 // Function to convert date to UNO date (com.sun.star.util.Date)
1883 RTLFUNC(CDateToUnoDate)
1885 (void)pBasic;
1886 (void)bWrite;
1888 if ( rPar.Count() != 2 )
1890 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1891 return;
1894 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNODate(rPar.Get(1))));
1897 // Function to convert date from UNO date (com.sun.star.util.Date)
1898 RTLFUNC(CDateFromUnoDate)
1900 (void)pBasic;
1901 (void)bWrite;
1903 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT )
1905 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1906 return;
1909 Any aAny (sbxToUnoValue(rPar.Get(1), ::getCppuType( (com::sun::star::util::Date*)0 )));
1910 com::sun::star::util::Date aUnoDate;
1911 if(aAny >>= aUnoDate)
1912 SbxDateFromUNODate(rPar.Get(0), aUnoDate);
1913 else
1914 SbxBase::SetError( SbxERR_CONVERSION );
1917 ::com::sun::star::util::Time SbxDateToUNOTime( const SbxValue* const pVal )
1919 double aDate = pVal->GetDate();
1921 com::sun::star::util::Time aUnoTime;
1922 aUnoTime.Hours = implGetHour ( aDate );
1923 aUnoTime.Minutes = implGetMinute ( aDate );
1924 aUnoTime.Seconds = implGetSecond ( aDate );
1925 aUnoTime.NanoSeconds = 0;
1927 return aUnoTime;
1930 void SbxDateFromUNOTime( SbxValue *pVal, const ::com::sun::star::util::Time& aUnoTime)
1932 pVal->PutDate( implTimeSerial(aUnoTime.Hours, aUnoTime.Minutes, aUnoTime.Seconds) );
1935 // Function to convert date to UNO time (com.sun.star.util.Time)
1936 RTLFUNC(CDateToUnoTime)
1938 (void)pBasic;
1939 (void)bWrite;
1941 if ( rPar.Count() != 2 )
1943 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1944 return;
1947 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNOTime(rPar.Get(1))));
1950 // Function to convert date from UNO time (com.sun.star.util.Time)
1951 RTLFUNC(CDateFromUnoTime)
1953 (void)pBasic;
1954 (void)bWrite;
1956 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT )
1958 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1959 return;
1962 Any aAny (sbxToUnoValue(rPar.Get(1), ::getCppuType( (com::sun::star::util::Time*)0 )));
1963 com::sun::star::util::Time aUnoTime;
1964 if(aAny >>= aUnoTime)
1965 SbxDateFromUNOTime(rPar.Get(0), aUnoTime);
1966 else
1967 SbxBase::SetError( SbxERR_CONVERSION );
1970 ::com::sun::star::util::DateTime SbxDateToUNODateTime( const SbxValue* const pVal )
1972 double aDate = pVal->GetDate();
1974 com::sun::star::util::DateTime aUnoDT;
1975 aUnoDT.Day = implGetDateDay ( aDate );
1976 aUnoDT.Month = implGetDateMonth( aDate );
1977 aUnoDT.Year = implGetDateYear ( aDate );
1978 aUnoDT.Hours = implGetHour ( aDate );
1979 aUnoDT.Minutes = implGetMinute ( aDate );
1980 aUnoDT.Seconds = implGetSecond ( aDate );
1981 aUnoDT.NanoSeconds = 0;
1983 return aUnoDT;
1986 void SbxDateFromUNODateTime( SbxValue *pVal, const ::com::sun::star::util::DateTime& aUnoDT)
1988 double dDate;
1989 if( implDateTimeSerial( aUnoDT.Year, aUnoDT.Month, aUnoDT.Day,
1990 aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds,
1991 dDate ) )
1993 pVal->PutDate( dDate );
1997 // Function to convert date to UNO date (com.sun.star.util.Date)
1998 RTLFUNC(CDateToUnoDateTime)
2000 (void)pBasic;
2001 (void)bWrite;
2003 if ( rPar.Count() != 2 )
2005 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2006 return;
2009 unoToSbxValue(rPar.Get(0), Any(SbxDateToUNODateTime(rPar.Get(1))));
2012 // Function to convert date from UNO date (com.sun.star.util.Date)
2013 RTLFUNC(CDateFromUnoDateTime)
2015 (void)pBasic;
2016 (void)bWrite;
2018 if ( rPar.Count() != 2 || rPar.Get(1)->GetType() != SbxOBJECT )
2020 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2021 return;
2024 Any aAny (sbxToUnoValue(rPar.Get(1), ::getCppuType( (com::sun::star::util::DateTime*)0 )));
2025 com::sun::star::util::DateTime aUnoDT;
2026 if(aAny >>= aUnoDT)
2027 SbxDateFromUNODateTime(rPar.Get(0), aUnoDT);
2028 else
2029 SbxBase::SetError( SbxERR_CONVERSION );
2032 // Function to convert date to ISO 8601 date format
2033 RTLFUNC(CDateToIso)
2035 (void)pBasic;
2036 (void)bWrite;
2038 if ( rPar.Count() == 2 )
2040 double aDate = rPar.Get(1)->GetDate();
2042 char Buffer[9];
2043 snprintf( Buffer, sizeof( Buffer ), "%04d%02d%02d",
2044 implGetDateYear( aDate ),
2045 implGetDateMonth( aDate ),
2046 implGetDateDay( aDate ) );
2047 OUString aRetStr = OUString::createFromAscii( Buffer );
2048 rPar.Get(0)->PutString( aRetStr );
2050 else
2052 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2056 // Function to convert date from ISO 8601 date format
2057 RTLFUNC(CDateFromIso)
2059 (void)pBasic;
2060 (void)bWrite;
2062 if ( rPar.Count() == 2 )
2064 OUString aStr = rPar.Get(1)->GetOUString();
2065 sal_Int16 iMonthStart = aStr.getLength() - 4;
2066 OUString aYearStr = aStr.copy( 0, iMonthStart );
2067 OUString aMonthStr = aStr.copy( iMonthStart, 2 );
2068 OUString aDayStr = aStr.copy( iMonthStart+2, 2 );
2070 double dDate;
2071 if( implDateSerial( (sal_Int16)aYearStr.toInt32(),
2072 (sal_Int16)aMonthStr.toInt32(), (sal_Int16)aDayStr.toInt32(), dDate ) )
2074 rPar.Get(0)->PutDate( dDate );
2077 else
2079 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2083 RTLFUNC(DateSerial)
2085 (void)pBasic;
2086 (void)bWrite;
2088 if ( rPar.Count() < 4 )
2090 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2091 return;
2093 sal_Int16 nYear = rPar.Get(1)->GetInteger();
2094 sal_Int16 nMonth = rPar.Get(2)->GetInteger();
2095 sal_Int16 nDay = rPar.Get(3)->GetInteger();
2097 double dDate;
2098 if( implDateSerial( nYear, nMonth, nDay, dDate ) )
2100 rPar.Get(0)->PutDate( dDate );
2104 RTLFUNC(TimeSerial)
2106 (void)pBasic;
2107 (void)bWrite;
2109 if ( rPar.Count() < 4 )
2111 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2112 return;
2114 sal_Int16 nHour = rPar.Get(1)->GetInteger();
2115 if ( nHour == 24 )
2117 nHour = 0; // because of UNO DateTimes, which go till 24 o'clock
2119 sal_Int16 nMinute = rPar.Get(2)->GetInteger();
2120 sal_Int16 nSecond = rPar.Get(3)->GetInteger();
2121 if ((nHour < 0 || nHour > 23) ||
2122 (nMinute < 0 || nMinute > 59 ) ||
2123 (nSecond < 0 || nSecond > 59 ))
2125 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2126 return;
2129 rPar.Get(0)->PutDate( implTimeSerial(nHour, nMinute, nSecond) ); // JSM
2132 RTLFUNC(DateValue)
2134 (void)pBasic;
2135 (void)bWrite;
2137 if ( rPar.Count() < 2 )
2139 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2141 else
2143 // #39629 check GetSbData()->pInst, can be called from the URL line
2144 SvNumberFormatter* pFormatter = NULL;
2145 if( GetSbData()->pInst )
2147 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2149 else
2151 sal_uInt32 n; // Dummy
2152 SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n );
2155 sal_uInt32 nIndex = 0;
2156 double fResult;
2157 OUString aStr( rPar.Get(1)->GetOUString() );
2158 sal_Bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult );
2159 short nType = pFormatter->GetType( nIndex );
2161 // DateValue("February 12, 1969") raises error if the system locale is not en_US
2162 // by using SbiInstance::GetNumberFormatter.
2163 // It seems that both locale number formatter and English number formatter
2164 // are supported in Visual Basic.
2165 LanguageType eLangType = GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
2166 if( !bSuccess && ( eLangType != LANGUAGE_ENGLISH_US ) )
2168 // Create a new SvNumberFormatter by using LANGUAGE_ENGLISH to get the date value;
2169 SvNumberFormatter aFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US );
2170 nIndex = 0;
2171 bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, fResult );
2172 nType = aFormatter.GetType( nIndex );
2175 if(bSuccess && (nType==NUMBERFORMAT_DATE || nType==NUMBERFORMAT_DATETIME))
2177 if ( nType == NUMBERFORMAT_DATETIME )
2179 // cut time
2180 if ( fResult > 0.0 )
2182 fResult = floor( fResult );
2184 else
2186 fResult = ceil( fResult );
2189 rPar.Get(0)->PutDate( fResult );
2191 else
2193 StarBASIC::Error( SbERR_CONVERSION );
2195 // #39629 pFormatter can be requested itself
2196 if( !GetSbData()->pInst )
2198 delete pFormatter;
2203 RTLFUNC(TimeValue)
2205 (void)pBasic;
2206 (void)bWrite;
2208 if ( rPar.Count() < 2 )
2210 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2212 else
2214 SvNumberFormatter* pFormatter = NULL;
2215 if( GetSbData()->pInst )
2216 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2217 else
2219 sal_uInt32 n;
2220 SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n );
2223 sal_uInt32 nIndex = 0;
2224 double fResult;
2225 sal_Bool bSuccess = pFormatter->IsNumberFormat( rPar.Get(1)->GetOUString(),
2226 nIndex, fResult );
2227 short nType = pFormatter->GetType(nIndex);
2228 if(bSuccess && (nType==NUMBERFORMAT_TIME||nType==NUMBERFORMAT_DATETIME))
2230 if ( nType == NUMBERFORMAT_DATETIME )
2232 // cut days
2233 fResult = fmod( fResult, 1 );
2235 rPar.Get(0)->PutDate( fResult );
2237 else
2239 StarBASIC::Error( SbERR_CONVERSION );
2241 if( !GetSbData()->pInst )
2243 delete pFormatter;
2248 RTLFUNC(Day)
2250 (void)pBasic;
2251 (void)bWrite;
2253 if ( rPar.Count() < 2 )
2255 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2257 else
2259 SbxVariableRef pArg = rPar.Get( 1 );
2260 double aDate = pArg->GetDate();
2262 sal_Int16 nDay = implGetDateDay( aDate );
2263 rPar.Get(0)->PutInteger( nDay );
2267 RTLFUNC(Year)
2269 (void)pBasic;
2270 (void)bWrite;
2272 if ( rPar.Count() < 2 )
2274 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2276 else
2278 sal_Int16 nYear = implGetDateYear( rPar.Get(1)->GetDate() );
2279 rPar.Get(0)->PutInteger( nYear );
2283 sal_Int16 implGetHour( double dDate )
2285 if( dDate < 0.0 )
2287 dDate *= -1.0;
2289 double nFrac = dDate - floor( dDate );
2290 nFrac *= 86400.0;
2291 sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2292 sal_Int16 nHour = (sal_Int16)(nSeconds / 3600);
2293 return nHour;
2296 RTLFUNC(Hour)
2298 (void)pBasic;
2299 (void)bWrite;
2301 if ( rPar.Count() < 2 )
2303 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2305 else
2307 double nArg = rPar.Get(1)->GetDate();
2308 sal_Int16 nHour = implGetHour( nArg );
2309 rPar.Get(0)->PutInteger( nHour );
2313 RTLFUNC(Minute)
2315 (void)pBasic;
2316 (void)bWrite;
2318 if ( rPar.Count() < 2 )
2320 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2322 else
2324 double nArg = rPar.Get(1)->GetDate();
2325 sal_Int16 nMin = implGetMinute( nArg );
2326 rPar.Get(0)->PutInteger( nMin );
2330 RTLFUNC(Month)
2332 (void)pBasic;
2333 (void)bWrite;
2335 if ( rPar.Count() < 2 )
2337 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2339 else
2341 sal_Int16 nMonth = implGetDateMonth( rPar.Get(1)->GetDate() );
2342 rPar.Get(0)->PutInteger( nMonth );
2346 sal_Int16 implGetSecond( double dDate )
2348 if( dDate < 0.0 )
2350 dDate *= -1.0;
2352 double nFrac = dDate - floor( dDate );
2353 nFrac *= 86400.0;
2354 sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2355 sal_Int16 nTemp = (sal_Int16)(nSeconds / 3600);
2356 nSeconds -= nTemp * 3600;
2357 nTemp = (sal_Int16)(nSeconds / 60);
2358 nSeconds -= nTemp * 60;
2360 sal_Int16 nRet = (sal_Int16)nSeconds;
2361 return nRet;
2364 RTLFUNC(Second)
2366 (void)pBasic;
2367 (void)bWrite;
2369 if ( rPar.Count() < 2 )
2371 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2373 else
2375 double nArg = rPar.Get(1)->GetDate();
2376 sal_Int16 nSecond = implGetSecond( nArg );
2377 rPar.Get(0)->PutInteger( nSecond );
2381 double Now_Impl()
2383 Date aDate( Date::SYSTEM );
2384 Time aTime( Time::SYSTEM );
2385 double aSerial = (double)GetDayDiff( aDate );
2386 long nSeconds = aTime.GetHour();
2387 nSeconds *= 3600;
2388 nSeconds += aTime.GetMin() * 60;
2389 nSeconds += aTime.GetSec();
2390 double nDays = ((double)nSeconds) / (double)(24.0*3600.0);
2391 aSerial += nDays;
2392 return aSerial;
2395 // Date Now(void)
2397 RTLFUNC(Now)
2399 (void)pBasic;
2400 (void)bWrite;
2401 rPar.Get(0)->PutDate( Now_Impl() );
2404 // Date Time(void)
2406 RTLFUNC(Time)
2408 (void)pBasic;
2410 if ( !bWrite )
2412 Time aTime( Time::SYSTEM );
2413 SbxVariable* pMeth = rPar.Get( 0 );
2414 OUString aRes;
2415 if( pMeth->IsFixed() )
2417 // Time$: hh:mm:ss
2418 char buf[ 20 ];
2419 snprintf( buf, sizeof(buf), "%02d:%02d:%02d",
2420 aTime.GetHour(), aTime.GetMin(), aTime.GetSec() );
2421 aRes = OUString::createFromAscii( buf );
2423 else
2425 // Time: system dependent
2426 long nSeconds=aTime.GetHour();
2427 nSeconds *= 3600;
2428 nSeconds += aTime.GetMin() * 60;
2429 nSeconds += aTime.GetSec();
2430 double nDays = (double)nSeconds * ( 1.0 / (24.0*3600.0) );
2431 Color* pCol;
2433 SvNumberFormatter* pFormatter = NULL;
2434 sal_uInt32 nIndex;
2435 if( GetSbData()->pInst )
2437 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2438 nIndex = GetSbData()->pInst->GetStdTimeIdx();
2440 else
2442 sal_uInt32 n; // Dummy
2443 SbiInstance::PrepareNumberFormatter( pFormatter, n, nIndex, n );
2446 pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
2448 if( !GetSbData()->pInst )
2450 delete pFormatter;
2453 pMeth->PutString( aRes );
2455 else
2457 StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
2461 RTLFUNC(Timer)
2463 (void)pBasic;
2464 (void)bWrite;
2466 Time aTime( Time::SYSTEM );
2467 long nSeconds = aTime.GetHour();
2468 nSeconds *= 3600;
2469 nSeconds += aTime.GetMin() * 60;
2470 nSeconds += aTime.GetSec();
2471 rPar.Get(0)->PutDate( (double)nSeconds );
2475 RTLFUNC(Date)
2477 (void)pBasic;
2478 (void)bWrite;
2480 if ( !bWrite )
2482 Date aToday( Date::SYSTEM );
2483 double nDays = (double)GetDayDiff( aToday );
2484 SbxVariable* pMeth = rPar.Get( 0 );
2485 if( pMeth->IsString() )
2487 OUString aRes;
2488 Color* pCol;
2490 SvNumberFormatter* pFormatter = NULL;
2491 sal_uInt32 nIndex;
2492 if( GetSbData()->pInst )
2494 pFormatter = GetSbData()->pInst->GetNumberFormatter();
2495 nIndex = GetSbData()->pInst->GetStdDateIdx();
2497 else
2499 sal_uInt32 n;
2500 SbiInstance::PrepareNumberFormatter( pFormatter, nIndex, n, n );
2503 pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
2504 pMeth->PutString( aRes );
2506 if( !GetSbData()->pInst )
2508 delete pFormatter;
2511 else
2513 pMeth->PutDate( nDays );
2516 else
2518 StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
2522 RTLFUNC(IsArray)
2524 (void)pBasic;
2525 (void)bWrite;
2527 if ( rPar.Count() < 2 )
2529 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2531 else
2533 rPar.Get(0)->PutBool((rPar.Get(1)->GetType() & SbxARRAY) ? sal_True : sal_False );
2537 RTLFUNC(IsObject)
2539 (void)pBasic;
2540 (void)bWrite;
2542 if ( rPar.Count() < 2 )
2544 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2546 else
2548 SbxVariable* pVar = rPar.Get(1);
2549 SbxBase* pObj = (SbxBase*)pVar->GetObject();
2551 // #100385: GetObject can result in an error, so reset it
2552 SbxBase::ResetError();
2554 SbUnoClass* pUnoClass;
2555 sal_Bool bObject;
2556 if( pObj && NULL != ( pUnoClass=PTR_CAST(SbUnoClass,pObj) ) )
2558 bObject = pUnoClass->getUnoClass().is();
2560 else
2562 bObject = pVar->IsObject();
2564 rPar.Get( 0 )->PutBool( bObject );
2568 RTLFUNC(IsDate)
2570 (void)pBasic;
2571 (void)bWrite;
2573 if ( rPar.Count() < 2 )
2575 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2577 else
2579 // #46134 only string is converted, all other types result in sal_False
2580 SbxVariableRef xArg = rPar.Get( 1 );
2581 SbxDataType eType = xArg->GetType();
2582 sal_Bool bDate = sal_False;
2584 if( eType == SbxDATE )
2586 bDate = sal_True;
2588 else if( eType == SbxSTRING )
2590 SbxError nPrevError = SbxBase::GetError();
2591 SbxBase::ResetError();
2593 // force conversion of the parameter to SbxDATE
2594 xArg->SbxValue::GetDate();
2596 bDate = !SbxBase::IsError();
2598 SbxBase::ResetError();
2599 SbxBase::SetError( nPrevError );
2601 rPar.Get( 0 )->PutBool( bDate );
2605 RTLFUNC(IsEmpty)
2607 (void)pBasic;
2608 (void)bWrite;
2610 if ( rPar.Count() < 2 )
2612 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2614 else
2616 SbxVariable* pVar = NULL;
2617 if( SbiRuntime::isVBAEnabled() )
2619 pVar = getDefaultProp( rPar.Get(1) );
2621 if ( pVar )
2623 pVar->Broadcast( SBX_HINT_DATAWANTED );
2624 rPar.Get( 0 )->PutBool( pVar->IsEmpty() );
2626 else
2628 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsEmpty() );
2633 RTLFUNC(IsError)
2635 (void)pBasic;
2636 (void)bWrite;
2638 if ( rPar.Count() < 2 )
2640 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2642 else
2644 SbxVariable* pVar =rPar.Get( 1 );
2645 SbUnoObject* pObj = PTR_CAST(SbUnoObject,pVar );
2646 if ( !pObj )
2648 if ( SbxBase* pBaseObj = pVar->GetObject() )
2650 pObj = PTR_CAST(SbUnoObject, pBaseObj );
2653 uno::Reference< script::XErrorQuery > xError;
2654 if ( pObj )
2656 xError.set( pObj->getUnoAny(), uno::UNO_QUERY );
2658 if ( xError.is() )
2660 rPar.Get( 0 )->PutBool( xError->hasError() );
2662 else
2664 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() );
2669 RTLFUNC(IsNull)
2671 (void)pBasic;
2672 (void)bWrite;
2674 if ( rPar.Count() < 2 )
2676 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2678 else
2680 // #51475 because of Uno-objects return true
2681 // even if the pObj value is NULL
2682 SbxVariableRef pArg = rPar.Get( 1 );
2683 sal_Bool bNull = rPar.Get(1)->IsNull();
2684 if( !bNull && pArg->GetType() == SbxOBJECT )
2686 SbxBase* pObj = pArg->GetObject();
2687 if( !pObj )
2689 bNull = sal_True;
2692 rPar.Get( 0 )->PutBool( bNull );
2696 RTLFUNC(IsNumeric)
2698 (void)pBasic;
2699 (void)bWrite;
2701 if ( rPar.Count() < 2 )
2703 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2705 else
2707 rPar.Get( 0 )->PutBool( rPar.Get( 1 )->IsNumericRTL() );
2713 RTLFUNC(IsMissing)
2715 (void)pBasic;
2716 (void)bWrite;
2718 if ( rPar.Count() < 2 )
2720 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2722 else
2724 // #57915 Missing is reported by an error
2725 rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() );
2729 // Function looks for wildcards, removes them and always returns the pure path
2730 OUString implSetupWildcard( const OUString& rFileParam, SbiRTLData* pRTLData )
2732 static sal_Char cDelim1 = (sal_Char)'/';
2733 static sal_Char cDelim2 = (sal_Char)'\\';
2734 static sal_Char cWild1 = '*';
2735 static sal_Char cWild2 = '?';
2737 delete pRTLData->pWildCard;
2738 pRTLData->pWildCard = NULL;
2739 pRTLData->sFullNameToBeChecked = OUString();
2741 OUString aFileParam = rFileParam;
2742 sal_Int32 nLastWild = aFileParam.lastIndexOf( cWild1 );
2743 if( nLastWild < 0 )
2745 nLastWild = aFileParam.lastIndexOf( cWild2 );
2747 bool bHasWildcards = ( nLastWild >= 0 );
2750 sal_Int32 nLastDelim = aFileParam.lastIndexOf( cDelim1 );
2751 if( nLastDelim < 0 )
2753 nLastDelim = aFileParam.lastIndexOf( cDelim2 );
2755 if( bHasWildcards )
2757 // Wildcards in path?
2758 if( nLastDelim >= 0 && nLastDelim > nLastWild )
2760 return aFileParam;
2763 else
2765 OUString aPathStr = getFullPath( aFileParam );
2766 if( nLastDelim != aFileParam.getLength() - 1 )
2768 pRTLData->sFullNameToBeChecked = aPathStr;
2770 return aPathStr;
2773 OUString aPureFileName;
2774 if( nLastDelim < 0 )
2776 aPureFileName = aFileParam;
2777 aFileParam = OUString();
2779 else
2781 aPureFileName = aFileParam.copy( nLastDelim + 1 );
2782 aFileParam = aFileParam.copy( 0, nLastDelim );
2785 // Try again to get a valid URL/UNC-path with only the path
2786 OUString aPathStr = getFullPath( aFileParam );
2788 // Is there a pure file name left? Otherwise the path is
2789 // invalid anyway because it was not accepted by OSL before
2790 if (!string::equals(aPureFileName, '*'))
2792 pRTLData->pWildCard = new WildCard( aPureFileName );
2794 return aPathStr;
2797 inline sal_Bool implCheckWildcard( const OUString& rName, SbiRTLData* pRTLData )
2799 sal_Bool bMatch = sal_True;
2801 if( pRTLData->pWildCard )
2803 bMatch = pRTLData->pWildCard->Matches( rName );
2805 return bMatch;
2809 bool isRootDir( OUString aDirURLStr )
2811 INetURLObject aDirURLObj( aDirURLStr );
2812 bool bRoot = false;
2814 // Check if it's a root directory
2815 sal_Int32 nCount = aDirURLObj.getSegmentCount();
2817 // No segment means Unix root directory "file:///"
2818 if( nCount == 0 )
2820 bRoot = true;
2822 // Exactly one segment needs further checking, because it
2823 // can be Unix "file:///foo/" -> no root
2824 // or Windows "file:///c:/" -> root
2825 else if( nCount == 1 )
2827 OUString aSeg1 = aDirURLObj.getName( 0, sal_True,
2828 INetURLObject::DECODE_WITH_CHARSET );
2829 if( aSeg1[1] == (sal_Unicode)':' )
2831 bRoot = true;
2834 // More than one segments can never be root
2835 // so bRoot remains false
2837 return bRoot;
2840 RTLFUNC(Dir)
2842 (void)pBasic;
2843 (void)bWrite;
2845 OUString aPath;
2847 sal_uInt16 nParCount = rPar.Count();
2848 if( nParCount > 3 )
2850 StarBASIC::Error( SbERR_BAD_ARGUMENT );
2852 else
2854 SbiRTLData* pRTLData = GetSbData()->pInst->GetRTLData();
2856 // #34645: can also be called from the URL line via 'macro: Dir'
2857 // there's no pRTLDate existing in that case and the method must be left
2858 if( !pRTLData )
2860 return;
2862 if( hasUno() )
2864 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
2865 if( xSFI.is() )
2867 if ( nParCount >= 2 )
2869 OUString aFileParam = rPar.Get(1)->GetOUString();
2871 OUString aFileURLStr = implSetupWildcard( aFileParam, pRTLData );
2872 if( !pRTLData->sFullNameToBeChecked.isEmpty())
2874 sal_Bool bExists = sal_False;
2875 try { bExists = xSFI->exists( aFileURLStr ); }
2876 catch(const Exception & ) {}
2878 OUString aNameOnlyStr;
2879 if( bExists )
2881 INetURLObject aFileURL( aFileURLStr );
2882 aNameOnlyStr = aFileURL.getName( INetURLObject::LAST_SEGMENT,
2883 true, INetURLObject::DECODE_WITH_CHARSET );
2885 rPar.Get(0)->PutString( aNameOnlyStr );
2886 return;
2891 OUString aDirURLStr;
2892 sal_Bool bFolder = xSFI->isFolder( aFileURLStr );
2894 if( bFolder )
2896 aDirURLStr = aFileURLStr;
2898 else
2900 OUString aEmptyStr;
2901 rPar.Get(0)->PutString( aEmptyStr );
2904 sal_uInt16 nFlags = 0;
2905 if ( nParCount > 2 )
2907 pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
2909 else
2911 pRTLData->nDirFlags = 0;
2913 // Read directory
2914 sal_Bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0);
2915 pRTLData->aDirSeq = xSFI->getFolderContents( aDirURLStr, bIncludeFolders );
2916 pRTLData->nCurDirPos = 0;
2918 // #78651 Add "." and ".." directories for VB compatibility
2919 if( bIncludeFolders )
2921 bool bRoot = isRootDir( aDirURLStr );
2923 // If it's no root directory we flag the need for
2924 // the "." and ".." directories by the value -2
2925 // for the actual position. Later for -2 will be
2926 // returned "." and for -1 ".."
2927 if( !bRoot )
2929 pRTLData->nCurDirPos = -2;
2933 catch(const Exception & )
2939 if( pRTLData->aDirSeq.getLength() > 0 )
2941 bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0);
2943 SbiInstance* pInst = GetSbData()->pInst;
2944 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
2945 for( ;; )
2947 if( pRTLData->nCurDirPos < 0 )
2949 if( pRTLData->nCurDirPos == -2 )
2951 aPath = OUString("." );
2953 else if( pRTLData->nCurDirPos == -1 )
2955 aPath = OUString(".." );
2957 pRTLData->nCurDirPos++;
2959 else if( pRTLData->nCurDirPos >= pRTLData->aDirSeq.getLength() )
2961 pRTLData->aDirSeq.realloc( 0 );
2962 aPath = "";
2963 break;
2965 else
2967 OUString aFile = pRTLData->aDirSeq.getConstArray()[pRTLData->nCurDirPos++];
2969 if( bCompatibility )
2971 if( !bFolderFlag )
2973 sal_Bool bFolder = xSFI->isFolder( aFile );
2974 if( bFolder )
2976 continue;
2980 else
2982 // Only directories
2983 if( bFolderFlag )
2985 sal_Bool bFolder = xSFI->isFolder( aFile );
2986 if( !bFolder )
2988 continue;
2993 INetURLObject aURL( aFile );
2994 aPath = aURL.getName( INetURLObject::LAST_SEGMENT, sal_True,
2995 INetURLObject::DECODE_WITH_CHARSET );
2998 sal_Bool bMatch = implCheckWildcard( aPath, pRTLData );
2999 if( !bMatch )
3001 continue;
3003 break;
3006 rPar.Get(0)->PutString( aPath );
3009 else
3011 // TODO: OSL
3012 if ( nParCount >= 2 )
3014 OUString aFileParam = rPar.Get(1)->GetOUString();
3016 OUString aDirURL = implSetupWildcard( aFileParam, pRTLData );
3018 sal_uInt16 nFlags = 0;
3019 if ( nParCount > 2 )
3021 pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
3023 else
3025 pRTLData->nDirFlags = 0;
3028 // Read directory
3029 bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0);
3030 pRTLData->pDir = new Directory( aDirURL );
3031 FileBase::RC nRet = pRTLData->pDir->open();
3032 if( nRet != FileBase::E_None )
3034 delete pRTLData->pDir;
3035 pRTLData->pDir = NULL;
3036 rPar.Get(0)->PutString( OUString() );
3037 return;
3040 // #86950 Add "." and ".." directories for VB compatibility
3041 pRTLData->nCurDirPos = 0;
3042 if( bIncludeFolders )
3044 bool bRoot = isRootDir( aDirURL );
3046 // If it's no root directory we flag the need for
3047 // the "." and ".." directories by the value -2
3048 // for the actual position. Later for -2 will be
3049 // returned "." and for -1 ".."
3050 if( !bRoot )
3052 pRTLData->nCurDirPos = -2;
3058 if( pRTLData->pDir )
3060 bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0);
3061 for( ;; )
3063 if( pRTLData->nCurDirPos < 0 )
3065 if( pRTLData->nCurDirPos == -2 )
3067 aPath = OUString("." );
3069 else if( pRTLData->nCurDirPos == -1 )
3071 aPath = OUString(".." );
3073 pRTLData->nCurDirPos++;
3075 else
3077 DirectoryItem aItem;
3078 FileBase::RC nRet = pRTLData->pDir->getNextItem( aItem );
3079 if( nRet != FileBase::E_None )
3081 delete pRTLData->pDir;
3082 pRTLData->pDir = NULL;
3083 aPath = "";
3084 break;
3087 // Handle flags
3088 FileStatus aFileStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName );
3089 nRet = aItem.getFileStatus( aFileStatus );
3091 // Only directories?
3092 if( bFolderFlag )
3094 FileStatus::Type aType = aFileStatus.getFileType();
3095 bool bFolder = isFolder( aType );
3096 if( !bFolder )
3098 continue;
3102 aPath = aFileStatus.getFileName();
3105 sal_Bool bMatch = implCheckWildcard( aPath, pRTLData );
3106 if( !bMatch )
3108 continue;
3110 break;
3113 rPar.Get(0)->PutString( aPath );
3119 RTLFUNC(GetAttr)
3121 (void)pBasic;
3122 (void)bWrite;
3124 if ( rPar.Count() == 2 )
3126 sal_Int16 nFlags = 0;
3128 // In Windows, we want to use Windows API to get the file attributes
3129 // for VBA interoperability.
3130 #if defined( WNT )
3131 if( SbiRuntime::isVBAEnabled() )
3133 OUString aPathURL = getFullPath( rPar.Get(1)->GetOUString() );
3134 OUString aPath;
3135 FileBase::getSystemPathFromFileURL( aPathURL, aPath );
3136 OString aSystemPath(OUStringToOString(aPath, osl_getThreadTextEncoding()));
3137 DWORD nRealFlags = GetFileAttributes (aSystemPath.getStr());
3138 if (nRealFlags != 0xffffffff)
3140 if (nRealFlags == FILE_ATTRIBUTE_NORMAL)
3142 nRealFlags = 0;
3144 nFlags = (sal_Int16) (nRealFlags);
3146 else
3148 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3150 rPar.Get(0)->PutInteger( nFlags );
3152 return;
3154 #endif
3156 if( hasUno() )
3158 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
3159 if( xSFI.is() )
3163 OUString aPath = getFullPath( rPar.Get(1)->GetOUString() );
3164 sal_Bool bExists = sal_False;
3165 try { bExists = xSFI->exists( aPath ); }
3166 catch(const Exception & ) {}
3167 if( !bExists )
3169 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3170 return;
3173 sal_Bool bReadOnly = xSFI->isReadOnly( aPath );
3174 sal_Bool bHidden = xSFI->isHidden( aPath );
3175 sal_Bool bDirectory = xSFI->isFolder( aPath );
3176 if( bReadOnly )
3178 nFlags |= Sb_ATTR_READONLY;
3180 if( bHidden )
3182 nFlags |= Sb_ATTR_HIDDEN;
3184 if( bDirectory )
3186 nFlags |= Sb_ATTR_DIRECTORY;
3189 catch(const Exception & )
3191 StarBASIC::Error( ERRCODE_IO_GENERAL );
3195 else
3197 DirectoryItem aItem;
3198 DirectoryItem::get( getFullPath( rPar.Get(1)->GetOUString() ), aItem );
3199 FileStatus aFileStatus( osl_FileStatus_Mask_Attributes | osl_FileStatus_Mask_Type );
3200 aItem.getFileStatus( aFileStatus );
3201 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3202 bool bReadOnly = (nAttributes & osl_File_Attribute_ReadOnly) != 0;
3204 FileStatus::Type aType = aFileStatus.getFileType();
3205 bool bDirectory = isFolder( aType );
3206 if( bReadOnly )
3208 nFlags |= Sb_ATTR_READONLY;
3210 if( bDirectory )
3212 nFlags |= Sb_ATTR_DIRECTORY;
3215 rPar.Get(0)->PutInteger( nFlags );
3217 else
3219 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3224 RTLFUNC(FileDateTime)
3226 (void)pBasic;
3227 (void)bWrite;
3229 if ( rPar.Count() != 2 )
3231 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3233 else
3235 OUString aPath = rPar.Get(1)->GetOUString();
3236 Time aTime( Time::EMPTY );
3237 Date aDate( Date::EMPTY );
3238 if( hasUno() )
3240 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
3241 if( xSFI.is() )
3245 util::DateTime aUnoDT = xSFI->getDateTimeModified( aPath );
3246 aTime = Time( aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, aUnoDT.NanoSeconds );
3247 aDate = Date( aUnoDT.Day, aUnoDT.Month, aUnoDT.Year );
3249 catch(const Exception & )
3251 StarBASIC::Error( ERRCODE_IO_GENERAL );
3255 else
3257 DirectoryItem aItem;
3258 DirectoryItem::get( getFullPath( aPath ), aItem );
3259 FileStatus aFileStatus( osl_FileStatus_Mask_ModifyTime );
3260 aItem.getFileStatus( aFileStatus );
3261 TimeValue aTimeVal = aFileStatus.getModifyTime();
3262 oslDateTime aDT;
3263 osl_getDateTimeFromTimeValue( &aTimeVal, &aDT );
3265 aTime = Time( aDT.Hours, aDT.Minutes, aDT.Seconds, aDT.NanoSeconds );
3266 aDate = Date( aDT.Day, aDT.Month, aDT.Year );
3269 double fSerial = (double)GetDayDiff( aDate );
3270 long nSeconds = aTime.GetHour();
3271 nSeconds *= 3600;
3272 nSeconds += aTime.GetMin() * 60;
3273 nSeconds += aTime.GetSec();
3274 double nDays = ((double)nSeconds) / (double)(24.0*3600.0);
3275 fSerial += nDays;
3277 Color* pCol;
3279 SvNumberFormatter* pFormatter = NULL;
3280 sal_uInt32 nIndex;
3281 if( GetSbData()->pInst )
3283 pFormatter = GetSbData()->pInst->GetNumberFormatter();
3284 nIndex = GetSbData()->pInst->GetStdDateTimeIdx();
3286 else
3288 sal_uInt32 n;
3289 SbiInstance::PrepareNumberFormatter( pFormatter, n, n, nIndex );
3292 OUString aRes;
3293 pFormatter->GetOutputString( fSerial, nIndex, aRes, &pCol );
3294 rPar.Get(0)->PutString( aRes );
3296 if( !GetSbData()->pInst )
3298 delete pFormatter;
3304 RTLFUNC(EOF)
3306 (void)pBasic;
3307 (void)bWrite;
3309 // No changes for UCB
3310 if ( rPar.Count() != 2 )
3312 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3314 else
3316 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3317 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3318 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3319 if ( !pSbStrm )
3321 StarBASIC::Error( SbERR_BAD_CHANNEL );
3322 return;
3324 sal_Bool bIsEof;
3325 SvStream* pSvStrm = pSbStrm->GetStrm();
3326 if ( pSbStrm->IsText() )
3328 char cBla;
3329 (*pSvStrm) >> cBla; // can we read another character?
3330 bIsEof = pSvStrm->IsEof();
3331 if ( !bIsEof )
3333 pSvStrm->SeekRel( -1 );
3336 else
3338 bIsEof = pSvStrm->IsEof(); // for binary data!
3340 rPar.Get(0)->PutBool( bIsEof );
3344 RTLFUNC(FileAttr)
3346 (void)pBasic;
3347 (void)bWrite;
3349 // No changes for UCB
3350 // #57064 Although this function doesn't operate with DirEntry, it is
3351 // not touched by the adjustment to virtual URLs, as it only works on
3352 // already opened files and the name doesn't matter there.
3354 if ( rPar.Count() != 3 )
3356 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3358 else
3360 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3361 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3362 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3363 if ( !pSbStrm )
3365 StarBASIC::Error( SbERR_BAD_CHANNEL );
3366 return;
3368 sal_Int16 nRet;
3369 if ( rPar.Get(2)->GetInteger() == 1 )
3371 nRet = (sal_Int16)(pSbStrm->GetMode());
3373 else
3375 nRet = 0; // System file handle not supported
3377 rPar.Get(0)->PutInteger( nRet );
3380 RTLFUNC(Loc)
3382 (void)pBasic;
3383 (void)bWrite;
3385 // No changes for UCB
3386 if ( rPar.Count() != 2 )
3388 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3390 else
3392 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3393 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3394 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3395 if ( !pSbStrm )
3397 StarBASIC::Error( SbERR_BAD_CHANNEL );
3398 return;
3400 SvStream* pSvStrm = pSbStrm->GetStrm();
3401 sal_uIntPtr nPos;
3402 if( pSbStrm->IsRandom())
3404 short nBlockLen = pSbStrm->GetBlockLen();
3405 nPos = nBlockLen ? (pSvStrm->Tell() / nBlockLen) : 0;
3406 nPos++; // block positions starting at 1
3408 else if ( pSbStrm->IsText() )
3410 nPos = pSbStrm->GetLine();
3412 else if( pSbStrm->IsBinary() )
3414 nPos = pSvStrm->Tell();
3416 else if ( pSbStrm->IsSeq() )
3418 nPos = ( pSvStrm->Tell()+1 ) / 128;
3420 else
3422 nPos = pSvStrm->Tell();
3424 rPar.Get(0)->PutLong( (sal_Int32)nPos );
3428 RTLFUNC(Lof)
3430 (void)pBasic;
3431 (void)bWrite;
3433 // No changes for UCB
3434 if ( rPar.Count() != 2 )
3436 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3438 else
3440 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3441 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3442 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3443 if ( !pSbStrm )
3445 StarBASIC::Error( SbERR_BAD_CHANNEL );
3446 return;
3448 SvStream* pSvStrm = pSbStrm->GetStrm();
3449 sal_uIntPtr nOldPos = pSvStrm->Tell();
3450 sal_uIntPtr nLen = pSvStrm->Seek( STREAM_SEEK_TO_END );
3451 pSvStrm->Seek( nOldPos );
3452 rPar.Get(0)->PutLong( (sal_Int32)nLen );
3457 RTLFUNC(Seek)
3459 (void)pBasic;
3460 (void)bWrite;
3462 // No changes for UCB
3463 int nArgs = (int)rPar.Count();
3464 if ( nArgs < 2 || nArgs > 3 )
3466 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3467 return;
3469 sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3470 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
3471 SbiStream* pSbStrm = pIO->GetStream( nChannel );
3472 if ( !pSbStrm )
3474 StarBASIC::Error( SbERR_BAD_CHANNEL );
3475 return;
3477 SvStream* pStrm = pSbStrm->GetStrm();
3479 if ( nArgs == 2 ) // Seek-Function
3481 sal_uIntPtr nPos = pStrm->Tell();
3482 if( pSbStrm->IsRandom() )
3484 nPos = nPos / pSbStrm->GetBlockLen();
3486 nPos++; // Basic counts from 1
3487 rPar.Get(0)->PutLong( (sal_Int32)nPos );
3489 else // Seek-Statement
3491 sal_Int32 nPos = rPar.Get(2)->GetLong();
3492 if ( nPos < 1 )
3494 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3495 return;
3497 nPos--; // Basic counts from 1, SvStreams count from 0
3498 pSbStrm->SetExpandOnWriteTo( 0 );
3499 if ( pSbStrm->IsRandom() )
3501 nPos *= pSbStrm->GetBlockLen();
3503 pStrm->Seek( (sal_uIntPtr)nPos );
3504 pSbStrm->SetExpandOnWriteTo( nPos );
3508 RTLFUNC(Format)
3510 (void)pBasic;
3511 (void)bWrite;
3513 sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
3514 if ( nArgCount < 2 || nArgCount > 3 )
3516 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3518 else
3520 OUString aResult;
3521 if( nArgCount == 2 )
3523 rPar.Get(1)->Format( aResult );
3525 else
3527 OUString aFmt( rPar.Get(2)->GetOUString() );
3528 rPar.Get(1)->Format( aResult, &aFmt );
3530 rPar.Get(0)->PutString( aResult );
3534 RTLFUNC(Randomize)
3536 (void)pBasic;
3537 (void)bWrite;
3539 if ( rPar.Count() > 2 )
3541 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3543 sal_Int16 nSeed;
3544 if( rPar.Count() == 2 )
3546 nSeed = (sal_Int16)rPar.Get(1)->GetInteger();
3548 else
3550 nSeed = (sal_Int16)rand();
3552 srand( nSeed );
3555 RTLFUNC(Rnd)
3557 (void)pBasic;
3558 (void)bWrite;
3560 if ( rPar.Count() > 2 )
3562 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3564 else
3566 double nRand = (double)rand();
3567 nRand = ( nRand / ((double)RAND_MAX + 1.0));
3568 rPar.Get(0)->PutDouble( nRand );
3573 // Syntax: Shell("Path",[ Window-Style,[ "Params", [ bSync = sal_False ]]])
3574 // WindowStyles (VBA-kompatibel):
3575 // 2 == Minimized
3576 // 3 == Maximized
3577 // 10 == Full-Screen (text mode applications OS/2, WIN95, WNT)
3578 // HACK: The WindowStyle will be passed to
3579 // Application::StartApp in Creator. Format: "xxxx2"
3582 RTLFUNC(Shell)
3584 (void)pBasic;
3585 (void)bWrite;
3587 // No shell command for "virtual" portal users
3588 if( needSecurityRestrictions() )
3590 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3591 return;
3594 sal_uIntPtr nArgCount = rPar.Count();
3595 if ( nArgCount < 2 || nArgCount > 5 )
3597 rPar.Get(0)->PutLong(0);
3598 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3600 else
3602 oslProcessOption nOptions = osl_Process_SEARCHPATH | osl_Process_DETACHED;
3604 OUString aCmdLine = rPar.Get(1)->GetOUString();
3605 // attach additional parameters - everything must be parsed anyway
3606 if( nArgCount >= 4 )
3608 aCmdLine += " ";
3609 aCmdLine += rPar.Get(3)->GetOUString();
3611 else if( aCmdLine.isEmpty() )
3613 // avaoid special treatment (empty list)
3614 aCmdLine += " ";
3616 sal_Int32 nLen = aCmdLine.getLength();
3618 // #55735 if there are parameters, they have to be separated
3619 // #72471 also separate the single parameters
3620 std::list<String> aTokenList;
3621 OUString aToken;
3622 sal_Int32 i = 0;
3623 sal_Unicode c;
3624 while( i < nLen )
3626 for ( ;; ++i )
3628 c = aCmdLine[ i ];
3629 if ( c != ' ' && c != '\t' )
3631 break;
3635 if( c == '\"' || c == '\'' )
3637 sal_Int32 iFoundPos = aCmdLine.indexOf( c, i + 1 );
3639 if( iFoundPos < 0 )
3641 aToken = aCmdLine.copy( i);
3642 i = nLen;
3644 else
3646 aToken = aCmdLine.copy( i + 1, (iFoundPos - i - 1) );
3647 i = iFoundPos + 1;
3650 else
3652 sal_Int32 iFoundSpacePos = aCmdLine.indexOf( ' ', i );
3653 sal_Int32 iFoundTabPos = aCmdLine.indexOf( '\t', i );
3654 sal_Int32 iFoundPos = iFoundSpacePos >= 0 ? iFoundTabPos >= 0 ? std::min( iFoundSpacePos, iFoundTabPos ) : iFoundSpacePos : -1;
3656 if( iFoundPos < 0 )
3658 aToken = aCmdLine.copy( i );
3659 i = nLen;
3661 else
3663 aToken = aCmdLine.copy( i, (iFoundPos - i) );
3664 i = iFoundPos;
3668 // insert into the list
3669 aTokenList.push_back( aToken );
3671 // #55735 / #72471 end
3673 sal_Int16 nWinStyle = 0;
3674 if( nArgCount >= 3 )
3676 nWinStyle = rPar.Get(2)->GetInteger();
3677 switch( nWinStyle )
3679 case 2:
3680 nOptions |= osl_Process_MINIMIZED;
3681 break;
3682 case 3:
3683 nOptions |= osl_Process_MAXIMIZED;
3684 break;
3685 case 10:
3686 nOptions |= osl_Process_FULLSCREEN;
3687 break;
3690 sal_Bool bSync = sal_False;
3691 if( nArgCount >= 5 )
3693 bSync = rPar.Get(4)->GetBool();
3695 if( bSync )
3697 nOptions |= osl_Process_WAIT;
3701 // #72471 work parameter(s) up
3702 std::list<String>::const_iterator iter = aTokenList.begin();
3703 const OUString& rStr = *iter;
3704 OUString aOUStrProg( rStr.getStr(), rStr.getLength() );
3705 OUString aOUStrProgURL = getFullPath( aOUStrProg );
3707 ++iter;
3709 sal_uInt16 nParamCount = sal::static_int_cast< sal_uInt16 >(aTokenList.size() - 1 );
3710 rtl_uString** pParamList = NULL;
3711 if( nParamCount )
3713 pParamList = new rtl_uString*[nParamCount];
3714 for(int iList = 0; iter != aTokenList.end(); ++iList, ++iter)
3716 const OUString& rParamStr = (*iter);
3717 const OUString aTempStr( rParamStr.getStr(), rParamStr.getLength());
3718 pParamList[iList] = NULL;
3719 rtl_uString_assign(&(pParamList[iList]), aTempStr.pData);
3723 oslProcess pApp;
3724 sal_Bool bSucc = osl_executeProcess(
3725 aOUStrProgURL.pData,
3726 pParamList,
3727 nParamCount,
3728 nOptions,
3729 NULL,
3730 NULL,
3731 NULL, 0,
3732 &pApp ) == osl_Process_E_None;
3734 // 53521 only free process handle on success
3735 if (bSucc)
3737 osl_freeProcessHandle( pApp );
3740 for(int j = 0; i < nParamCount; i++)
3742 rtl_uString_release(pParamList[j]);
3743 pParamList[j] = NULL;
3746 if( !bSucc )
3748 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3750 else
3752 rPar.Get(0)->PutLong( 0 );
3757 RTLFUNC(VarType)
3759 (void)pBasic;
3760 (void)bWrite;
3762 if ( rPar.Count() != 2 )
3764 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3766 else
3768 SbxDataType eType = rPar.Get(1)->GetType();
3769 rPar.Get(0)->PutInteger( (sal_Int16)eType );
3773 // Exported function
3774 OUString getBasicTypeName( SbxDataType eType )
3776 static const char* pTypeNames[] =
3778 "Empty", // SbxEMPTY
3779 "Null", // SbxNULL
3780 "Integer", // SbxINTEGER
3781 "Long", // SbxLONG
3782 "Single", // SbxSINGLE
3783 "Double", // SbxDOUBLE
3784 "Currency", // SbxCURRENCY
3785 "Date", // SbxDATE
3786 "String", // SbxSTRING
3787 "Object", // SbxOBJECT
3788 "Error", // SbxERROR
3789 "Boolean", // SbxBOOL
3790 "Variant", // SbxVARIANT
3791 "DataObject", // SbxDATAOBJECT
3792 "Unknown Type", //
3793 "Unknown Type", //
3794 "Char", // SbxCHAR
3795 "Byte", // SbxBYTE
3796 "UShort", // SbxUSHORT
3797 "ULong", // SbxULONG
3798 "Long64", // SbxLONG64
3799 "ULong64", // SbxULONG64
3800 "Int", // SbxINT
3801 "UInt", // SbxUINT
3802 "Void", // SbxVOID
3803 "HResult", // SbxHRESULT
3804 "Pointer", // SbxPOINTER
3805 "DimArray", // SbxDIMARRAY
3806 "CArray", // SbxCARRAY
3807 "Userdef", // SbxUSERDEF
3808 "Lpstr", // SbxLPSTR
3809 "Lpwstr", // SbxLPWSTR
3810 "Unknown Type", // SbxCoreSTRING
3811 "WString", // SbxWSTRING
3812 "WChar", // SbxWCHAR
3813 "Int64", // SbxSALINT64
3814 "UInt64", // SbxSALUINT64
3815 "Decimal", // SbxDECIMAL
3818 int nPos = ((int)eType) & 0x0FFF;
3819 sal_uInt16 nTypeNameCount = sizeof( pTypeNames ) / sizeof( char* );
3820 if ( nPos < 0 || nPos >= nTypeNameCount )
3822 nPos = nTypeNameCount - 1;
3824 return OUString::createFromAscii(pTypeNames[nPos]);
3827 String getObjectTypeName( SbxVariable* pVar )
3829 OUString sRet( "Object" );
3830 if ( pVar )
3832 SbxBase* pObj = pVar->GetObject();
3833 if( !pObj )
3835 sRet = OUString("Nothing");
3837 else
3839 SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pVar );
3840 if ( !pUnoObj )
3842 if ( SbxBase* pBaseObj = pVar->GetObject() )
3844 pUnoObj = PTR_CAST(SbUnoObject, pBaseObj );
3847 if ( pUnoObj )
3849 Any aObj = pUnoObj->getUnoAny();
3850 // For upstreaming unless we start to build oovbaapi by default
3851 // we need to get detect the vba-ness of the object in some
3852 // other way
3853 // note: Automation objects do not support XServiceInfo
3854 uno::Reference< XServiceInfo > xServInfo( aObj, uno::UNO_QUERY );
3855 if ( xServInfo.is() )
3857 // is this a VBA object ?
3858 uno::Reference< ooo::vba::XHelperInterface > xVBA( aObj, uno::UNO_QUERY );
3859 Sequence< OUString > sServices = xServInfo->getSupportedServiceNames();
3860 if ( sServices.getLength() )
3862 sRet = sServices[ 0 ];
3865 else
3867 uno::Reference< bridge::oleautomation::XAutomationObject > xAutoMation( aObj, uno::UNO_QUERY );
3868 if ( xAutoMation.is() )
3870 uno::Reference< script::XInvocation > xInv( aObj, uno::UNO_QUERY );
3871 if ( xInv.is() )
3875 xInv->getValue( OUString( "$GetTypeName" ) ) >>= sRet;
3877 catch(const Exception& )
3883 sal_Int32 nDot = sRet.lastIndexOf( '.' );
3884 if ( nDot != -1 && nDot < sRet.getLength() )
3886 sRet = sRet.copy( nDot + 1 );
3891 return sRet;
3894 RTLFUNC(TypeName)
3896 (void)pBasic;
3897 (void)bWrite;
3899 if ( rPar.Count() != 2 )
3901 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3903 else
3905 SbxDataType eType = rPar.Get(1)->GetType();
3906 bool bIsArray = ( ( eType & SbxARRAY ) != 0 );
3908 OUString aRetStr;
3909 if ( SbiRuntime::isVBAEnabled() && eType == SbxOBJECT )
3911 aRetStr = getObjectTypeName( rPar.Get(1) );
3913 else
3915 aRetStr = getBasicTypeName( eType );
3917 if( bIsArray )
3919 aRetStr += "()";
3921 rPar.Get(0)->PutString( aRetStr );
3925 RTLFUNC(Len)
3927 (void)pBasic;
3928 (void)bWrite;
3930 if ( rPar.Count() != 2 )
3932 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3934 else
3936 const OUString& rStr = rPar.Get(1)->GetOUString();
3937 rPar.Get(0)->PutLong( rStr.getLength() );
3941 RTLFUNC(DDEInitiate)
3943 (void)pBasic;
3944 (void)bWrite;
3946 // No DDE for "virtual" portal users
3947 if( needSecurityRestrictions() )
3949 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3950 return;
3953 int nArgs = (int)rPar.Count();
3954 if ( nArgs != 3 )
3956 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3957 return;
3959 const OUString& rApp = rPar.Get(1)->GetOUString();
3960 const OUString& rTopic = rPar.Get(2)->GetOUString();
3962 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
3963 size_t nChannel;
3964 SbError nDdeErr = pDDE->Initiate( rApp, rTopic, nChannel );
3965 if( nDdeErr )
3967 StarBASIC::Error( nDdeErr );
3969 else
3971 rPar.Get(0)->PutInteger( (int)nChannel );
3975 RTLFUNC(DDETerminate)
3977 (void)pBasic;
3978 (void)bWrite;
3980 // No DDE for "virtual" portal users
3981 if( needSecurityRestrictions() )
3983 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3984 return;
3987 rPar.Get(0)->PutEmpty();
3988 int nArgs = (int)rPar.Count();
3989 if ( nArgs != 2 )
3991 StarBASIC::Error( SbERR_BAD_ARGUMENT );
3992 return;
3994 size_t nChannel = rPar.Get(1)->GetInteger();
3995 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
3996 SbError nDdeErr = pDDE->Terminate( nChannel );
3997 if( nDdeErr )
3999 StarBASIC::Error( nDdeErr );
4003 RTLFUNC(DDETerminateAll)
4005 (void)pBasic;
4006 (void)bWrite;
4008 // No DDE for "virtual" portal users
4009 if( needSecurityRestrictions() )
4011 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4012 return;
4015 rPar.Get(0)->PutEmpty();
4016 int nArgs = (int)rPar.Count();
4017 if ( nArgs != 1 )
4019 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4020 return;
4023 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4024 SbError nDdeErr = pDDE->TerminateAll();
4025 if( nDdeErr )
4027 StarBASIC::Error( nDdeErr );
4031 RTLFUNC(DDERequest)
4033 (void)pBasic;
4034 (void)bWrite;
4036 // No DDE for "virtual" portal users
4037 if( needSecurityRestrictions() )
4039 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4040 return;
4043 int nArgs = (int)rPar.Count();
4044 if ( nArgs != 3 )
4046 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4047 return;
4049 size_t nChannel = rPar.Get(1)->GetInteger();
4050 const OUString& rItem = rPar.Get(2)->GetOUString();
4051 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4052 OUString aResult;
4053 SbError nDdeErr = pDDE->Request( nChannel, rItem, aResult );
4054 if( nDdeErr )
4056 StarBASIC::Error( nDdeErr );
4058 else
4060 rPar.Get(0)->PutString( aResult );
4064 RTLFUNC(DDEExecute)
4066 (void)pBasic;
4067 (void)bWrite;
4069 // No DDE for "virtual" portal users
4070 if( needSecurityRestrictions() )
4072 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4073 return;
4076 rPar.Get(0)->PutEmpty();
4077 int nArgs = (int)rPar.Count();
4078 if ( nArgs != 3 )
4080 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4081 return;
4083 size_t nChannel = rPar.Get(1)->GetInteger();
4084 const OUString& rCommand = rPar.Get(2)->GetOUString();
4085 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4086 SbError nDdeErr = pDDE->Execute( nChannel, rCommand );
4087 if( nDdeErr )
4089 StarBASIC::Error( nDdeErr );
4093 RTLFUNC(DDEPoke)
4095 (void)pBasic;
4096 (void)bWrite;
4098 // No DDE for "virtual" portal users
4099 if( needSecurityRestrictions() )
4101 StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
4102 return;
4105 rPar.Get(0)->PutEmpty();
4106 int nArgs = (int)rPar.Count();
4107 if ( nArgs != 4 )
4109 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4110 return;
4112 size_t nChannel = rPar.Get(1)->GetInteger();
4113 const OUString& rItem = rPar.Get(2)->GetOUString();
4114 const OUString& rData = rPar.Get(3)->GetOUString();
4115 SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
4116 SbError nDdeErr = pDDE->Poke( nChannel, rItem, rData );
4117 if( nDdeErr )
4119 StarBASIC::Error( nDdeErr );
4124 RTLFUNC(FreeFile)
4126 (void)pBasic;
4127 (void)bWrite;
4129 if ( rPar.Count() != 1 )
4131 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4132 return;
4134 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
4135 short nChannel = 1;
4136 while( nChannel < CHANNELS )
4138 SbiStream* pStrm = pIO->GetStream( nChannel );
4139 if( !pStrm )
4141 rPar.Get(0)->PutInteger( nChannel );
4142 return;
4144 nChannel++;
4146 StarBASIC::Error( SbERR_TOO_MANY_FILES );
4149 RTLFUNC(LBound)
4151 (void)pBasic;
4152 (void)bWrite;
4154 sal_uInt16 nParCount = rPar.Count();
4155 if ( nParCount != 3 && nParCount != 2 )
4157 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4158 return;
4160 SbxBase* pParObj = rPar.Get(1)->GetObject();
4161 SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj);
4162 if( pArr )
4164 sal_Int32 nLower, nUpper;
4165 short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1;
4166 if( !pArr->GetDim32( nDim, nLower, nUpper ) )
4167 StarBASIC::Error( SbERR_OUT_OF_RANGE );
4168 else
4169 rPar.Get(0)->PutLong( nLower );
4171 else
4172 StarBASIC::Error( SbERR_MUST_HAVE_DIMS );
4175 RTLFUNC(UBound)
4177 (void)pBasic;
4178 (void)bWrite;
4180 sal_uInt16 nParCount = rPar.Count();
4181 if ( nParCount != 3 && nParCount != 2 )
4183 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4184 return;
4187 SbxBase* pParObj = rPar.Get(1)->GetObject();
4188 SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj);
4189 if( pArr )
4191 sal_Int32 nLower, nUpper;
4192 short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1;
4193 if( !pArr->GetDim32( nDim, nLower, nUpper ) )
4194 StarBASIC::Error( SbERR_OUT_OF_RANGE );
4195 else
4196 rPar.Get(0)->PutLong( nUpper );
4198 else
4199 StarBASIC::Error( SbERR_MUST_HAVE_DIMS );
4202 RTLFUNC(RGB)
4204 (void)pBasic;
4205 (void)bWrite;
4207 if ( rPar.Count() != 4 )
4209 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4210 return;
4213 sal_uIntPtr nRed = rPar.Get(1)->GetInteger() & 0xFF;
4214 sal_uIntPtr nGreen = rPar.Get(2)->GetInteger() & 0xFF;
4215 sal_uIntPtr nBlue = rPar.Get(3)->GetInteger() & 0xFF;
4216 sal_uIntPtr nRGB;
4218 SbiInstance* pInst = GetSbData()->pInst;
4219 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
4220 if( bCompatibility )
4222 nRGB = (nBlue << 16) | (nGreen << 8) | nRed;
4224 else
4226 nRGB = (nRed << 16) | (nGreen << 8) | nBlue;
4228 rPar.Get(0)->PutLong( nRGB );
4231 RTLFUNC(QBColor)
4233 (void)pBasic;
4234 (void)bWrite;
4236 static const sal_Int32 pRGB[] =
4238 0x000000,
4239 0x800000,
4240 0x008000,
4241 0x808000,
4242 0x000080,
4243 0x800080,
4244 0x008080,
4245 0xC0C0C0,
4246 0x808080,
4247 0xFF0000,
4248 0x00FF00,
4249 0xFFFF00,
4250 0x0000FF,
4251 0xFF00FF,
4252 0x00FFFF,
4253 0xFFFFFF,
4256 if ( rPar.Count() != 2 )
4258 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4259 return;
4262 sal_Int16 nCol = rPar.Get(1)->GetInteger();
4263 if( nCol < 0 || nCol > 15 )
4265 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4266 return;
4268 sal_Int32 nRGB = pRGB[ nCol ];
4269 rPar.Get(0)->PutLong( nRGB );
4272 // StrConv(string, conversion, LCID)
4273 RTLFUNC(StrConv)
4275 (void)pBasic;
4276 (void)bWrite;
4278 sal_uIntPtr nArgCount = rPar.Count()-1;
4279 if( nArgCount < 2 || nArgCount > 3 )
4281 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4282 return;
4285 OUString aOldStr = rPar.Get(1)->GetOUString();
4286 sal_Int32 nConversion = rPar.Get(2)->GetLong();
4288 sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
4290 sal_Int32 nOldLen = aOldStr.getLength();
4291 if( nOldLen == 0 )
4293 // null string,return
4294 rPar.Get(0)->PutString(aOldStr);
4295 return;
4298 sal_Int32 nType = 0;
4299 if ( (nConversion & 0x03) == 3 ) // vbProperCase
4301 const CharClass& rCharClass = GetCharClass();
4302 aOldStr = rCharClass.titlecase( aOldStr.toAsciiLowerCase(), 0, nOldLen );
4304 else if ( (nConversion & 0x01) == 1 ) // vbUpperCase
4306 nType |= i18n::TransliterationModules_LOWERCASE_UPPERCASE;
4308 else if ( (nConversion & 0x02) == 2 ) // vbLowerCase
4310 nType |= i18n::TransliterationModules_UPPERCASE_LOWERCASE;
4312 if ( (nConversion & 0x04) == 4 ) // vbWide
4314 nType |= i18n::TransliterationModules_HALFWIDTH_FULLWIDTH;
4316 else if ( (nConversion & 0x08) == 8 ) // vbNarrow
4318 nType |= i18n::TransliterationModules_FULLWIDTH_HALFWIDTH;
4320 if ( (nConversion & 0x10) == 16) // vbKatakana
4322 nType |= i18n::TransliterationModules_HIRAGANA_KATAKANA;
4324 else if ( (nConversion & 0x20) == 32 ) // vbHiragana
4326 nType |= i18n::TransliterationModules_KATAKANA_HIRAGANA;
4328 OUString aNewStr( aOldStr );
4329 if( nType != 0 )
4331 uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
4332 ::utl::TransliterationWrapper aTransliterationWrapper( xContext, nType );
4333 uno::Sequence<sal_Int32> aOffsets;
4334 aTransliterationWrapper.loadModuleIfNeeded( nLanguage );
4335 aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
4338 if ( (nConversion & 0x40) == 64 ) // vbUnicode
4340 // convert the string to byte string, preserving unicode (2 bytes per character)
4341 sal_Int32 nSize = aNewStr.getLength()*2;
4342 const sal_Unicode* pSrc = aNewStr.getStr();
4343 sal_Char* pChar = new sal_Char[nSize+1];
4344 for( sal_Int32 i=0; i < nSize; i++ )
4346 pChar[i] = static_cast< sal_Char >( (i%2) ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff );
4347 if( i%2 )
4349 pSrc++;
4352 pChar[nSize] = '\0';
4353 OString aOStr(pChar);
4354 delete[] pChar;
4356 // there is no concept about default codepage in unix. so it is incorrectly in unix
4357 OUString aOUStr = OStringToOUString(aOStr, osl_getThreadTextEncoding());
4358 rPar.Get(0)->PutString( aOUStr );
4359 return;
4361 else if ( (nConversion & 0x80) == 128 ) // vbFromUnicode
4363 // there is no concept about default codepage in unix. so it is incorrectly in unix
4364 OString aOStr = OUStringToOString(aNewStr,osl_getThreadTextEncoding());
4365 const sal_Char* pChar = aOStr.getStr();
4366 sal_Int32 nArraySize = aOStr.getLength();
4367 SbxDimArray* pArray = new SbxDimArray(SbxBYTE);
4368 bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() );
4369 if(nArraySize)
4371 if( bIncIndex )
4373 pArray->AddDim( 1, nArraySize );
4375 else
4377 pArray->AddDim( 0, nArraySize-1 );
4380 else
4382 pArray->unoAddDim( 0, -1 );
4385 for( sal_Int32 i=0; i< nArraySize; i++)
4387 SbxVariable* pNew = new SbxVariable( SbxBYTE );
4388 pNew->PutByte(*pChar);
4389 pChar++;
4390 pNew->SetFlag( SBX_WRITE );
4391 short index = i;
4392 if( bIncIndex )
4394 ++index;
4396 pArray->Put( pNew, &index );
4399 SbxVariableRef refVar = rPar.Get(0);
4400 sal_uInt16 nFlags = refVar->GetFlags();
4401 refVar->ResetFlag( SBX_FIXED );
4402 refVar->PutObject( pArray );
4403 refVar->SetFlags( nFlags );
4404 refVar->SetParameters( NULL );
4405 return;
4407 rPar.Get(0)->PutString(aNewStr);
4411 RTLFUNC(Beep)
4413 (void)pBasic;
4414 (void)bWrite;
4416 if ( rPar.Count() != 1 )
4418 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4419 return;
4421 Sound::Beep();
4424 RTLFUNC(Load)
4426 (void)pBasic;
4427 (void)bWrite;
4429 if( rPar.Count() != 2 )
4431 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4432 return;
4436 SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject();
4437 if ( pObj )
4439 if( pObj->IsA( TYPE( SbUserFormModule ) ) )
4441 ((SbUserFormModule*)pObj)->Load();
4443 else if( pObj->IsA( TYPE( SbxObject ) ) )
4445 SbxVariable* pVar = ((SbxObject*)pObj)->Find( OUString("Load"), SbxCLASS_METHOD );
4446 if( pVar )
4448 pVar->GetInteger();
4454 RTLFUNC(Unload)
4456 (void)pBasic;
4457 (void)bWrite;
4459 rPar.Get(0)->PutEmpty();
4460 if( rPar.Count() != 2 )
4462 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4463 return;
4467 SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject();
4468 if ( pObj )
4470 if( pObj->IsA( TYPE( SbUserFormModule ) ) )
4472 SbUserFormModule* pFormModule = ( SbUserFormModule* )pObj;
4473 pFormModule->Unload();
4475 else if( pObj->IsA( TYPE( SbxObject ) ) )
4477 SbxVariable* pVar = ((SbxObject*)pObj)->Find( OUString("Unload"), SbxCLASS_METHOD );
4478 if( pVar )
4480 pVar->GetInteger();
4486 RTLFUNC(LoadPicture)
4488 (void)pBasic;
4489 (void)bWrite;
4491 if( rPar.Count() != 2 )
4493 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4494 return;
4497 OUString aFileURL = getFullPath( rPar.Get(1)->GetOUString() );
4498 SvStream* pStream = utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_READ );
4499 if( pStream != NULL )
4501 Bitmap aBmp;
4502 *pStream >> aBmp;
4503 Graphic aGraphic( aBmp );
4505 SbxObjectRef xRef = new SbStdPicture;
4506 ((SbStdPicture*)(SbxObject*)xRef)->SetGraphic( aGraphic );
4507 rPar.Get(0)->PutObject( xRef );
4509 delete pStream;
4512 RTLFUNC(SavePicture)
4514 (void)pBasic;
4515 (void)bWrite;
4517 rPar.Get(0)->PutEmpty();
4518 if( rPar.Count() != 3 )
4520 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4521 return;
4524 SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject();
4525 if( pObj->IsA( TYPE( SbStdPicture ) ) )
4527 SvFileStream aOStream( rPar.Get(2)->GetOUString(), STREAM_WRITE | STREAM_TRUNC );
4528 Graphic aGraphic = ((SbStdPicture*)pObj)->GetGraphic();
4529 aOStream << aGraphic;
4534 //-----------------------------------------------------------------------------------------
4536 RTLFUNC(MsgBox)
4538 (void)pBasic;
4539 (void)bWrite;
4541 static const WinBits nStyleMap[] =
4543 WB_OK, // MB_OK
4544 WB_OK_CANCEL, // MB_OKCANCEL
4545 WB_ABORT_RETRY_IGNORE, // MB_ABORTRETRYIGNORE
4546 WB_YES_NO_CANCEL, // MB_YESNOCANCEL
4547 WB_YES_NO, // MB_YESNO
4548 WB_RETRY_CANCEL // MB_RETRYCANCEL
4550 static const sal_Int16 nButtonMap[] =
4552 2, // #define RET_CANCEL sal_False
4553 1, // #define RET_OK sal_True
4554 6, // #define RET_YES 2
4555 7, // #define RET_NO 3
4556 4 // #define RET_RETRY 4
4560 sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
4561 if( nArgCount < 2 || nArgCount > 6 )
4563 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4564 return;
4566 WinBits nWinBits;
4567 WinBits nType = 0; // MB_OK
4568 if( nArgCount >= 3 )
4569 nType = (WinBits)rPar.Get(2)->GetInteger();
4570 WinBits nStyle = nType;
4571 nStyle &= 15; // delete bits 4-16
4572 if( nStyle > 5 )
4574 nStyle = 0;
4576 nWinBits = nStyleMap[ nStyle ];
4578 WinBits nWinDefBits;
4579 nWinDefBits = (WB_DEF_OK | WB_DEF_RETRY | WB_DEF_YES);
4580 if( nType & 256 )
4582 if( nStyle == 5 )
4584 nWinDefBits = WB_DEF_CANCEL;
4586 else if( nStyle == 2 )
4588 nWinDefBits = WB_DEF_RETRY;
4590 else
4592 nWinDefBits = (WB_DEF_CANCEL | WB_DEF_RETRY | WB_DEF_NO);
4595 else if( nType & 512 )
4597 if( nStyle == 2)
4599 nWinDefBits = WB_DEF_IGNORE;
4601 else
4603 nWinDefBits = WB_DEF_CANCEL;
4606 else if( nStyle == 2)
4608 nWinDefBits = WB_DEF_CANCEL;
4610 nWinBits |= nWinDefBits;
4612 OUString aMsg = rPar.Get(1)->GetOUString();
4613 OUString aTitle;
4614 if( nArgCount >= 4 )
4616 aTitle = rPar.Get(3)->GetOUString();
4618 else
4620 aTitle = GetpApp()->GetAppName();
4623 nType &= (16+32+64);
4624 MessBox* pBox = 0;
4625 Window* pParent = GetpApp()->GetDefDialogParent();
4626 switch( nType )
4628 case 16:
4629 pBox = new ErrorBox( pParent, nWinBits, aMsg );
4630 break;
4631 case 32:
4632 pBox = new QueryBox( pParent, nWinBits, aMsg );
4633 break;
4634 case 48:
4635 pBox = new WarningBox( pParent, nWinBits, aMsg );
4636 break;
4637 case 64:
4638 pBox = new InfoBox( pParent, aMsg );
4639 break;
4640 default:
4641 pBox = new MessBox( pParent, nWinBits, aTitle, aMsg );
4643 pBox->SetText( aTitle );
4644 sal_uInt16 nRet = (sal_uInt16)pBox->Execute();
4645 if( nRet == sal_True )
4647 nRet = 1;
4649 sal_Int16 nMappedRet;
4650 if( nStyle == 2 )
4652 nMappedRet = nRet;
4653 if( nMappedRet == 0 )
4655 nMappedRet = 3; // Abort
4658 else
4660 nMappedRet = nButtonMap[ nRet ];
4662 rPar.Get(0)->PutInteger( nMappedRet );
4663 delete pBox;
4666 RTLFUNC(SetAttr)
4668 (void)pBasic;
4669 (void)bWrite;
4671 rPar.Get(0)->PutEmpty();
4672 if ( rPar.Count() == 3 )
4674 OUString aStr = rPar.Get(1)->GetOUString();
4675 sal_Int16 nFlags = rPar.Get(2)->GetInteger();
4677 if( hasUno() )
4679 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
4680 if( xSFI.is() )
4684 sal_Bool bReadOnly = (nFlags & Sb_ATTR_READONLY) != 0;
4685 xSFI->setReadOnly( aStr, bReadOnly );
4686 sal_Bool bHidden = (nFlags & Sb_ATTR_HIDDEN) != 0;
4687 xSFI->setHidden( aStr, bHidden );
4689 catch(const Exception & )
4691 StarBASIC::Error( ERRCODE_IO_GENERAL );
4696 else
4698 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4702 RTLFUNC(Reset)
4704 (void)pBasic;
4705 (void)bWrite;
4706 (void)rPar;
4708 SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
4709 if (pIO)
4711 pIO->CloseAll();
4715 RTLFUNC(DumpAllObjects)
4717 (void)pBasic;
4718 (void)bWrite;
4720 sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
4721 if( nArgCount < 2 || nArgCount > 3 )
4723 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4725 else if( !pBasic )
4727 StarBASIC::Error( SbERR_INTERNAL_ERROR );
4729 else
4731 SbxObject* p = pBasic;
4732 while( p->GetParent() )
4734 p = p->GetParent();
4736 SvFileStream aStrm( rPar.Get( 1 )->GetOUString(),
4737 STREAM_WRITE | STREAM_TRUNC );
4738 p->Dump( aStrm, rPar.Get( 2 )->GetBool() );
4739 aStrm.Close();
4740 if( aStrm.GetError() != SVSTREAM_OK )
4742 StarBASIC::Error( SbERR_IO_ERROR );
4748 RTLFUNC(FileExists)
4750 (void)pBasic;
4751 (void)bWrite;
4753 if ( rPar.Count() == 2 )
4755 OUString aStr = rPar.Get(1)->GetOUString();
4756 sal_Bool bExists = sal_False;
4758 if( hasUno() )
4760 uno::Reference< ucb::XSimpleFileAccess3 > xSFI = getFileAccess();
4761 if( xSFI.is() )
4765 bExists = xSFI->exists( aStr );
4767 catch(const Exception & )
4769 StarBASIC::Error( ERRCODE_IO_GENERAL );
4773 else
4775 DirectoryItem aItem;
4776 FileBase::RC nRet = DirectoryItem::get( getFullPath( aStr ), aItem );
4777 bExists = (nRet == FileBase::E_None);
4779 rPar.Get(0)->PutBool( bExists );
4781 else
4783 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4787 RTLFUNC(Partition)
4789 (void)pBasic;
4790 (void)bWrite;
4792 if ( rPar.Count() != 5 )
4794 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4795 return;
4798 sal_Int32 nNumber = rPar.Get(1)->GetLong();
4799 sal_Int32 nStart = rPar.Get(2)->GetLong();
4800 sal_Int32 nStop = rPar.Get(3)->GetLong();
4801 sal_Int32 nInterval = rPar.Get(4)->GetLong();
4803 if( nStart < 0 || nStop <= nStart || nInterval < 1 )
4805 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4806 return;
4809 // the Partition function inserts leading spaces before lowervalue and uppervalue
4810 // so that they both have the same number of characters as the string
4811 // representation of the value (Stop + 1). This ensures that if you use the output
4812 // of the Partition function with several values of Number, the resulting text
4813 // will be handled properly during any subsequent sort operation.
4815 // calculate the maximun number of characters before lowervalue and uppervalue
4816 OUString aBeforeStart = OUString::valueOf( nStart - 1 );
4817 OUString aAfterStop = OUString::valueOf( nStop + 1 );
4818 sal_Int32 nLen1 = aBeforeStart.getLength();
4819 sal_Int32 nLen2 = aAfterStop.getLength();
4820 sal_Int32 nLen = nLen1 >= nLen2 ? nLen1:nLen2;
4822 OUStringBuffer aRetStr( nLen * 2 + 1);
4823 OUString aLowerValue;
4824 OUString aUpperValue;
4825 if( nNumber < nStart )
4827 aUpperValue = aBeforeStart;
4829 else if( nNumber > nStop )
4831 aLowerValue = aAfterStop;
4833 else
4835 sal_Int32 nLowerValue = nNumber;
4836 sal_Int32 nUpperValue = nLowerValue;
4837 if( nInterval > 1 )
4839 nLowerValue = ((( nNumber - nStart ) / nInterval ) * nInterval ) + nStart;
4840 nUpperValue = nLowerValue + nInterval - 1;
4842 aLowerValue = OUString::valueOf( nLowerValue );
4843 aUpperValue = OUString::valueOf( nUpperValue );
4846 nLen1 = aLowerValue.getLength();
4847 nLen2 = aUpperValue.getLength();
4849 if( nLen > nLen1 )
4851 // appending the leading spaces for the lowervalue
4852 for ( sal_Int32 i= (nLen - nLen1) ; i > 0; --i )
4854 aRetStr.appendAscii(" ");
4857 aRetStr.append( aLowerValue ).appendAscii(":");
4858 if( nLen > nLen2 )
4860 // appending the leading spaces for the uppervalue
4861 for ( sal_Int32 i= (nLen - nLen2) ; i > 0; --i )
4863 aRetStr.appendAscii(" ");
4866 aRetStr.append( aUpperValue );
4867 rPar.Get(0)->PutString( aRetStr.makeStringAndClear());
4870 #endif
4872 static long GetDayDiff( const Date& rDate )
4874 Date aRefDate( 1,1,1900 );
4875 long nDiffDays;
4876 if ( aRefDate > rDate )
4878 nDiffDays = (long)(aRefDate - rDate);
4879 nDiffDays *= -1;
4881 else
4883 nDiffDays = (long)(rDate - aRefDate);
4885 nDiffDays += 2; // adjustment VisualBasic: 1.Jan.1900 == 2
4886 return nDiffDays;
4889 sal_Int16 implGetDateYear( double aDate )
4891 Date aRefDate( 1,1,1900 );
4892 long nDays = (long) aDate;
4893 nDays -= 2; // standardize: 1.1.1900 => 0.0
4894 aRefDate += nDays;
4895 sal_Int16 nRet = (sal_Int16)( aRefDate.GetYear() );
4896 return nRet;
4899 bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, double& rdRet )
4901 #ifndef DISABLE_SCRIPTING
4902 if ( nYear < 30 && SbiRuntime::isVBAEnabled() )
4904 nYear += 2000;
4906 else
4907 #endif
4909 if ( nYear < 100 )
4911 nYear += 1900;
4914 Date aCurDate( nDay, nMonth, nYear );
4915 if ((nYear < 100 || nYear > 9999) )
4917 #ifndef DISABLE_SCRIPTING
4918 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4919 #endif
4920 return false;
4923 #ifndef DISABLE_SCRIPTING
4924 if ( !SbiRuntime::isVBAEnabled() )
4925 #endif
4927 if ( (nMonth < 1 || nMonth > 12 )||
4928 (nDay < 1 || nDay > 31 ) )
4930 #ifndef DISABLE_SCRIPTING
4931 StarBASIC::Error( SbERR_BAD_ARGUMENT );
4932 #endif
4933 return false;
4936 #ifndef DISABLE_SCRIPTING
4937 else
4939 // grab the year & month
4940 aCurDate = Date( 1, (( nMonth % 12 ) > 0 ) ? ( nMonth % 12 ) : 12 + ( nMonth % 12 ), nYear );
4942 // adjust year based on month value
4943 // e.g. 2000, 0, xx = 1999, 12, xx ( or December of the previous year )
4944 // 2000, 13, xx = 2001, 1, xx ( or January of the following year )
4945 if( ( nMonth < 1 ) || ( nMonth > 12 ) )
4947 // inacurrate around leap year, don't use days to calculate,
4948 // just modify the months directory
4949 sal_Int16 nYearAdj = ( nMonth /12 ); // default to positive months inputed
4950 if ( nMonth <=0 )
4952 nYearAdj = ( ( nMonth -12 ) / 12 );
4954 aCurDate.SetYear( aCurDate.GetYear() + nYearAdj );
4957 // adjust day value,
4958 // e.g. 2000, 2, 0 = 2000, 1, 31 or the last day of the previous month
4959 // 2000, 1, 32 = 2000, 2, 1 or the first day of the following month
4960 if( ( nDay < 1 ) || ( nDay > aCurDate.GetDaysInMonth() ) )
4962 aCurDate += nDay - 1;
4964 else
4966 aCurDate.SetDay( nDay );
4969 #endif
4971 long nDiffDays = GetDayDiff( aCurDate );
4972 rdRet = (double)nDiffDays;
4973 return true;
4976 double implTimeSerial( sal_Int16 nHours, sal_Int16 nMinutes, sal_Int16 nSeconds )
4978 return
4979 static_cast<double>( nHours * ::Time::secondPerHour +
4980 nMinutes * ::Time::secondPerMinute +
4981 nSeconds)
4983 static_cast<double>( ::Time::secondPerDay );
4986 bool implDateTimeSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
4987 sal_Int16 nHour, sal_Int16 nMinute, sal_Int16 nSecond,
4988 double& rdRet )
4990 double dDate;
4991 if(!implDateSerial(nYear, nMonth, nDay, dDate))
4992 return false;
4993 rdRet += dDate + implTimeSerial(nHour, nMinute, nSecond);
4994 return true;
4997 sal_Int16 implGetMinute( double dDate )
4999 if( dDate < 0.0 )
5001 dDate *= -1.0;
5003 double nFrac = dDate - floor( dDate );
5004 nFrac *= 86400.0;
5005 sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
5006 sal_Int16 nTemp = (sal_Int16)(nSeconds % 3600);
5007 sal_Int16 nMin = nTemp / 60;
5008 return nMin;
5011 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */