diff options
Diffstat (limited to 'basic/source/runtime/methods.cxx')
-rw-r--r-- | basic/source/runtime/methods.cxx | 4540 |
1 files changed, 4540 insertions, 0 deletions
diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx new file mode 100644 index 000000000000..1d1f1c641547 --- /dev/null +++ b/basic/source/runtime/methods.cxx @@ -0,0 +1,4540 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + + +#include <tools/date.hxx> +#include <basic/sbxvar.hxx> +#ifndef _VOS_PROCESS_HXX +#include <vos/process.hxx> +#endif +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/sound.hxx> +#include <tools/wintypes.hxx> +#include <vcl/msgbox.hxx> +#include <basic/sbx.hxx> +#include <svl/zforlist.hxx> +#include <rtl/math.hxx> +#include <tools/urlobj.hxx> +#include <osl/time.h> +#include <unotools/charclass.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <tools/wldcrd.hxx> +#include <i18npool/lang.h> + +#include "runtime.hxx" +#include "sbunoobj.hxx" +#ifdef WNT +#include <tools/prewin.h> +#include "winbase.h" +#include <tools/postwin.h> +#ifndef _FSYS_HXX //autogen +#include <tools/fsys.hxx> +#endif +#else +#include <osl/file.hxx> +#endif +#include "errobject.hxx" + +#ifdef _USE_UNO +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess3.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> + +using namespace comphelper; +using namespace osl; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::ucb; +using namespace com::sun::star::io; + +#endif /* _USE_UNO */ + +//#define _ENABLE_CUR_DIR + +#include "stdobj.hxx" +#include <basic/sbstdobj.hxx> +#include "rtlproto.hxx" +#include "basrid.hxx" +#include "image.hxx" +#include "sb.hrc" +#include "iosys.hxx" +#include "ddectrl.hxx" +#include <sbintern.hxx> + +#include <list> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#if defined (WNT) || defined (OS2) +#include <direct.h> // _getdcwd get current work directory, _chdrive +#endif + +#ifdef UNX +#include <errno.h> +#include <unistd.h> +#endif + +#ifdef WNT +#include <io.h> +#endif + +#include <basic/sbobjmod.hxx> + +static void FilterWhiteSpace( String& rStr ) +{ + rStr.EraseAllChars( ' ' ); + rStr.EraseAllChars( '\t' ); + rStr.EraseAllChars( '\n' ); + rStr.EraseAllChars( '\r' ); +} + +static long GetDayDiff( const Date& rDate ) +{ + Date aRefDate( 1,1,1900 ); + long nDiffDays; + if ( aRefDate > rDate ) + { + nDiffDays = (long)(aRefDate - rDate); + nDiffDays *= -1; + } + else + nDiffDays = (long)(rDate - aRefDate); + nDiffDays += 2; // Anpassung VisualBasic: 1.Jan.1900 == 2 + return nDiffDays; +} + +static CharClass& GetCharClass( void ) +{ + static sal_Bool bNeedsInit = sal_True; + static ::com::sun::star::lang::Locale aLocale; + if( bNeedsInit ) + { + bNeedsInit = sal_False; + aLocale = Application::GetSettings().GetLocale(); + } + static CharClass aCharClass( aLocale ); + return aCharClass; +} + +static inline sal_Bool isFolder( FileStatus::Type aType ) +{ + return ( aType == FileStatus::Directory || aType == FileStatus::Volume ); +} + + +//*** UCB file access *** + +// Converts possibly relative paths to absolute paths +// according to the setting done by ChDir/ChDrive +String getFullPath( const String& aRelPath ) +{ + ::rtl::OUString aFileURL; + + // #80204 Try first if it already is a valid URL + INetURLObject aURLObj( aRelPath ); + aFileURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + + if( !aFileURL.getLength() ) + { + File::getFileURLFromSystemPath( aRelPath, aFileURL ); + } + + return aFileURL; +} + +// Sets (virtual) current path for UCB file access +void implChDir( const String& aDir ) +{ + (void)aDir; + // TODO +} + +// Sets (virtual) current drive for UCB file access +void implChDrive( const String& aDrive ) +{ + (void)aDrive; + // TODO +} + +// Returns (virtual) current path for UCB file access +String implGetCurDir( void ) +{ + String aRetStr; + + return aRetStr; +} + +// TODO: -> SbiGlobals +static com::sun::star::uno::Reference< XSimpleFileAccess3 > getFileAccess( void ) +{ + static com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI; + if( !xSFI.is() ) + { + com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + if( xSMgr.is() ) + { + xSFI = com::sun::star::uno::Reference< XSimpleFileAccess3 >( xSMgr->createInstance + ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY ); + } + } + return xSFI; +} + + + +// Properties und Methoden legen beim Get (bPut = sal_False) den Returnwert +// im Element 0 des Argv ab; beim Put (bPut = sal_True) wird der Wert aus +// Element 0 gespeichert. + +// CreateObject( class ) + +RTLFUNC(CreateObject) +{ + (void)bWrite; + + String aClass( rPar.Get( 1 )->GetString() ); + SbxObjectRef p = SbxBase::CreateObject( aClass ); + if( !p ) + StarBASIC::Error( SbERR_CANNOT_LOAD ); + else + { + // Convenience: BASIC als Parent eintragen + p->SetParent( pBasic ); + rPar.Get( 0 )->PutObject( p ); + } +} + +// Error( n ) + +RTLFUNC(Error) +{ + (void)bWrite; + + if( !pBasic ) + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + else + { + String aErrorMsg; + SbError nErr = 0L; + sal_Int32 nCode = 0; + if( rPar.Count() == 1 ) + { + nErr = StarBASIC::GetErrBasic(); + aErrorMsg = StarBASIC::GetErrorMsg(); + } + else + { + nCode = rPar.Get( 1 )->GetLong(); + if( nCode > 65535L ) + StarBASIC::Error( SbERR_CONVERSION ); + else + nErr = StarBASIC::GetSfxFromVBError( (sal_uInt16)nCode ); + } + + bool bVBA = SbiRuntime::isVBAEnabled(); + String tmpErrMsg; + if( bVBA && aErrorMsg.Len() > 0 ) + { + tmpErrMsg = aErrorMsg; + } + else + { + pBasic->MakeErrorText( nErr, aErrorMsg ); + tmpErrMsg = pBasic->GetErrorText(); + } + // If this rtlfunc 'Error' passed a errcode the same as the active Err Objects's + // current err then return the description for the error message if it is set + // ( complicated isn't it ? ) + if ( bVBA && rPar.Count() > 1 ) + { + com::sun::star::uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() ); + if ( xErrObj.is() && xErrObj->getNumber() == nCode && xErrObj->getDescription().getLength() ) + tmpErrMsg = xErrObj->getDescription(); + } + rPar.Get( 0 )->PutString( tmpErrMsg ); + } +} + +// Sinus + +RTLFUNC(Sin) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( sin( pArg->GetDouble() ) ); + } +} + +// Cosinus + +RTLFUNC(Cos) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( cos( pArg->GetDouble() ) ); + } +} + +// Atn + +RTLFUNC(Atn) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( atan( pArg->GetDouble() ) ); + } +} + + + +RTLFUNC(Abs) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( fabs( pArg->GetDouble() ) ); + } +} + + +RTLFUNC(Asc) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + String aStr( pArg->GetString() ); + if ( aStr.Len() == 0 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + rPar.Get(0)->PutEmpty(); + } + else + { + sal_Unicode aCh = aStr.GetBuffer()[0]; + rPar.Get(0)->PutLong( aCh ); + } + } +} + +RTLFUNC(Chr) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + sal_Unicode aCh = (sal_Unicode)pArg->GetUShort(); + String aStr( aCh ); + rPar.Get(0)->PutString( aStr ); + } +} + + +#ifdef UNX +#define _MAX_PATH 260 +#define _PATH_INCR 250 +#endif + +RTLFUNC(CurDir) +{ + (void)pBasic; + (void)bWrite; + + // #57064 Obwohl diese Funktion nicht mit DirEntry arbeitet, ist sie von + // der Anpassung an virtuelle URLs nich betroffen, da bei Nutzung der + // DirEntry-Funktionalitaet keine Moeglichkeit besteht, das aktuelle so + // zu ermitteln, dass eine virtuelle URL geliefert werden koennte. + +// rPar.Get(0)->PutEmpty(); +#if defined (WNT) || defined (OS2) + int nCurDir = 0; // Current dir // JSM + if ( rPar.Count() == 2 ) + { + String aDrive = rPar.Get(1)->GetString(); + if ( aDrive.Len() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + else + { + nCurDir = (int)aDrive.GetBuffer()[0]; + if ( !isalpha( nCurDir ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + else + nCurDir -= ( 'A' - 1 ); + } + } + char* pBuffer = new char[ _MAX_PATH ]; +#ifdef OS2 + if( !nCurDir ) + nCurDir = _getdrive(); +#endif + if ( _getdcwd( nCurDir, pBuffer, _MAX_PATH ) != 0 ) + rPar.Get(0)->PutString( String::CreateFromAscii( pBuffer ) ); + else + StarBASIC::Error( SbERR_NO_DEVICE ); + delete [] pBuffer; + +#elif defined( UNX ) + + int nSize = _PATH_INCR; + char* pMem; + while( sal_True ) + { + pMem = new char[nSize]; + if( !pMem ) + { + StarBASIC::Error( SbERR_NO_MEMORY ); + return; + } + if( getcwd( pMem, nSize-1 ) != NULL ) + { + rPar.Get(0)->PutString( String::CreateFromAscii(pMem) ); + delete [] pMem; + return; + } + if( errno != ERANGE ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + delete [] pMem; + return; + } + delete [] pMem; + nSize += _PATH_INCR; + }; + +#endif +} + +RTLFUNC(ChDir) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { +#ifdef _ENABLE_CUR_DIR + String aPath = rPar.Get(1)->GetString(); + sal_Bool bError = sal_False; +#ifdef WNT + // #55997 Laut MI hilft es bei File-URLs einen DirEntry zwischenzuschalten + // #40996 Harmoniert bei Verwendung der WIN32-Funktion nicht mit getdir + DirEntry aEntry( aPath ); + ByteString aFullPath( aEntry.GetFull(), gsl_getSystemTextEncoding() ); + if( chdir( aFullPath.GetBuffer()) ) + bError = sal_True; +#else + if (!DirEntry(aPath).SetCWD()) + bError = sal_True; +#endif + if( bError ) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#endif + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(ChDrive) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { +#ifdef _ENABLE_CUR_DIR + // Keine Laufwerke in Unix +#ifndef UNX + String aPar1 = rPar.Get(1)->GetString(); + +#if defined (WNT) || defined (OS2) + if (aPar1.Len() > 0) + { + int nCurDrive = (int)aPar1.GetBuffer()[0]; ; + if ( !isalpha( nCurDrive ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + else + nCurDrive -= ( 'A' - 1 ); + if (_chdrive(nCurDrive)) + StarBASIC::Error( SbERR_NO_DEVICE ); + } +#endif + +#endif + // #ifndef UNX +#endif + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + + +// Implementation of StepRENAME with UCB +void implStepRenameUCB( const String& aSource, const String& aDest ) +{ + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + String aSourceFullPath = getFullPath( aSource ); + if( !xSFI->exists( aSourceFullPath ) ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + return; + } + + String aDestFullPath = getFullPath( aDest ); + if( xSFI->exists( aDestFullPath ) ) + StarBASIC::Error( SbERR_FILE_EXISTS ); + else + xSFI->move( aSourceFullPath, aDestFullPath ); + } + catch( Exception & ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + } + } +} + +// Implementation of StepRENAME with OSL +void implStepRenameOSL( const String& aSource, const String& aDest ) +{ + FileBase::RC nRet = File::move( getFullPathUNC( aSource ), getFullPathUNC( aDest ) ); + if( nRet != FileBase::E_None ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } +} + +RTLFUNC(FileCopy) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 3) + { + String aSource = rPar.Get(1)->GetString(); + String aDest = rPar.Get(2)->GetString(); + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) ); + } + catch( Exception & ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aSourceDirEntry(aSource); + if (aSourceDirEntry.Exists()) + { + if (aSourceDirEntry.CopyTo(DirEntry(aDest),FSYS_ACTION_COPYFILE) != FSYS_ERR_OK) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } + else + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + FileBase::RC nRet = File::copy( getFullPathUNC( aSource ), getFullPathUNC( aDest ) ); + if( nRet != FileBase::E_None ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(Kill) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { + String aFileSpec = rPar.Get(1)->GetString(); + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + String aFullPath = getFullPath( aFileSpec ); + if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + return; + } + try + { + xSFI->kill( aFullPath ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + if(DirEntry(aFileSpec).Kill() != FSYS_ERR_OK) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + File::remove( getFullPathUNC( aFileSpec ) ); +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(MkDir) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { + String aPath = rPar.Get(1)->GetString(); + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + xSFI->createFolder( getFullPath( aPath ) ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + if (!DirEntry(aPath).MakeDir()) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + Directory::create( getFullPathUNC( aPath ) ); +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + + +#ifndef _OLD_FILE_IMPL + +// In OSL only empty directories can be deleted +// so we have to delete all files recursively +void implRemoveDirRecursive( const String& aDirPath ) +{ + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem ); + sal_Bool bExists = (nRet == FileBase::E_None); + + FileStatus aFileStatus( FileStatusMask_Type ); + nRet = aItem.getFileStatus( aFileStatus ); + FileStatus::Type aType = aFileStatus.getFileType(); + sal_Bool bFolder = isFolder( aType ); + + if( !bExists || !bFolder ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + return; + } + + Directory aDir( aDirPath ); + nRet = aDir.open(); + if( nRet != FileBase::E_None ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + return; + } + + for( ;; ) + { + DirectoryItem aItem2; + nRet = aDir.getNextItem( aItem2 ); + if( nRet != FileBase::E_None ) + break; + + // Handle flags + FileStatus aFileStatus2( FileStatusMask_Type | FileStatusMask_FileURL ); + nRet = aItem2.getFileStatus( aFileStatus2 ); + ::rtl::OUString aPath = aFileStatus2.getFileURL(); + + // Directory? + FileStatus::Type aType2 = aFileStatus2.getFileType(); + sal_Bool bFolder2 = isFolder( aType2 ); + if( bFolder2 ) + { + implRemoveDirRecursive( aPath ); + } + else + { + File::remove( aPath ); + } + } + nRet = aDir.close(); + + nRet = Directory::remove( aDirPath ); +} +#endif + + +RTLFUNC(RmDir) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { + String aPath = rPar.Get(1)->GetString(); + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + if( !xSFI->isFolder( aPath ) ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + return; + } + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + Sequence< ::rtl::OUString > aContent = xSFI->getFolderContents( aPath, true ); + sal_Int32 nCount = aContent.getLength(); + if( nCount > 0 ) + { + StarBASIC::Error( SbERR_ACCESS_ERROR ); + return; + } + } + + xSFI->kill( getFullPath( aPath ) ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aDirEntry(aPath); + if (aDirEntry.Kill() != FSYS_ERR_OK) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + implRemoveDirRecursive( getFullPathUNC( aPath ) ); +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(SendKeys) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); +} + +RTLFUNC(Exp) +{ + (void)pBasic; + (void)bWrite; + + if( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double aDouble = rPar.Get( 1 )->GetDouble(); + aDouble = exp( aDouble ); + checkArithmeticOverflow( aDouble ); + rPar.Get( 0 )->PutDouble( aDouble ); + } +} + +RTLFUNC(FileLen) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + String aStr( pArg->GetString() ); + sal_Int32 nLen = 0; + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + nLen = xSFI->getSize( getFullPath( aStr ) ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + FileStat aStat = DirEntry( aStr ); + nLen = aStat.GetSize(); +#else + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( aStr ), aItem ); + FileStatus aFileStatus( FileStatusMask_FileSize ); + nRet = aItem.getFileStatus( aFileStatus ); + nLen = (sal_Int32)aFileStatus.getFileSize(); +#endif + } + rPar.Get(0)->PutLong( (long)nLen ); + } +} + + +RTLFUNC(Hex) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + char aBuffer[16]; + SbxVariableRef pArg = rPar.Get( 1 ); + if ( pArg->IsInteger() ) + snprintf( aBuffer, sizeof(aBuffer), "%X", pArg->GetInteger() ); + else + snprintf( aBuffer, sizeof(aBuffer), "%lX", static_cast<long unsigned int>(pArg->GetLong()) ); + rPar.Get(0)->PutString( String::CreateFromAscii( aBuffer ) ); + } +} + +// InStr( [start],string,string,[compare] ) + +RTLFUNC(InStr) +{ + (void)pBasic; + (void)bWrite; + + sal_uIntPtr nArgCount = rPar.Count()-1; + if ( nArgCount < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_uInt16 nStartPos = 1; + + sal_uInt16 nFirstStringPos = 1; + if ( nArgCount >= 3 ) + { + sal_Int32 lStartPos = rPar.Get(1)->GetLong(); + if( lStartPos <= 0 || lStartPos > 0xffff ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + lStartPos = 1; + } + nStartPos = (sal_uInt16)lStartPos; + nFirstStringPos++; + } + + SbiInstance* pInst = pINST; + int bTextMode; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + SbiRuntime* pRT = pInst ? pInst->pRun : NULL; + bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False; + } + else + { + bTextMode = 1;; + } + if ( nArgCount == 4 ) + bTextMode = rPar.Get(4)->GetInteger(); + + sal_uInt16 nPos; + const String& rToken = rPar.Get(nFirstStringPos+1)->GetString(); + + // #97545 Always find empty string + if( !rToken.Len() ) + { + nPos = nStartPos; + } + else + { + if( !bTextMode ) + { + const String& rStr1 = rPar.Get(nFirstStringPos)->GetString(); + + nPos = rStr1.Search( rToken, nStartPos-1 ); + if ( nPos == STRING_NOTFOUND ) + nPos = 0; + else + nPos++; + } + else + { + String aStr1 = rPar.Get(nFirstStringPos)->GetString(); + String aToken = rToken; + + aStr1.ToUpperAscii(); + aToken.ToUpperAscii(); + + nPos = aStr1.Search( aToken, nStartPos-1 ); + if ( nPos == STRING_NOTFOUND ) + nPos = 0; + else + nPos++; + } + } + rPar.Get(0)->PutLong( nPos ); + } +} + + +// InstrRev(string1, string2[, start[, compare]]) + +RTLFUNC(InStrRev) +{ + (void)pBasic; + (void)bWrite; + + sal_uIntPtr nArgCount = rPar.Count()-1; + if ( nArgCount < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr1 = rPar.Get(1)->GetString(); + String aToken = rPar.Get(2)->GetString(); + + sal_Int32 lStartPos = -1; + if ( nArgCount >= 3 ) + { + lStartPos = rPar.Get(3)->GetLong(); + if( (lStartPos <= 0 && lStartPos != -1) || lStartPos > 0xffff ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + lStartPos = -1; + } + } + + SbiInstance* pInst = pINST; + int bTextMode; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + SbiRuntime* pRT = pInst ? pInst->pRun : NULL; + bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False; + } + else + { + bTextMode = 1;; + } + if ( nArgCount == 4 ) + bTextMode = rPar.Get(4)->GetInteger(); + + sal_uInt16 nStrLen = aStr1.Len(); + sal_uInt16 nStartPos = lStartPos == -1 ? nStrLen : (sal_uInt16)lStartPos; + + sal_uInt16 nPos = 0; + if( nStartPos <= nStrLen ) + { + sal_uInt16 nTokenLen = aToken.Len(); + if( !nTokenLen ) + { + // Always find empty string + nPos = nStartPos; + } + else if( nStrLen > 0 ) + { + if( !bTextMode ) + { + ::rtl::OUString aOUStr1 ( aStr1 ); + ::rtl::OUString aOUToken( aToken ); + sal_Int32 nRet = aOUStr1.lastIndexOf( aOUToken, nStartPos ); + if( nRet == -1 ) + nPos = 0; + else + nPos = (sal_uInt16)nRet + 1; + } + else + { + aStr1.ToUpperAscii(); + aToken.ToUpperAscii(); + + ::rtl::OUString aOUStr1 ( aStr1 ); + ::rtl::OUString aOUToken( aToken ); + sal_Int32 nRet = aOUStr1.lastIndexOf( aOUToken, nStartPos ); + + if( nRet == -1 ) + nPos = 0; + else + nPos = (sal_uInt16)nRet + 1; + } + } + } + rPar.Get(0)->PutLong( nPos ); + } +} + + +/* + Int( 2.8 ) = 2.0 + Int( -2.8 ) = -3.0 + Fix( 2.8 ) = 2.0 + Fix( -2.8 ) = -2.0 <- !! +*/ + +RTLFUNC(Int) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + double aDouble= pArg->GetDouble(); + /* + floor( 2.8 ) = 2.0 + floor( -2.8 ) = -3.0 + */ + aDouble = floor( aDouble ); + rPar.Get(0)->PutDouble( aDouble ); + } +} + + + +RTLFUNC(Fix) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + double aDouble = pArg->GetDouble(); + if ( aDouble >= 0.0 ) + aDouble = floor( aDouble ); + else + aDouble = ceil( aDouble ); + rPar.Get(0)->PutDouble( aDouble ); + } +} + + +RTLFUNC(LCase) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + CharClass& rCharClass = GetCharClass(); + String aStr( rPar.Get(1)->GetString() ); + rCharClass.toLower( aStr ); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(Left) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr( rPar.Get(1)->GetString() ); + sal_Int32 lResultLen = rPar.Get(2)->GetLong(); + if( lResultLen > 0xffff ) + { + lResultLen = 0xffff; + } + else if( lResultLen < 0 ) + { + lResultLen = 0; + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } + aStr.Erase( (sal_uInt16)lResultLen ); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(Log) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double aArg = rPar.Get(1)->GetDouble(); + if ( aArg > 0 ) + { + double d = log( aArg ); + checkArithmeticOverflow( d ); + rPar.Get( 0 )->PutDouble( d ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } +} + +RTLFUNC(LTrim) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr( rPar.Get(1)->GetString() ); + aStr.EraseLeadingChars(); + rPar.Get(0)->PutString( aStr ); + } +} + + +// Mid( String, nStart, nLength ) + +RTLFUNC(Mid) +{ + (void)pBasic; + (void)bWrite; + + sal_uIntPtr nArgCount = rPar.Count()-1; + if ( nArgCount < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // #23178: Funktionalitaet von Mid$ als Anweisung nachbilden, indem + // als weiterer (4.) Parameter ein Ersetzungsstring aufgenommen wird. + // Anders als im Original kann in dieser Variante der 3. Parameter + // nLength nicht weggelassen werden. Ist ueber bWrite schon vorgesehen. + if( nArgCount == 4 ) + bWrite = sal_True; + + String aArgStr = rPar.Get(1)->GetString(); + sal_uInt16 nStartPos = (sal_uInt16)(rPar.Get(2)->GetLong() ); + if ( nStartPos == 0 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + nStartPos--; + sal_uInt16 nLen = 0xffff; + bool bWriteNoLenParam = false; + if ( nArgCount == 3 || bWrite ) + { + sal_Int32 n = rPar.Get(3)->GetLong(); + if( bWrite && n == -1 ) + bWriteNoLenParam = true; + nLen = (sal_uInt16)n; + } + String aResultStr; + if ( bWrite ) + { + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + sal_uInt16 nArgLen = aArgStr.Len(); + if( nStartPos + 1 > nArgLen ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aReplaceStr = rPar.Get(4)->GetString(); + sal_uInt16 nReplaceStrLen = aReplaceStr.Len(); + sal_uInt16 nReplaceLen; + if( bWriteNoLenParam ) + { + nReplaceLen = nReplaceStrLen; + } + else + { + nReplaceLen = nLen; + if( nReplaceLen > nReplaceStrLen ) + nReplaceLen = nReplaceStrLen; + } + + sal_uInt16 nReplaceEndPos = nStartPos + nReplaceLen; + if( nReplaceEndPos > nArgLen ) + nReplaceLen -= (nReplaceEndPos - nArgLen); + + aResultStr = aArgStr; + sal_uInt16 nErase = nReplaceLen; + aResultStr.Erase( nStartPos, nErase ); + aResultStr.Insert( aReplaceStr, 0, nReplaceLen, nStartPos ); + } + else + { + aResultStr = aArgStr; + aResultStr.Erase( nStartPos, nLen ); + aResultStr.Insert(rPar.Get(4)->GetString(),0,nLen,nStartPos); + } + + rPar.Get(1)->PutString( aResultStr ); + } + else + { + aResultStr = aArgStr.Copy( nStartPos, nLen ); + rPar.Get(0)->PutString( aResultStr ); + } + } + } +} + +RTLFUNC(Oct) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + char aBuffer[16]; + SbxVariableRef pArg = rPar.Get( 1 ); + if ( pArg->IsInteger() ) + snprintf( aBuffer, sizeof(aBuffer), "%o", pArg->GetInteger() ); + else + snprintf( aBuffer, sizeof(aBuffer), "%lo", static_cast<long unsigned int>(pArg->GetLong()) ); + rPar.Get(0)->PutString( String::CreateFromAscii( aBuffer ) ); + } +} + +// Replace(expression, find, replace[, start[, count[, compare]]]) + +RTLFUNC(Replace) +{ + (void)pBasic; + (void)bWrite; + + sal_uIntPtr nArgCount = rPar.Count()-1; + if ( nArgCount < 3 || nArgCount > 6 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aExpStr = rPar.Get(1)->GetString(); + String aFindStr = rPar.Get(2)->GetString(); + String aReplaceStr = rPar.Get(3)->GetString(); + + sal_Int32 lStartPos = 1; + if ( nArgCount >= 4 ) + { + if( rPar.Get(4)->GetType() != SbxEMPTY ) + lStartPos = rPar.Get(4)->GetLong(); + if( lStartPos < 1 || lStartPos > 0xffff ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + lStartPos = 1; + } + } + + sal_Int32 lCount = -1; + if( nArgCount >=5 ) + { + if( rPar.Get(5)->GetType() != SbxEMPTY ) + lCount = rPar.Get(5)->GetLong(); + if( lCount < -1 || lCount > 0xffff ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + lCount = -1; + } + } + + SbiInstance* pInst = pINST; + int bTextMode; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + SbiRuntime* pRT = pInst ? pInst->pRun : NULL; + bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False; + } + else + { + bTextMode = 1; + } + if ( nArgCount == 6 ) + bTextMode = rPar.Get(6)->GetInteger(); + + sal_uInt16 nExpStrLen = aExpStr.Len(); + sal_uInt16 nFindStrLen = aFindStr.Len(); + sal_uInt16 nReplaceStrLen = aReplaceStr.Len(); + + if( lStartPos <= nExpStrLen ) + { + sal_uInt16 nPos = static_cast<sal_uInt16>( lStartPos - 1 ); + sal_uInt16 nCounts = 0; + while( lCount == -1 || lCount > nCounts ) + { + String aSrcStr( aExpStr ); + if( bTextMode ) + { + aSrcStr.ToUpperAscii(); + aFindStr.ToUpperAscii(); + } + nPos = aSrcStr.Search( aFindStr, nPos ); + if( nPos != STRING_NOTFOUND ) + { + aExpStr.Replace( nPos, nFindStrLen, aReplaceStr ); + nPos = nPos - nFindStrLen + nReplaceStrLen + 1; + nCounts++; + } + else + { + break; + } + } + } + rPar.Get(0)->PutString( aExpStr.Copy( static_cast<sal_uInt16>(lStartPos - 1) ) ); + } +} + +RTLFUNC(Right) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + const String& rStr = rPar.Get(1)->GetString(); + sal_Int32 lResultLen = rPar.Get(2)->GetLong(); + if( lResultLen > 0xffff ) + { + lResultLen = 0xffff; + } + else if( lResultLen < 0 ) + { + lResultLen = 0; + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } + sal_uInt16 nResultLen = (sal_uInt16)lResultLen; + sal_uInt16 nStrLen = rStr.Len(); + if ( nResultLen > nStrLen ) + nResultLen = nStrLen; + String aResultStr = rStr.Copy( nStrLen-nResultLen ); + rPar.Get(0)->PutString( aResultStr ); + } +} + +RTLFUNC(RTL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get( 0 )->PutObject( pBasic->getRTL() ); +} + +RTLFUNC(RTrim) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr( rPar.Get(1)->GetString() ); + aStr.EraseTrailingChars(); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(Sgn) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double aDouble = rPar.Get(1)->GetDouble(); + sal_Int16 nResult = 0; + if ( aDouble > 0 ) + nResult = 1; + else if ( aDouble < 0 ) + nResult = -1; + rPar.Get(0)->PutInteger( nResult ); + } +} + +RTLFUNC(Space) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr; + aStr.Fill( (sal_uInt16)(rPar.Get(1)->GetLong() )); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(Spc) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr; + aStr.Fill( (sal_uInt16)(rPar.Get(1)->GetLong() )); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(Sqr) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double aDouble = rPar.Get(1)->GetDouble(); + if ( aDouble >= 0 ) + rPar.Get(0)->PutDouble( sqrt( aDouble )); + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } +} + +RTLFUNC(Str) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr; + SbxVariableRef pArg = rPar.Get( 1 ); + pArg->Format( aStr ); + + // Numbers start with a space + if( pArg->IsNumericRTL() ) + { + // Kommas durch Punkte ersetzen, damit es symmetrisch zu Val ist! + aStr.SearchAndReplace( ',', '.' ); + + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + xub_StrLen nLen = aStr.Len(); + + const sal_Unicode* pBuf = aStr.GetBuffer(); + + bool bNeg = ( pBuf[0] == '-' ); + sal_uInt16 iZeroSearch = 0; + if( bNeg ) + iZeroSearch++; + + sal_uInt16 iNext = iZeroSearch + 1; + if( pBuf[iZeroSearch] == '0' && nLen > iNext && pBuf[iNext] == '.' ) + { + aStr.Erase( iZeroSearch, 1 ); + pBuf = aStr.GetBuffer(); + } + if( !bNeg ) + aStr.Insert( ' ', 0 ); + } + else + aStr.Insert( ' ', 0 ); + } + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(StrComp) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + rPar.Get(0)->PutEmpty(); + return; + } + const String& rStr1 = rPar.Get(1)->GetString(); + const String& rStr2 = rPar.Get(2)->GetString(); + + SbiInstance* pInst = pINST; + sal_Int16 nTextCompare; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + SbiRuntime* pRT = pInst ? pInst->pRun : NULL; + nTextCompare = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False; + } + else + { + nTextCompare = sal_True; + } + if ( rPar.Count() == 4 ) + nTextCompare = rPar.Get(3)->GetInteger(); + + if( !bCompatibility ) + nTextCompare = !nTextCompare; + + StringCompare aResult; + sal_Int32 nRetValue = 0; + if( nTextCompare ) + { + ::utl::TransliterationWrapper* pTransliterationWrapper = GetSbData()->pTransliterationWrapper; + if( !pTransliterationWrapper ) + { + com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + pTransliterationWrapper = GetSbData()->pTransliterationWrapper = + new ::utl::TransliterationWrapper( xSMgr, + ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE | + ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA | + ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH ); + } + + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + pTransliterationWrapper->loadModuleIfNeeded( eLangType ); + nRetValue = pTransliterationWrapper->compareString( rStr1, rStr2 ); + } + else + { + aResult = rStr1.CompareTo( rStr2 ); + if ( aResult == COMPARE_LESS ) + nRetValue = -1; + else if ( aResult == COMPARE_GREATER ) + nRetValue = 1; + } + + rPar.Get(0)->PutInteger( sal::static_int_cast< sal_Int16 >( nRetValue ) ); +} + +RTLFUNC(String) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr; + sal_Unicode aFiller; + sal_Int32 lCount = rPar.Get(1)->GetLong(); + if( lCount < 0 || lCount > 0xffff ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + sal_uInt16 nCount = (sal_uInt16)lCount; + if( rPar.Get(2)->GetType() == SbxINTEGER ) + aFiller = (sal_Unicode)rPar.Get(2)->GetInteger(); + else + { + const String& rStr = rPar.Get(2)->GetString(); + aFiller = rStr.GetBuffer()[0]; + } + aStr.Fill( nCount, aFiller ); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(Tan) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( tan( pArg->GetDouble() ) ); + } +} + +RTLFUNC(UCase) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + CharClass& rCharClass = GetCharClass(); + String aStr( rPar.Get(1)->GetString() ); + rCharClass.toUpper( aStr ); + rPar.Get(0)->PutString( aStr ); + } +} + + +RTLFUNC(Val) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double nResult = 0.0; + char* pEndPtr; + + String aStr( rPar.Get(1)->GetString() ); +// lt. Mikkysoft bei Kommas abbrechen! +// for( sal_uInt16 n=0; n < aStr.Len(); n++ ) +// if( aStr[n] == ',' ) aStr[n] = '.'; + + FilterWhiteSpace( aStr ); + if ( aStr.GetBuffer()[0] == '&' && aStr.Len() > 1 ) + { + int nRadix = 10; + char aChar = (char)aStr.GetBuffer()[1]; + if ( aChar == 'h' || aChar == 'H' ) + nRadix = 16; + else if ( aChar == 'o' || aChar == 'O' ) + nRadix = 8; + if ( nRadix != 10 ) + { + ByteString aByteStr( aStr, gsl_getSystemTextEncoding() ); + sal_Int16 nlResult = (sal_Int16)strtol( aByteStr.GetBuffer()+2, &pEndPtr, nRadix); + nResult = (double)nlResult; + } + } + else + { + // #57844 Lokalisierte Funktion benutzen + nResult = ::rtl::math::stringToDouble( aStr, '.', ',', NULL, NULL ); + checkArithmeticOverflow( nResult ); + // ATL: nResult = strtod( aStr.GetStr(), &pEndPtr ); + } + + rPar.Get(0)->PutDouble( nResult ); + } +} + + +// Helper functions for date conversion +sal_Int16 implGetDateDay( double aDate ) +{ + aDate -= 2.0; // normieren: 1.1.1900 => 0.0 + Date aRefDate( 1, 1, 1900 ); + if ( aDate >= 0.0 ) + { + aDate = floor( aDate ); + aRefDate += (sal_uIntPtr)aDate; + } + else + { + aDate = ceil( aDate ); + aRefDate -= (sal_uIntPtr)(-1.0 * aDate); + } + + sal_Int16 nRet = (sal_Int16)( aRefDate.GetDay() ); + return nRet; +} + +sal_Int16 implGetDateMonth( double aDate ) +{ + Date aRefDate( 1,1,1900 ); + long nDays = (long)aDate; + nDays -= 2; // normieren: 1.1.1900 => 0.0 + aRefDate += nDays; + sal_Int16 nRet = (sal_Int16)( aRefDate.GetMonth() ); + return nRet; +} + +sal_Int16 implGetDateYear( double aDate ) +{ + Date aRefDate( 1,1,1900 ); + long nDays = (long) aDate; + nDays -= 2; // normieren: 1.1.1900 => 0.0 + aRefDate += nDays; + sal_Int16 nRet = (sal_Int16)( aRefDate.GetYear() ); + return nRet; +} + +sal_Bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, double& rdRet ) +{ + if ( nYear < 30 && SbiRuntime::isVBAEnabled() ) + nYear += 2000; + else if ( nYear < 100 ) + nYear += 1900; + Date aCurDate( nDay, nMonth, nYear ); + if ((nYear < 100 || nYear > 9999) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return sal_False; + } + if ( !SbiRuntime::isVBAEnabled() ) + { + if ( (nMonth < 1 || nMonth > 12 )|| + (nDay < 1 || nDay > 31 ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return sal_False; + } + } + else + { + // grab the year & month + aCurDate = Date( 1, (( nMonth % 12 ) > 0 ) ? ( nMonth % 12 ) : 12 + ( nMonth % 12 ), nYear ); + + // adjust year based on month value + // e.g. 2000, 0, xx = 1999, 12, xx ( or December of the previous year ) + // 2000, 13, xx = 2001, 1, xx ( or January of the following year ) + if( ( nMonth < 1 ) || ( nMonth > 12 ) ) + { + // inacurrate around leap year, don't use days to calculate, + // just modify the months directory + sal_Int16 nYearAdj = ( nMonth /12 ); // default to positive months inputed + if ( nMonth <=0 ) + nYearAdj = ( ( nMonth -12 ) / 12 ); + aCurDate.SetYear( aCurDate.GetYear() + nYearAdj ); + } + + // adjust day value, + // e.g. 2000, 2, 0 = 2000, 1, 31 or the last day of the previous month + // 2000, 1, 32 = 2000, 2, 1 or the first day of the following month + if( ( nDay < 1 ) || ( nDay > aCurDate.GetDaysInMonth() ) ) + aCurDate += nDay - 1; + else + aCurDate.SetDay( nDay ); + } + + long nDiffDays = GetDayDiff( aCurDate ); + rdRet = (double)nDiffDays; + return sal_True; +} + +// Function to convert date to ISO 8601 date format +RTLFUNC(CDateToIso) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + double aDate = rPar.Get(1)->GetDate(); + + char Buffer[9]; + snprintf( Buffer, sizeof( Buffer ), "%04d%02d%02d", + implGetDateYear( aDate ), + implGetDateMonth( aDate ), + implGetDateDay( aDate ) ); + String aRetStr = String::CreateFromAscii( Buffer ); + rPar.Get(0)->PutString( aRetStr ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +// Function to convert date from ISO 8601 date format +RTLFUNC(CDateFromIso) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + String aStr = rPar.Get(1)->GetString(); + sal_Int16 iMonthStart = aStr.Len() - 4; + String aYearStr = aStr.Copy( 0, iMonthStart ); + String aMonthStr = aStr.Copy( iMonthStart, 2 ); + String aDayStr = aStr.Copy( iMonthStart+2, 2 ); + + double dDate; + if( implDateSerial( (sal_Int16)aYearStr.ToInt32(), + (sal_Int16)aMonthStr.ToInt32(), (sal_Int16)aDayStr.ToInt32(), dDate ) ) + { + rPar.Get(0)->PutDate( dDate ); + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(DateSerial) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nYear = rPar.Get(1)->GetInteger(); + sal_Int16 nMonth = rPar.Get(2)->GetInteger(); + sal_Int16 nDay = rPar.Get(3)->GetInteger(); + + double dDate; + if( implDateSerial( nYear, nMonth, nDay, dDate ) ) + rPar.Get(0)->PutDate( dDate ); +} + +RTLFUNC(TimeSerial) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nHour = rPar.Get(1)->GetInteger(); + if ( nHour == 24 ) + nHour = 0; // Wegen UNO DateTimes, die bis 24 Uhr gehen + sal_Int16 nMinute = rPar.Get(2)->GetInteger(); + sal_Int16 nSecond = rPar.Get(3)->GetInteger(); + if ((nHour < 0 || nHour > 23) || + (nMinute < 0 || nMinute > 59 ) || + (nSecond < 0 || nSecond > 59 )) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + sal_Int32 nSeconds = nHour; + nSeconds *= 3600; + nSeconds += nMinute * 60; + nSeconds += nSecond; + double nDays = ((double)nSeconds) / (double)(86400.0); + rPar.Get(0)->PutDate( nDays ); // JSM +} + +RTLFUNC(DateValue) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden + SvNumberFormatter* pFormatter = NULL; + if( pINST ) + pFormatter = pINST->GetNumberFormatter(); + else + { + sal_uInt32 n; // Dummy + SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n ); + } + + sal_uInt32 nIndex; + double fResult; + String aStr( rPar.Get(1)->GetString() ); + sal_Bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult ); + short nType = pFormatter->GetType( nIndex ); + + // DateValue("February 12, 1969") raises error if the system locale is not en_US + // by using SbiInstance::GetNumberFormatter. + // It seems that both locale number formatter and English number formatter + // are supported in Visual Basic. + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + if( !bSuccess && ( eLangType != LANGUAGE_ENGLISH_US ) ) + { + // Create a new SvNumberFormatter by using LANGUAGE_ENGLISH to get the date value; + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > + xFactory = comphelper::getProcessServiceFactory(); + SvNumberFormatter aFormatter( xFactory, LANGUAGE_ENGLISH_US ); + bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, fResult ); + nType = aFormatter.GetType( nIndex ); + } + + if(bSuccess && (nType==NUMBERFORMAT_DATE || nType==NUMBERFORMAT_DATETIME)) + { + if ( nType == NUMBERFORMAT_DATETIME ) + { + // Zeit abschneiden + if ( fResult > 0.0 ) + fResult = floor( fResult ); + else + fResult = ceil( fResult ); + } + // fResult += 2.0; // Anpassung StarCalcFormatter + rPar.Get(0)->PutDate( fResult ); // JSM + } + else + StarBASIC::Error( SbERR_CONVERSION ); + + // #39629 pFormatter kann selbst angefordert sein + if( !pINST ) + delete pFormatter; + } +} + +RTLFUNC(TimeValue) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden + SvNumberFormatter* pFormatter = NULL; + if( pINST ) + pFormatter = pINST->GetNumberFormatter(); + else + { + sal_uInt32 n; // Dummy + SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n ); + } + + sal_uInt32 nIndex; + double fResult; + sal_Bool bSuccess = pFormatter->IsNumberFormat( rPar.Get(1)->GetString(), + nIndex, fResult ); + short nType = pFormatter->GetType(nIndex); + if(bSuccess && (nType==NUMBERFORMAT_TIME||nType==NUMBERFORMAT_DATETIME)) + { + if ( nType == NUMBERFORMAT_DATETIME ) + // Tage abschneiden + fResult = fmod( fResult, 1 ); + rPar.Get(0)->PutDate( fResult ); // JSM + } + else + StarBASIC::Error( SbERR_CONVERSION ); + + // #39629 pFormatter kann selbst angefordert sein + if( !pINST ) + delete pFormatter; + } +} + +RTLFUNC(Day) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + double aDate = pArg->GetDate(); + + sal_Int16 nDay = implGetDateDay( aDate ); + rPar.Get(0)->PutInteger( nDay ); + } +} + +RTLFUNC(Year) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_Int16 nYear = implGetDateYear( rPar.Get(1)->GetDate() ); + rPar.Get(0)->PutInteger( nYear ); + } +} + +sal_Int16 implGetHour( double dDate ) +{ + if( dDate < 0.0 ) + dDate *= -1.0; + double nFrac = dDate - floor( dDate ); + nFrac *= 86400.0; + sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5); + sal_Int16 nHour = (sal_Int16)(nSeconds / 3600); + return nHour; +} + +RTLFUNC(Hour) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double nArg = rPar.Get(1)->GetDate(); + sal_Int16 nHour = implGetHour( nArg ); + rPar.Get(0)->PutInteger( nHour ); + } +} + +sal_Int16 implGetMinute( double dDate ) +{ + if( dDate < 0.0 ) + dDate *= -1.0; + double nFrac = dDate - floor( dDate ); + nFrac *= 86400.0; + sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5); + sal_Int16 nTemp = (sal_Int16)(nSeconds % 3600); + sal_Int16 nMin = nTemp / 60; + return nMin; +} + +RTLFUNC(Minute) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double nArg = rPar.Get(1)->GetDate(); + sal_Int16 nMin = implGetMinute( nArg ); + rPar.Get(0)->PutInteger( nMin ); + } +} + +RTLFUNC(Month) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_Int16 nMonth = implGetDateMonth( rPar.Get(1)->GetDate() ); + rPar.Get(0)->PutInteger( nMonth ); + } +} + +sal_Int16 implGetSecond( double dDate ) +{ + if( dDate < 0.0 ) + dDate *= -1.0; + double nFrac = dDate - floor( dDate ); + nFrac *= 86400.0; + sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5); + sal_Int16 nTemp = (sal_Int16)(nSeconds / 3600); + nSeconds -= nTemp * 3600; + nTemp = (sal_Int16)(nSeconds / 60); + nSeconds -= nTemp * 60; + + sal_Int16 nRet = (sal_Int16)nSeconds; + return nRet; +} + +RTLFUNC(Second) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double nArg = rPar.Get(1)->GetDate(); + sal_Int16 nSecond = implGetSecond( nArg ); + rPar.Get(0)->PutInteger( nSecond ); + } +} + +double Now_Impl() +{ + Date aDate; + Time aTime; + double aSerial = (double)GetDayDiff( aDate ); + long nSeconds = aTime.GetHour(); + nSeconds *= 3600; + nSeconds += aTime.GetMin() * 60; + nSeconds += aTime.GetSec(); + double nDays = ((double)nSeconds) / (double)(24.0*3600.0); + aSerial += nDays; + return aSerial; +} + +// Date Now(void) + +RTLFUNC(Now) +{ + (void)pBasic; + (void)bWrite; + rPar.Get(0)->PutDate( Now_Impl() ); +} + +// Date Time(void) + +RTLFUNC(Time) +{ + (void)pBasic; + + if ( !bWrite ) + { + Time aTime; + SbxVariable* pMeth = rPar.Get( 0 ); + String aRes; + if( pMeth->IsFixed() ) + { + // Time$: hh:mm:ss + char buf[ 20 ]; + snprintf( buf, sizeof(buf), "%02d:%02d:%02d", + aTime.GetHour(), aTime.GetMin(), aTime.GetSec() ); + aRes = String::CreateFromAscii( buf ); + } + else + { + // Time: system dependent + long nSeconds=aTime.GetHour(); + nSeconds *= 3600; + nSeconds += aTime.GetMin() * 60; + nSeconds += aTime.GetSec(); + double nDays = (double)nSeconds * ( 1.0 / (24.0*3600.0) ); + Color* pCol; + + // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden + SvNumberFormatter* pFormatter = NULL; + sal_uInt32 nIndex; + if( pINST ) + { + pFormatter = pINST->GetNumberFormatter(); + nIndex = pINST->GetStdTimeIdx(); + } + else + { + sal_uInt32 n; // Dummy + SbiInstance::PrepareNumberFormatter( pFormatter, n, nIndex, n ); + } + + pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol ); + + // #39629 pFormatter kann selbst angefordert sein + if( !pINST ) + delete pFormatter; + } + pMeth->PutString( aRes ); + } + else + { + StarBASIC::Error( SbERR_NOT_IMPLEMENTED ); + } +} + +RTLFUNC(Timer) +{ + (void)pBasic; + (void)bWrite; + + Time aTime; + long nSeconds = aTime.GetHour(); + nSeconds *= 3600; + nSeconds += aTime.GetMin() * 60; + nSeconds += aTime.GetSec(); + rPar.Get(0)->PutDate( (double)nSeconds ); +} + + +RTLFUNC(Date) +{ + (void)pBasic; + (void)bWrite; + + if ( !bWrite ) + { + Date aToday; + double nDays = (double)GetDayDiff( aToday ); + SbxVariable* pMeth = rPar.Get( 0 ); + if( pMeth->IsString() ) + { + String aRes; + Color* pCol; + + // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden + SvNumberFormatter* pFormatter = NULL; + sal_uInt32 nIndex; + if( pINST ) + { + pFormatter = pINST->GetNumberFormatter(); + nIndex = pINST->GetStdDateIdx(); + } + else + { + sal_uInt32 n; // Dummy + SbiInstance::PrepareNumberFormatter( pFormatter, nIndex, n, n ); + } + + pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol ); + pMeth->PutString( aRes ); + + // #39629 pFormatter kann selbst angefordert sein + if( !pINST ) + delete pFormatter; + } + else + pMeth->PutDate( nDays ); + } + else + { + StarBASIC::Error( SbERR_NOT_IMPLEMENTED ); + } +} + +RTLFUNC(IsArray) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + rPar.Get(0)->PutBool((rPar.Get(1)->GetType() & SbxARRAY) ? sal_True : sal_False ); +} + +RTLFUNC(IsObject) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariable* pVar = rPar.Get(1); + SbxBase* pObj = (SbxBase*)pVar->GetObject(); + + // #100385: GetObject can result in an error, so reset it + SbxBase::ResetError(); + + SbUnoClass* pUnoClass; + sal_Bool bObject; + if( pObj && NULL != ( pUnoClass=PTR_CAST(SbUnoClass,pObj) ) ) + { + bObject = pUnoClass->getUnoClass().is(); + } + else + { + bObject = pVar->IsObject(); + } + rPar.Get( 0 )->PutBool( bObject ); + } +} + +RTLFUNC(IsDate) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // #46134 Nur String wird konvertiert, andere Typen ergeben sal_False + SbxVariableRef xArg = rPar.Get( 1 ); + SbxDataType eType = xArg->GetType(); + sal_Bool bDate = sal_False; + + if( eType == SbxDATE ) + { + bDate = sal_True; + } + else if( eType == SbxSTRING ) + { + // Error loeschen + SbxError nPrevError = SbxBase::GetError(); + SbxBase::ResetError(); + + // Konvertierung des Parameters nach SbxDATE erzwingen + xArg->SbxValue::GetDate(); + + // Bei Fehler ist es kein Date + bDate = !SbxBase::IsError(); + + // Error-Situation wiederherstellen + SbxBase::ResetError(); + SbxBase::SetError( nPrevError ); + } + rPar.Get( 0 )->PutBool( bDate ); + } +} + +RTLFUNC(IsEmpty) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + rPar.Get( 0 )->PutBool( rPar.Get(1)->IsEmpty() ); +} + +RTLFUNC(IsError) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() ); +} + +RTLFUNC(IsNull) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // #51475 Wegen Uno-Objekten auch true liefern, + // wenn der pObj-Wert NULL ist + SbxVariableRef pArg = rPar.Get( 1 ); + sal_Bool bNull = rPar.Get(1)->IsNull(); + if( !bNull && pArg->GetType() == SbxOBJECT ) + { + SbxBase* pObj = pArg->GetObject(); + if( !pObj ) + bNull = sal_True; + } + rPar.Get( 0 )->PutBool( bNull ); + } +} + +RTLFUNC(IsNumeric) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + rPar.Get( 0 )->PutBool( rPar.Get( 1 )->IsNumericRTL() ); +} + +// Das machen wir auf die billige Tour + +RTLFUNC(IsMissing) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + // #57915 Missing wird durch Error angezeigt + rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() ); +} + +// Dir( [Maske] [,Attrs] ) +// ToDo: Library-globaler Datenbereich fuer Dir-Objekt und Flags + + +String getDirectoryPath( String aPathStr ) +{ + String aRetStr; + + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( aPathStr, aItem ); + if( nRet == FileBase::E_None ) + { + FileStatus aFileStatus( FileStatusMask_Type ); + nRet = aItem.getFileStatus( aFileStatus ); + if( nRet == FileBase::E_None ) + { + FileStatus::Type aType = aFileStatus.getFileType(); + if( isFolder( aType ) ) + { + aRetStr = aPathStr; + } + else if( aType == FileStatus::Link ) + { + FileStatus aFileStatus2( FileStatusMask_LinkTargetURL ); + nRet = aItem.getFileStatus( aFileStatus2 ); + if( nRet == FileBase::E_None ) + aRetStr = getDirectoryPath( aFileStatus2.getLinkTargetURL() ); + } + } + } + return aRetStr; +} + +// Function looks for wildcards, removes them and always returns the pure path +String implSetupWildcard( const String& rFileParam, SbiRTLData* pRTLData ) +{ + static String aAsterisk = String::CreateFromAscii( "*" ); + static sal_Char cDelim1 = (sal_Char)'/'; + static sal_Char cDelim2 = (sal_Char)'\\'; + static sal_Char cWild1 = '*'; + static sal_Char cWild2 = '?'; + + delete pRTLData->pWildCard; + pRTLData->pWildCard = NULL; + pRTLData->sFullNameToBeChecked = String(); + + String aFileParam = rFileParam; + xub_StrLen nLastWild = aFileParam.SearchBackward( cWild1 ); + if( nLastWild == STRING_NOTFOUND ) + nLastWild = aFileParam.SearchBackward( cWild2 ); + sal_Bool bHasWildcards = ( nLastWild != STRING_NOTFOUND ); + + + xub_StrLen nLastDelim = aFileParam.SearchBackward( cDelim1 ); + if( nLastDelim == STRING_NOTFOUND ) + nLastDelim = aFileParam.SearchBackward( cDelim2 ); + + if( bHasWildcards ) + { + // Wildcards in path? + if( nLastDelim != STRING_NOTFOUND && nLastDelim > nLastWild ) + return aFileParam; + } + else + { + String aPathStr = getFullPath( aFileParam ); + if( nLastDelim != aFileParam.Len() - 1 ) + pRTLData->sFullNameToBeChecked = aPathStr; + return aPathStr; + } + + String aPureFileName; + if( nLastDelim == STRING_NOTFOUND ) + { + aPureFileName = aFileParam; + aFileParam = String(); + } + else + { + aPureFileName = aFileParam.Copy( nLastDelim + 1 ); + aFileParam = aFileParam.Copy( 0, nLastDelim ); + } + + // Try again to get a valid URL/UNC-path with only the path + String aPathStr = getFullPath( aFileParam ); + xub_StrLen nPureLen = aPureFileName.Len(); + + // Is there a pure file name left? Otherwise the path is + // invalid anyway because it was not accepted by OSL before + if( nPureLen && aPureFileName != aAsterisk ) + { + pRTLData->pWildCard = new WildCard( aPureFileName ); + } + return aPathStr; +} + +inline sal_Bool implCheckWildcard( const String& rName, SbiRTLData* pRTLData ) +{ + sal_Bool bMatch = sal_True; + + if( pRTLData->pWildCard ) + bMatch = pRTLData->pWildCard->Matches( rName ); + return bMatch; +} + + +bool isRootDir( String aDirURLStr ) +{ + INetURLObject aDirURLObj( aDirURLStr ); + sal_Bool bRoot = sal_False; + + // Check if it's a root directory + sal_Int32 nCount = aDirURLObj.getSegmentCount(); + + // No segment means Unix root directory "file:///" + if( nCount == 0 ) + { + bRoot = sal_True; + } + // Exactly one segment needs further checking, because it + // can be Unix "file:///foo/" -> no root + // or Windows "file:///c:/" -> root + else if( nCount == 1 ) + { + ::rtl::OUString aSeg1 = aDirURLObj.getName( 0, sal_True, + INetURLObject::DECODE_WITH_CHARSET ); + if( aSeg1.getStr()[1] == (sal_Unicode)':' ) + { + bRoot = sal_True; + } + } + // More than one segments can never be root + // so bRoot remains sal_False + + return bRoot; +} + +RTLFUNC(Dir) +{ + (void)pBasic; + (void)bWrite; + + String aPath; + + sal_uInt16 nParCount = rPar.Count(); + if( nParCount > 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbiRTLData* pRTLData = pINST->GetRTLData(); + + // #34645: Kann auch von der URL-Zeile ueber 'macro: Dir' aufgerufen werden + // dann existiert kein pRTLData und die Methode muss verlassen werden + if( !pRTLData ) + return; + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + if ( nParCount >= 2 ) + { + String aFileParam = rPar.Get(1)->GetString(); + + String aFileURLStr = implSetupWildcard( aFileParam, pRTLData ); + if( pRTLData->sFullNameToBeChecked.Len() > 0 ) + { + sal_Bool bExists = sal_False; + try { bExists = xSFI->exists( aFileURLStr ); } + catch( Exception & ) {} + + String aNameOnlyStr; + if( bExists ) + { + INetURLObject aFileURL( aFileURLStr ); + aNameOnlyStr = aFileURL.getName( INetURLObject::LAST_SEGMENT, + true, INetURLObject::DECODE_WITH_CHARSET ); + } + rPar.Get(0)->PutString( aNameOnlyStr ); + return; + } + + try + { + String aDirURLStr; + sal_Bool bFolder = xSFI->isFolder( aFileURLStr ); + + if( bFolder ) + { + aDirURLStr = aFileURLStr; + } + else + { + String aEmptyStr; + rPar.Get(0)->PutString( aEmptyStr ); + } + + sal_uInt16 nFlags = 0; + if ( nParCount > 2 ) + pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger(); + else + pRTLData->nDirFlags = 0; + + // Read directory + sal_Bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0); + pRTLData->aDirSeq = xSFI->getFolderContents( aDirURLStr, bIncludeFolders ); + pRTLData->nCurDirPos = 0; + + // #78651 Add "." and ".." directories for VB compatibility + if( bIncludeFolders ) + { + sal_Bool bRoot = isRootDir( aDirURLStr ); + + // If it's no root directory we flag the need for + // the "." and ".." directories by the value -2 + // for the actual position. Later for -2 will be + // returned "." and for -1 ".." + if( !bRoot ) + { + pRTLData->nCurDirPos = -2; + } + } + } + catch( Exception & ) + { + //StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + + + if( pRTLData->aDirSeq.getLength() > 0 ) + { + sal_Bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0); + + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + for( ;; ) + { + if( pRTLData->nCurDirPos < 0 ) + { + if( pRTLData->nCurDirPos == -2 ) + { + aPath = ::rtl::OUString::createFromAscii( "." ); + } + else if( pRTLData->nCurDirPos == -1 ) + { + aPath = ::rtl::OUString::createFromAscii( ".." ); + } + pRTLData->nCurDirPos++; + } + else if( pRTLData->nCurDirPos >= pRTLData->aDirSeq.getLength() ) + { + pRTLData->aDirSeq.realloc( 0 ); + aPath.Erase(); + break; + } + else + { + ::rtl::OUString aFile = pRTLData->aDirSeq.getConstArray()[pRTLData->nCurDirPos++]; + + if( bCompatibility ) + { + if( !bFolderFlag ) + { + sal_Bool bFolder = xSFI->isFolder( aFile ); + if( bFolder ) + continue; + } + } + else + { + // Only directories + if( bFolderFlag ) + { + sal_Bool bFolder = xSFI->isFolder( aFile ); + if( !bFolder ) + continue; + } + } + + INetURLObject aURL( aFile ); + aPath = aURL.getName( INetURLObject::LAST_SEGMENT, sal_True, + INetURLObject::DECODE_WITH_CHARSET ); + } + + sal_Bool bMatch = implCheckWildcard( aPath, pRTLData ); + if( !bMatch ) + continue; + + break; + } + } + rPar.Get(0)->PutString( aPath ); + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + if ( nParCount >= 2 ) + { + delete pRTLData->pDir; + pRTLData->pDir = 0; // wg. Sonderbehandlung Sb_ATTR_VOLUME + DirEntry aEntry( rPar.Get(1)->GetString() ); + FileStat aStat( aEntry ); + if(!aStat.GetError() && (aStat.GetKind() & FSYS_KIND_FILE)) + { + // ah ja, ist nur ein dateiname + // Pfad abschneiden (wg. VB4) + rPar.Get(0)->PutString( aEntry.GetName() ); + return; + } + sal_uInt16 nFlags = 0; + if ( nParCount > 2 ) + pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger(); + else + pRTLData->nDirFlags = 0; + + // Sb_ATTR_VOLUME wird getrennt gehandelt + if( pRTLData->nDirFlags & Sb_ATTR_VOLUME ) + aPath = aEntry.GetVolume(); + else + { + // Die richtige Auswahl treffen + sal_uInt16 nMode = FSYS_KIND_FILE; + if( nFlags & Sb_ATTR_DIRECTORY ) + nMode |= FSYS_KIND_DIR; + if( nFlags == Sb_ATTR_DIRECTORY ) + nMode = FSYS_KIND_DIR; + pRTLData->pDir = new Dir( aEntry, (DirEntryKind) nMode ); + pRTLData->nCurDirPos = 0; + } + } + + if( pRTLData->pDir ) + { + for( ;; ) + { + if( pRTLData->nCurDirPos >= pRTLData->pDir->Count() ) + { + delete pRTLData->pDir; + pRTLData->pDir = 0; + aPath.Erase(); + break; + } + DirEntry aNextEntry=(*(pRTLData->pDir))[pRTLData->nCurDirPos++]; + aPath = aNextEntry.GetName(); //Full(); + break; + } + } + rPar.Get(0)->PutString( aPath ); +#else + // TODO: OSL + if ( nParCount >= 2 ) + { + String aFileParam = rPar.Get(1)->GetString(); + + String aDirURL = implSetupWildcard( aFileParam, pRTLData ); + + sal_uInt16 nFlags = 0; + if ( nParCount > 2 ) + pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger(); + else + pRTLData->nDirFlags = 0; + + // Read directory + sal_Bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0); + pRTLData->pDir = new Directory( aDirURL ); + FileBase::RC nRet = pRTLData->pDir->open(); + if( nRet != FileBase::E_None ) + { + delete pRTLData->pDir; + pRTLData->pDir = NULL; + rPar.Get(0)->PutString( String() ); + return; + } + + // #86950 Add "." and ".." directories for VB compatibility + pRTLData->nCurDirPos = 0; + if( bIncludeFolders ) + { + sal_Bool bRoot = isRootDir( aDirURL ); + + // If it's no root directory we flag the need for + // the "." and ".." directories by the value -2 + // for the actual position. Later for -2 will be + // returned "." and for -1 ".." + if( !bRoot ) + { + pRTLData->nCurDirPos = -2; + } + } + + } + + if( pRTLData->pDir ) + { + sal_Bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0); + for( ;; ) + { + if( pRTLData->nCurDirPos < 0 ) + { + if( pRTLData->nCurDirPos == -2 ) + { + aPath = ::rtl::OUString::createFromAscii( "." ); + } + else if( pRTLData->nCurDirPos == -1 ) + { + aPath = ::rtl::OUString::createFromAscii( ".." ); + } + pRTLData->nCurDirPos++; + } + else + { + DirectoryItem aItem; + FileBase::RC nRet = pRTLData->pDir->getNextItem( aItem ); + if( nRet != FileBase::E_None ) + { + delete pRTLData->pDir; + pRTLData->pDir = NULL; + aPath.Erase(); + break; + } + + // Handle flags + FileStatus aFileStatus( FileStatusMask_Type | FileStatusMask_FileName ); + nRet = aItem.getFileStatus( aFileStatus ); + + // Only directories? + if( bFolderFlag ) + { + FileStatus::Type aType = aFileStatus.getFileType(); + sal_Bool bFolder = isFolder( aType ); + if( !bFolder ) + continue; + } + + aPath = aFileStatus.getFileName(); + } + + sal_Bool bMatch = implCheckWildcard( aPath, pRTLData ); + if( !bMatch ) + continue; + + break; + } + } + rPar.Get(0)->PutString( aPath ); +#endif + } + } +} + + +RTLFUNC(GetAttr) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + sal_Int16 nFlags = 0; + + // In Windows, We want to use Windows API to get the file attributes + // for VBA interoperability. + #if defined( WNT ) + if( SbiRuntime::isVBAEnabled() ) + { + DirEntry aEntry( rPar.Get(1)->GetString() ); + aEntry.ToAbs(); + + // #57064 Bei virtuellen URLs den Real-Path extrahieren + ByteString aByteStrFullPath( aEntry.GetFull(), gsl_getSystemTextEncoding() ); + DWORD nRealFlags = GetFileAttributes (aByteStrFullPath.GetBuffer()); + if (nRealFlags != 0xffffffff) + { + if (nRealFlags == FILE_ATTRIBUTE_NORMAL) + nRealFlags = 0; + nFlags = (sal_Int16) (nRealFlags); + } + else + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + + rPar.Get(0)->PutInteger( nFlags ); + + return; + } + #endif + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + String aPath = getFullPath( rPar.Get(1)->GetString() ); + sal_Bool bExists = sal_False; + try { bExists = xSFI->exists( aPath ); } + catch( Exception & ) {} + if( !bExists ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + return; + } + + sal_Bool bReadOnly = xSFI->isReadOnly( aPath ); + sal_Bool bHidden = xSFI->isHidden( aPath ); + sal_Bool bDirectory = xSFI->isFolder( aPath ); + if( bReadOnly ) + nFlags |= 0x0001; // ATTR_READONLY + if( bHidden ) + nFlags |= 0x0002; // ATTR_HIDDEN + if( bDirectory ) + nFlags |= 0x0010; // ATTR_DIRECTORY + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( rPar.Get(1)->GetString() ), aItem ); + FileStatus aFileStatus( FileStatusMask_Attributes | FileStatusMask_Type ); + nRet = aItem.getFileStatus( aFileStatus ); + sal_uInt64 nAttributes = aFileStatus.getAttributes(); + sal_Bool bReadOnly = (nAttributes & Attribute_ReadOnly) != 0; + + FileStatus::Type aType = aFileStatus.getFileType(); + sal_Bool bDirectory = isFolder( aType ); + if( bReadOnly ) + nFlags |= 0x0001; // ATTR_READONLY + if( bDirectory ) + nFlags |= 0x0010; // ATTR_DIRECTORY + } + rPar.Get(0)->PutInteger( nFlags ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + + +RTLFUNC(FileDateTime) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // <-- UCB + String aPath = rPar.Get(1)->GetString(); + Time aTime; + Date aDate; + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + com::sun::star::util::DateTime aUnoDT = xSFI->getDateTimeModified( aPath ); + aTime = Time( aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, aUnoDT.HundredthSeconds ); + aDate = Date( aUnoDT.Day, aUnoDT.Month, aUnoDT.Year ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aEntry( aPath ); + FileStat aStat( aEntry ); + aTime = Time( aStat.TimeModified() ); + aDate = Date( aStat.DateModified() ); +#else + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( aPath ), aItem ); + FileStatus aFileStatus( FileStatusMask_ModifyTime ); + nRet = aItem.getFileStatus( aFileStatus ); + TimeValue aTimeVal = aFileStatus.getModifyTime(); + oslDateTime aDT; + osl_getDateTimeFromTimeValue( &aTimeVal, &aDT ); + + aTime = Time( aDT.Hours, aDT.Minutes, aDT.Seconds, 10000000*aDT.NanoSeconds ); + aDate = Date( aDT.Day, aDT.Month, aDT.Year ); +#endif + } + + double fSerial = (double)GetDayDiff( aDate ); + long nSeconds = aTime.GetHour(); + nSeconds *= 3600; + nSeconds += aTime.GetMin() * 60; + nSeconds += aTime.GetSec(); + double nDays = ((double)nSeconds) / (double)(24.0*3600.0); + fSerial += nDays; + + Color* pCol; + + // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden + SvNumberFormatter* pFormatter = NULL; + sal_uInt32 nIndex; + if( pINST ) + { + pFormatter = pINST->GetNumberFormatter(); + nIndex = pINST->GetStdDateTimeIdx(); + } + else + { + sal_uInt32 n; // Dummy + SbiInstance::PrepareNumberFormatter( pFormatter, n, n, nIndex ); + } + + String aRes; + pFormatter->GetOutputString( fSerial, nIndex, aRes, &pCol ); + rPar.Get(0)->PutString( aRes ); + + // #39629 pFormatter kann selbst angefordert sein + if( !pINST ) + delete pFormatter; + } +} + + +RTLFUNC(EOF) +{ + (void)pBasic; + (void)bWrite; + + // AB 08/16/2000: No changes for UCB + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + // nChannel--; // macht MD beim Oeffnen auch nicht + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nChannel ); + if ( !pSbStrm ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + sal_Bool bIsEof; + SvStream* pSvStrm = pSbStrm->GetStrm(); + if ( pSbStrm->IsText() ) + { + char cBla; + (*pSvStrm) >> cBla; // koennen wir noch ein Zeichen lesen + bIsEof = pSvStrm->IsEof(); + if ( !bIsEof ) + pSvStrm->SeekRel( -1 ); + } + else + bIsEof = pSvStrm->IsEof(); // fuer binaerdateien! + rPar.Get(0)->PutBool( bIsEof ); + } +} + +RTLFUNC(FileAttr) +{ + (void)pBasic; + (void)bWrite; + + // AB 08/16/2000: No changes for UCB + + // #57064 Obwohl diese Funktion nicht mit DirEntry arbeitet, ist sie von + // der Anpassung an virtuelle URLs nich betroffen, da sie nur auf bereits + // geoeffneten Dateien arbeitet und der Name hier keine Rolle spielt. + + if ( rPar.Count() != 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); +// nChannel--; + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nChannel ); + if ( !pSbStrm ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + sal_Int16 nRet; + if ( rPar.Get(2)->GetInteger() == 1 ) + nRet = (sal_Int16)(pSbStrm->GetMode()); + else + nRet = 0; // System file handle not supported + + rPar.Get(0)->PutInteger( nRet ); + } +} +RTLFUNC(Loc) +{ + (void)pBasic; + (void)bWrite; + + // AB 08/16/2000: No changes for UCB + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nChannel ); + if ( !pSbStrm ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + SvStream* pSvStrm = pSbStrm->GetStrm(); + sal_uIntPtr nPos; + if( pSbStrm->IsRandom()) + { + short nBlockLen = pSbStrm->GetBlockLen(); + nPos = nBlockLen ? (pSvStrm->Tell() / nBlockLen) : 0; + nPos++; // Blockpositionen beginnen bei 1 + } + else if ( pSbStrm->IsText() ) + nPos = pSbStrm->GetLine(); + else if( pSbStrm->IsBinary() ) + nPos = pSvStrm->Tell(); + else if ( pSbStrm->IsSeq() ) + nPos = ( pSvStrm->Tell()+1 ) / 128; + else + nPos = pSvStrm->Tell(); + rPar.Get(0)->PutLong( (sal_Int32)nPos ); + } +} + +RTLFUNC(Lof) +{ + (void)pBasic; + (void)bWrite; + + // AB 08/16/2000: No changes for UCB + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nChannel ); + if ( !pSbStrm ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + SvStream* pSvStrm = pSbStrm->GetStrm(); + sal_uIntPtr nOldPos = pSvStrm->Tell(); + sal_uIntPtr nLen = pSvStrm->Seek( STREAM_SEEK_TO_END ); + pSvStrm->Seek( nOldPos ); + rPar.Get(0)->PutLong( (sal_Int32)nLen ); + } +} + + +RTLFUNC(Seek) +{ + (void)pBasic; + (void)bWrite; + + // AB 08/16/2000: No changes for UCB + int nArgs = (int)rPar.Count(); + if ( nArgs < 2 || nArgs > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); +// nChannel--; + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nChannel ); + if ( !pSbStrm ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + SvStream* pStrm = pSbStrm->GetStrm(); + + if ( nArgs == 2 ) // Seek-Function + { + sal_uIntPtr nPos = pStrm->Tell(); + if( pSbStrm->IsRandom() ) + nPos = nPos / pSbStrm->GetBlockLen(); + nPos++; // Basic zaehlt ab 1 + rPar.Get(0)->PutLong( (sal_Int32)nPos ); + } + else // Seek-Statement + { + sal_Int32 nPos = rPar.Get(2)->GetLong(); + if ( nPos < 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + nPos--; // Basic zaehlt ab 1, SvStreams zaehlen ab 0 + pSbStrm->SetExpandOnWriteTo( 0 ); + if ( pSbStrm->IsRandom() ) + nPos *= pSbStrm->GetBlockLen(); + pStrm->Seek( (sal_uIntPtr)nPos ); + pSbStrm->SetExpandOnWriteTo( nPos ); + } +} + +RTLFUNC(Format) +{ + (void)pBasic; + (void)bWrite; + + sal_uInt16 nArgCount = (sal_uInt16)rPar.Count(); + if ( nArgCount < 2 || nArgCount > 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aResult; + if( nArgCount == 2 ) + rPar.Get(1)->Format( aResult ); + else + { + String aFmt( rPar.Get(2)->GetString() ); + rPar.Get(1)->Format( aResult, &aFmt ); + } + rPar.Get(0)->PutString( aResult ); + } +} + +RTLFUNC(Randomize) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() > 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + sal_Int16 nSeed; + if( rPar.Count() == 2 ) + nSeed = (sal_Int16)rPar.Get(1)->GetInteger(); + else + nSeed = (sal_Int16)rand(); + srand( nSeed ); +} + +RTLFUNC(Rnd) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() > 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double nRand = (double)rand(); + nRand = ( nRand / (double)RAND_MAX ); + rPar.Get(0)->PutDouble( nRand ); + } +} + + +// +// Syntax: Shell("Path",[ Window-Style,[ "Params", [ bSync = sal_False ]]]) +// +// WindowStyles (VBA-kompatibel): +// 2 == Minimized +// 3 == Maximized +// 10 == Full-Screen (Textmodus-Anwendungen OS/2, WIN95, WNT) +// +// !!!HACK der WindowStyle wird im Creator an Application::StartApp +// uebergeben. Format: "xxxx2" +// + + +RTLFUNC(Shell) +{ + (void)pBasic; + (void)bWrite; + + // No shell command for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + sal_uIntPtr nArgCount = rPar.Count(); + if ( nArgCount < 2 || nArgCount > 5 ) + { + rPar.Get(0)->PutLong(0); + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } + else + { + sal_uInt16 nOptions = vos::OProcess::TOption_SearchPath| + vos::OProcess::TOption_Detached; + String aCmdLine = rPar.Get(1)->GetString(); + // Zusaetzliche Parameter anhaengen, es muss eh alles geparsed werden + if( nArgCount >= 4 ) + { + aCmdLine.AppendAscii( " " ); + aCmdLine += rPar.Get(3)->GetString(); + } + else if( !aCmdLine.Len() ) + { + // Spezial-Behandlung (leere Liste) vermeiden + aCmdLine.AppendAscii( " " ); + } + sal_uInt16 nLen = aCmdLine.Len(); + + // #55735 Wenn Parameter dabei sind, muessen die abgetrennt werden + // #72471 Auch die einzelnen Parameter trennen + std::list<String> aTokenList; + String aToken; + sal_uInt16 i = 0; + sal_Unicode c; + while( i < nLen ) + { + // Spaces weg + for ( ;; ++i ) + { + c = aCmdLine.GetBuffer()[ i ]; + if ( c != ' ' && c != '\t' ) + break; + } + + if( c == '\"' || c == '\'' ) + { + sal_uInt16 iFoundPos = aCmdLine.Search( c, i + 1 ); + + // Wenn nichts gefunden wurde, Rest kopieren + if( iFoundPos == STRING_NOTFOUND ) + { + aToken = aCmdLine.Copy( i, STRING_LEN ); + i = nLen; + } + else + { + aToken = aCmdLine.Copy( i + 1, (iFoundPos - i - 1) ); + i = iFoundPos + 1; + } + } + else + { + sal_uInt16 iFoundSpacePos = aCmdLine.Search( ' ', i ); + sal_uInt16 iFoundTabPos = aCmdLine.Search( '\t', i ); + sal_uInt16 iFoundPos = Min( iFoundSpacePos, iFoundTabPos ); + + // Wenn nichts gefunden wurde, Rest kopieren + if( iFoundPos == STRING_NOTFOUND ) + { + aToken = aCmdLine.Copy( i, STRING_LEN ); + i = nLen; + } + else + { + aToken = aCmdLine.Copy( i, (iFoundPos - i) ); + i = iFoundPos; + } + } + + // In die Liste uebernehmen + aTokenList.push_back( aToken ); + } + // #55735 / #72471 Ende + + sal_Int16 nWinStyle = 0; + if( nArgCount >= 3 ) + { + nWinStyle = rPar.Get(2)->GetInteger(); + switch( nWinStyle ) + { + case 2: + nOptions |= vos::OProcess::TOption_Minimized; + break; + case 3: + nOptions |= vos::OProcess::TOption_Maximized; + break; + case 10: + nOptions |= vos::OProcess::TOption_FullScreen; + break; + } + + sal_Bool bSync = sal_False; + if( nArgCount >= 5 ) + bSync = rPar.Get(4)->GetBool(); + if( bSync ) + nOptions |= vos::OProcess::TOption_Wait; + } + vos::OProcess::TProcessOption eOptions = + (vos::OProcess::TProcessOption)nOptions; + + + // #72471 Parameter aufbereiten + std::list<String>::const_iterator iter = aTokenList.begin(); + const String& rStr = *iter; + ::rtl::OUString aOUStrProg( rStr.GetBuffer(), rStr.Len() ); + String aOUStrProgUNC = getFullPathUNC( aOUStrProg ); + + iter++; + + sal_uInt16 nParamCount = sal::static_int_cast< sal_uInt16 >( + aTokenList.size() - 1 ); + ::rtl::OUString* pArgumentList = NULL; + //const char** pParamList = NULL; + if( nParamCount ) + { + pArgumentList = new ::rtl::OUString[ nParamCount ]; + //pParamList = new const char*[ nParamCount ]; + sal_uInt16 iList = 0; + while( iter != aTokenList.end() ) + { + const String& rParamStr = (*iter); + pArgumentList[iList++] = ::rtl::OUString( rParamStr.GetBuffer(), rParamStr.Len() ); + //pParamList[iList++] = (*iter).GetStr(); + iter++; + } + } + + //const char* pParams = aParams.Len() ? aParams.GetStr() : 0; + vos::OProcess* pApp; + pApp = new vos::OProcess( aOUStrProgUNC ); + sal_Bool bSucc; + if( nParamCount == 0 ) + { + bSucc = pApp->execute( eOptions ) == vos::OProcess::E_None; + } + else + { + vos::OArgumentList aArgList( pArgumentList, nParamCount ); + bSucc = pApp->execute( eOptions, aArgList ) == vos::OProcess::E_None; + } + + /* + if( nParamCount == 0 ) + pApp = new vos::OProcess( pProg ); + else + pApp = new vos::OProcess( pProg, pParamList, nParamCount ); + sal_Bool bSucc = pApp->execute( eOptions ) == vos::OProcess::E_None; + */ + + delete pApp; + delete[] pArgumentList; + if( !bSucc ) + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + else + rPar.Get(0)->PutLong( 0 ); + } +} + +RTLFUNC(VarType) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxDataType eType = rPar.Get(1)->GetType(); + rPar.Get(0)->PutInteger( (sal_Int16)eType ); + } +} + +// Exported function +String getBasicTypeName( SbxDataType eType ) +{ + static const char* pTypeNames[] = + { + "Empty", // SbxEMPTY + "Null", // SbxNULL + "Integer", // SbxINTEGER + "Long", // SbxLONG + "Single", // SbxSINGLE + "Double", // SbxDOUBLE + "Currency", // SbxCURRENCY + "Date", // SbxDATE + "String", // SbxSTRING + "Object", // SbxOBJECT + "Error", // SbxERROR + "Boolean", // SbxBOOL + "Variant", // SbxVARIANT + "DataObject", // SbxDATAOBJECT + "Unknown Type", // + "Unknown Type", // + "Char", // SbxCHAR + "Byte", // SbxBYTE + "UShort", // SbxUSHORT + "ULong", // SbxULONG + "Long64", // SbxLONG64 + "ULong64", // SbxULONG64 + "Int", // SbxINT + "UInt", // SbxUINT + "Void", // SbxVOID + "HResult", // SbxHRESULT + "Pointer", // SbxPOINTER + "DimArray", // SbxDIMARRAY + "CArray", // SbxCARRAY + "Userdef", // SbxUSERDEF + "Lpstr", // SbxLPSTR + "Lpwstr", // SbxLPWSTR + "Unknown Type", // SbxCoreSTRING + "WString", // SbxWSTRING + "WChar", // SbxWCHAR + "Int64", // SbxSALINT64 + "UInt64", // SbxSALUINT64 + "Decimal", // SbxDECIMAL + }; + + int nPos = ((int)eType) & 0x0FFF; + sal_uInt16 nTypeNameCount = sizeof( pTypeNames ) / sizeof( char* ); + if ( nPos < 0 || nPos >= nTypeNameCount ) + nPos = nTypeNameCount - 1; + String aRetStr = String::CreateFromAscii( pTypeNames[nPos] ); + return aRetStr; +} + +RTLFUNC(TypeName) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxDataType eType = rPar.Get(1)->GetType(); + sal_Bool bIsArray = ( ( eType & SbxARRAY ) != 0 ); + String aRetStr = getBasicTypeName( eType ); + if( bIsArray ) + aRetStr.AppendAscii( "()" ); + rPar.Get(0)->PutString( aRetStr ); + } +} + +RTLFUNC(Len) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + const String& rStr = rPar.Get(1)->GetString(); + rPar.Get(0)->PutLong( (sal_Int32)rStr.Len() ); + } +} + +RTLFUNC(DDEInitiate) +{ + (void)pBasic; + (void)bWrite; + + // No DDE for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + int nArgs = (int)rPar.Count(); + if ( nArgs != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + const String& rApp = rPar.Get(1)->GetString(); + const String& rTopic = rPar.Get(2)->GetString(); + + SbiDdeControl* pDDE = pINST->GetDdeControl(); + sal_Int16 nChannel; + SbError nDdeErr = pDDE->Initiate( rApp, rTopic, nChannel ); + if( nDdeErr ) + StarBASIC::Error( nDdeErr ); + else + rPar.Get(0)->PutInteger( nChannel ); +} + +RTLFUNC(DDETerminate) +{ + (void)pBasic; + (void)bWrite; + + // No DDE for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + rPar.Get(0)->PutEmpty(); + int nArgs = (int)rPar.Count(); + if ( nArgs != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + SbiDdeControl* pDDE = pINST->GetDdeControl(); + SbError nDdeErr = pDDE->Terminate( nChannel ); + if( nDdeErr ) + StarBASIC::Error( nDdeErr ); +} + +RTLFUNC(DDETerminateAll) +{ + (void)pBasic; + (void)bWrite; + + // No DDE for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + rPar.Get(0)->PutEmpty(); + int nArgs = (int)rPar.Count(); + if ( nArgs != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + SbiDdeControl* pDDE = pINST->GetDdeControl(); + SbError nDdeErr = pDDE->TerminateAll(); + if( nDdeErr ) + StarBASIC::Error( nDdeErr ); + +} + +RTLFUNC(DDERequest) +{ + (void)pBasic; + (void)bWrite; + + // No DDE for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + int nArgs = (int)rPar.Count(); + if ( nArgs != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + const String& rItem = rPar.Get(2)->GetString(); + SbiDdeControl* pDDE = pINST->GetDdeControl(); + String aResult; + SbError nDdeErr = pDDE->Request( nChannel, rItem, aResult ); + if( nDdeErr ) + StarBASIC::Error( nDdeErr ); + else + rPar.Get(0)->PutString( aResult ); +} + +RTLFUNC(DDEExecute) +{ + (void)pBasic; + (void)bWrite; + + // No DDE for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + rPar.Get(0)->PutEmpty(); + int nArgs = (int)rPar.Count(); + if ( nArgs != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + const String& rCommand = rPar.Get(2)->GetString(); + SbiDdeControl* pDDE = pINST->GetDdeControl(); + SbError nDdeErr = pDDE->Execute( nChannel, rCommand ); + if( nDdeErr ) + StarBASIC::Error( nDdeErr ); +} + +RTLFUNC(DDEPoke) +{ + (void)pBasic; + (void)bWrite; + + // No DDE for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + rPar.Get(0)->PutEmpty(); + int nArgs = (int)rPar.Count(); + if ( nArgs != 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int16 nChannel = rPar.Get(1)->GetInteger(); + const String& rItem = rPar.Get(2)->GetString(); + const String& rData = rPar.Get(3)->GetString(); + SbiDdeControl* pDDE = pINST->GetDdeControl(); + SbError nDdeErr = pDDE->Poke( nChannel, rItem, rData ); + if( nDdeErr ) + StarBASIC::Error( nDdeErr ); +} + + +RTLFUNC(FreeFile) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + SbiIoSystem* pIO = pINST->GetIoSystem(); + short nChannel = 1; + while( nChannel < CHANNELS ) + { + SbiStream* pStrm = pIO->GetStream( nChannel ); + if( !pStrm ) + { + rPar.Get(0)->PutInteger( nChannel ); + return; + } + nChannel++; + } + StarBASIC::Error( SbERR_TOO_MANY_FILES ); +} + +RTLFUNC(LBound) +{ + (void)pBasic; + (void)bWrite; + + sal_uInt16 nParCount = rPar.Count(); + if ( nParCount != 3 && nParCount != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + SbxBase* pParObj = rPar.Get(1)->GetObject(); + SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj); + if( pArr ) + { + sal_Int32 nLower, nUpper; + short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1; + if( !pArr->GetDim32( nDim, nLower, nUpper ) ) + StarBASIC::Error( SbERR_OUT_OF_RANGE ); + else + rPar.Get(0)->PutLong( nLower ); + } + else + StarBASIC::Error( SbERR_MUST_HAVE_DIMS ); +} + +RTLFUNC(UBound) +{ + (void)pBasic; + (void)bWrite; + + sal_uInt16 nParCount = rPar.Count(); + if ( nParCount != 3 && nParCount != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + SbxBase* pParObj = rPar.Get(1)->GetObject(); + SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj); + if( pArr ) + { + sal_Int32 nLower, nUpper; + short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1; + if( !pArr->GetDim32( nDim, nLower, nUpper ) ) + StarBASIC::Error( SbERR_OUT_OF_RANGE ); + else + rPar.Get(0)->PutLong( nUpper ); + } + else + StarBASIC::Error( SbERR_MUST_HAVE_DIMS ); +} + +RTLFUNC(RGB) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + sal_uIntPtr nRed = rPar.Get(1)->GetInteger() & 0xFF; + sal_uIntPtr nGreen = rPar.Get(2)->GetInteger() & 0xFF; + sal_uIntPtr nBlue = rPar.Get(3)->GetInteger() & 0xFF; + sal_uIntPtr nRGB; + + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + nRGB = (nBlue << 16) | (nGreen << 8) | nRed; + } + else + { + nRGB = (nRed << 16) | (nGreen << 8) | nBlue; + } + rPar.Get(0)->PutLong( nRGB ); +} + +RTLFUNC(QBColor) +{ + (void)pBasic; + (void)bWrite; + + static const sal_Int32 pRGB[] = + { + 0x000000, + 0x800000, + 0x008000, + 0x808000, + 0x000080, + 0x800080, + 0x008080, + 0xC0C0C0, + 0x808080, + 0xFF0000, + 0x00FF00, + 0xFFFF00, + 0x0000FF, + 0xFF00FF, + 0x00FFFF, + 0xFFFFFF, + }; + + if ( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + sal_Int16 nCol = rPar.Get(1)->GetInteger(); + if( nCol < 0 || nCol > 15 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + sal_Int32 nRGB = pRGB[ nCol ]; + rPar.Get(0)->PutLong( nRGB ); +} + +// StrConv(string, conversion, LCID) +RTLFUNC(StrConv) +{ + (void)pBasic; + (void)bWrite; + + sal_uIntPtr nArgCount = rPar.Count()-1; + if( nArgCount < 2 || nArgCount > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aOldStr = rPar.Get(1)->GetString(); + sal_Int32 nConversion = rPar.Get(2)->GetLong(); + + sal_uInt16 nLanguage = LANGUAGE_SYSTEM; + if( nArgCount == 3 ) + { + // LCID not supported now + //nLanguage = rPar.Get(3)->GetInteger(); + } + + sal_uInt16 nOldLen = aOldStr.Len(); + if( nOldLen == 0 ) + { + // null string,return + rPar.Get(0)->PutString(aOldStr); + return; + } + + sal_Int32 nType = 0; + if ( (nConversion & 0x03) == 3 ) // vbProperCase + { + CharClass& rCharClass = GetCharClass(); + aOldStr = rCharClass.toTitle( aOldStr.ToLowerAscii(), 0, nOldLen ); + } + else if ( (nConversion & 0x01) == 1 ) // vbUpperCase + nType |= ::com::sun::star::i18n::TransliterationModules_LOWERCASE_UPPERCASE; + else if ( (nConversion & 0x02) == 2 ) // vbLowerCase + nType |= ::com::sun::star::i18n::TransliterationModules_UPPERCASE_LOWERCASE; + + if ( (nConversion & 0x04) == 4 ) // vbWide + nType |= ::com::sun::star::i18n::TransliterationModules_HALFWIDTH_FULLWIDTH; + else if ( (nConversion & 0x08) == 8 ) // vbNarrow + nType |= ::com::sun::star::i18n::TransliterationModules_FULLWIDTH_HALFWIDTH; + + if ( (nConversion & 0x10) == 16) // vbKatakana + nType |= ::com::sun::star::i18n::TransliterationModules_HIRAGANA_KATAKANA; + else if ( (nConversion & 0x20) == 32 ) // vbHiragana + nType |= ::com::sun::star::i18n::TransliterationModules_KATAKANA_HIRAGANA; + + String aNewStr( aOldStr ); + if( nType != 0 ) + { + com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + ::utl::TransliterationWrapper aTransliterationWrapper( xSMgr,nType ); + com::sun::star::uno::Sequence<sal_Int32> aOffsets; + aTransliterationWrapper.loadModuleIfNeeded( nLanguage ); + aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets ); + } + + if ( (nConversion & 0x40) == 64 ) // vbUnicode + { + // convert the string to byte string, preserving unicode (2 bytes per character) + sal_uInt16 nSize = aNewStr.Len()*2; + const sal_Unicode* pSrc = aNewStr.GetBuffer(); + sal_Char* pChar = new sal_Char[nSize+1]; + for( sal_uInt16 i=0; i < nSize; i++ ) + { + pChar[i] = static_cast< sal_Char >( i%2 ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff ); + if( i%2 ) + pSrc++; + } + pChar[nSize] = '\0'; + ::rtl::OString aOStr(pChar); + + // there is no concept about default codepage in unix. so it is incorrectly in unix + ::rtl::OUString aOUStr = ::rtl::OStringToOUString(aOStr, osl_getThreadTextEncoding()); + aNewStr = String(aOUStr); + rPar.Get(0)->PutString( aNewStr ); + return; + } + else if ( (nConversion & 0x80) == 128 ) // vbFromUnicode + { + ::rtl::OUString aOUStr(aNewStr); + // there is no concept about default codepage in unix. so it is incorrectly in unix + ::rtl::OString aOStr = ::rtl::OUStringToOString(aNewStr,osl_getThreadTextEncoding()); + const sal_Char* pChar = aOStr.getStr(); + sal_uInt16 nArraySize = static_cast< sal_uInt16 >( aOStr.getLength() ); + SbxDimArray* pArray = new SbxDimArray(SbxBYTE); + bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() ); + if(nArraySize) + { + if( bIncIndex ) + pArray->AddDim( 1, nArraySize ); + else + pArray->AddDim( 0, nArraySize-1 ); + } + else + { + pArray->unoAddDim( 0, -1 ); + } + + for( sal_uInt16 i=0; i< nArraySize; i++) + { + SbxVariable* pNew = new SbxVariable( SbxBYTE ); + pNew->PutByte(*pChar); + pChar++; + pNew->SetFlag( SBX_WRITE ); + short index = i; + if( bIncIndex ) + ++index; + pArray->Put( pNew, &index ); + } + + SbxVariableRef refVar = rPar.Get(0); + sal_uInt16 nFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->PutObject( pArray ); + refVar->SetFlags( nFlags ); + refVar->SetParameters( NULL ); + return; + } + + rPar.Get(0)->PutString(aNewStr); +} + + +RTLFUNC(Beep) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + Sound::Beep(); +} + +RTLFUNC(Load) +{ + (void)pBasic; + (void)bWrite; + + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // Diesen Call einfach an das Object weiterreichen + SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject(); + if ( pObj ) + { + if( pObj->IsA( TYPE( SbUserFormModule ) ) ) + { + ((SbUserFormModule*)pObj)->Load(); + } + else if( pObj->IsA( TYPE( SbxObject ) ) ) + { + SbxVariable* pVar = ((SbxObject*)pObj)-> + Find( String( RTL_CONSTASCII_USTRINGPARAM("Load") ), SbxCLASS_METHOD ); + if( pVar ) + pVar->GetInteger(); + } + } +} + +RTLFUNC(Unload) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // Diesen Call einfach an das Object weitereichen + SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject(); + if ( pObj ) + { + if( pObj->IsA( TYPE( SbUserFormModule ) ) ) + { + SbUserFormModule* pFormModule = ( SbUserFormModule* )pObj; + pFormModule->Unload(); + } + else if( pObj->IsA( TYPE( SbxObject ) ) ) + { + SbxVariable* pVar = ((SbxObject*)pObj)-> + Find( String( RTL_CONSTASCII_USTRINGPARAM("Unload") ), SbxCLASS_METHOD ); + if( pVar ) + pVar->GetInteger(); + } + } +} + +RTLFUNC(LoadPicture) +{ + (void)pBasic; + (void)bWrite; + + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aFileURL = getFullPath( rPar.Get(1)->GetString() ); + SvStream* pStream = utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_READ ); + if( pStream != NULL ) + { + Bitmap aBmp; + *pStream >> aBmp; + Graphic aGraphic( aBmp ); + + SbxObjectRef xRef = new SbStdPicture; + ((SbStdPicture*)(SbxObject*)xRef)->SetGraphic( aGraphic ); + rPar.Get(0)->PutObject( xRef ); + } + delete pStream; +} + +RTLFUNC(SavePicture) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if( rPar.Count() != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject(); + if( pObj->IsA( TYPE( SbStdPicture ) ) ) + { + SvFileStream aOStream( rPar.Get(2)->GetString(), STREAM_WRITE | STREAM_TRUNC ); + Graphic aGraphic = ((SbStdPicture*)pObj)->GetGraphic(); + aOStream << aGraphic; + } +} + + +//----------------------------------------------------------------------------------------- + +RTLFUNC(AboutStarBasic) +{ + (void)pBasic; + (void)bWrite; + (void)rPar; +} + +RTLFUNC(MsgBox) +{ + (void)pBasic; + (void)bWrite; + + static const WinBits nStyleMap[] = + { + WB_OK, // MB_OK + WB_OK_CANCEL, // MB_OKCANCEL + WB_ABORT_RETRY_IGNORE, // MB_ABORTRETRYIGNORE + WB_YES_NO_CANCEL, // MB_YESNOCANCEL + WB_YES_NO, // MB_YESNO + WB_RETRY_CANCEL // MB_RETRYCANCEL + }; + static const sal_Int16 nButtonMap[] = + { + 2, // #define RET_CANCEL sal_False + 1, // #define RET_OK sal_True + 6, // #define RET_YES 2 + 7, // #define RET_NO 3 + 4 // #define RET_RETRY 4 + }; + + + sal_uInt16 nArgCount = (sal_uInt16)rPar.Count(); + if( nArgCount < 2 || nArgCount > 6 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + WinBits nWinBits; + WinBits nType = 0; // MB_OK + if( nArgCount >= 3 ) + nType = (WinBits)rPar.Get(2)->GetInteger(); + WinBits nStyle = nType; + nStyle &= 15; // Bits 4-16 loeschen + if( nStyle > 5 ) + nStyle = 0; + + nWinBits = nStyleMap[ nStyle ]; + + WinBits nWinDefBits; + nWinDefBits = (WB_DEF_OK | WB_DEF_RETRY | WB_DEF_YES); + if( nType & 256 ) + { + if( nStyle == 5 ) + nWinDefBits = WB_DEF_CANCEL; + else if( nStyle == 2 ) + nWinDefBits = WB_DEF_RETRY; + else + nWinDefBits = (WB_DEF_CANCEL | WB_DEF_RETRY | WB_DEF_NO); + } + else if( nType & 512 ) + { + if( nStyle == 2) + nWinDefBits = WB_DEF_IGNORE; + else + nWinDefBits = WB_DEF_CANCEL; + } + else if( nStyle == 2) + nWinDefBits = WB_DEF_CANCEL; + nWinBits |= nWinDefBits; + + String aMsg = rPar.Get(1)->GetString(); + String aTitle; + if( nArgCount >= 4 ) + aTitle = rPar.Get(3)->GetString(); + else + aTitle = GetpApp()->GetAppName(); + + nType &= (16+32+64); + MessBox* pBox = 0; + Window* pParent = GetpApp()->GetDefDialogParent(); + switch( nType ) + { + case 16: + pBox = new ErrorBox( pParent, nWinBits, aMsg ); + break; + case 32: + pBox = new QueryBox( pParent, nWinBits, aMsg ); + break; + case 48: + pBox = new WarningBox( pParent, nWinBits, aMsg ); + break; + case 64: + pBox = new InfoBox( pParent, aMsg ); + break; + default: + pBox = new MessBox( pParent, nWinBits, aTitle, aMsg ); + } + pBox->SetText( aTitle ); + sal_uInt16 nRet = (sal_uInt16)pBox->Execute(); + if( nRet == sal_True ) + nRet = 1; + + sal_Int16 nMappedRet; + if( nStyle == 2 ) + { + nMappedRet = nRet; + if( nMappedRet == 0 ) + nMappedRet = 3; // Abort + } + else + nMappedRet = nButtonMap[ nRet ]; + + rPar.Get(0)->PutInteger( nMappedRet ); + delete pBox; +} + +RTLFUNC(SetAttr) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if ( rPar.Count() == 3 ) + { + String aStr = rPar.Get(1)->GetString(); + sal_Int16 nFlags = rPar.Get(2)->GetInteger(); + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + sal_Bool bReadOnly = (nFlags & 0x0001) != 0; // ATTR_READONLY + xSFI->setReadOnly( aStr, bReadOnly ); + sal_Bool bHidden = (nFlags & 0x0002) != 0; // ATTR_HIDDEN + xSFI->setHidden( aStr, bHidden ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + // #57064 Bei virtuellen URLs den Real-Path extrahieren + DirEntry aEntry( aStr ); + String aFile = aEntry.GetFull(); + ByteString aByteFile( aFile, gsl_getSystemTextEncoding() ); + #ifdef WNT + if (!SetFileAttributes (aByteFile.GetBuffer(),(DWORD)nFlags)) + StarBASIC::Error(SbERR_FILE_NOT_FOUND); + #endif + #ifdef OS2 + FILESTATUS3 aFileStatus; + APIRET rc = DosQueryPathInfo(aByteFile.GetBuffer(),1, + &aFileStatus,sizeof(FILESTATUS3)); + if (!rc) + { + if (aFileStatus.attrFile != nFlags) + { + aFileStatus.attrFile = nFlags; + rc = DosSetPathInfo(aFile.GetStr(),1, + &aFileStatus,sizeof(FILESTATUS3),0); + if (rc) + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + } + } + else + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + #endif +#else + // Not implemented +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(Reset) // JSM +{ + (void)pBasic; + (void)bWrite; + (void)rPar; + + SbiIoSystem* pIO = pINST->GetIoSystem(); + if (pIO) + pIO->CloseAll(); +} + +RTLFUNC(DumpAllObjects) +{ + (void)pBasic; + (void)bWrite; + + sal_uInt16 nArgCount = (sal_uInt16)rPar.Count(); + if( nArgCount < 2 || nArgCount > 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else if( !pBasic ) + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + else + { + SbxObject* p = pBasic; + while( p->GetParent() ) + p = p->GetParent(); + SvFileStream aStrm( rPar.Get( 1 )->GetString(), + STREAM_WRITE | STREAM_TRUNC ); + p->Dump( aStrm, rPar.Get( 2 )->GetBool() ); + aStrm.Close(); + if( aStrm.GetError() != SVSTREAM_OK ) + StarBASIC::Error( SbERR_IO_ERROR ); + } +} + + +RTLFUNC(FileExists) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + String aStr = rPar.Get(1)->GetString(); + sal_Bool bExists = sal_False; + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + bExists = xSFI->exists( aStr ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aEntry( aStr ); + bExists = aEntry.Exists(); +#else + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( aStr ), aItem ); + bExists = (nRet == FileBase::E_None); +#endif + } + rPar.Get(0)->PutBool( bExists ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(Partition) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 5 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + sal_Int32 nNumber = rPar.Get(1)->GetLong(); + sal_Int32 nStart = rPar.Get(2)->GetLong(); + sal_Int32 nStop = rPar.Get(3)->GetLong(); + sal_Int32 nInterval = rPar.Get(4)->GetLong(); + + if( nStart < 0 || nStop <= nStart || nInterval < 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // the Partition function inserts leading spaces before lowervalue and uppervalue + // so that they both have the same number of characters as the string + // representation of the value (Stop + 1). This ensures that if you use the output + // of the Partition function with several values of Number, the resulting text + // will be handled properly during any subsequent sort operation. + + // calculate the maximun number of characters before lowervalue and uppervalue + ::rtl::OUString aBeforeStart = ::rtl::OUString::valueOf( nStart - 1 ); + ::rtl::OUString aAfterStop = ::rtl::OUString::valueOf( nStop + 1 ); + sal_Int32 nLen1 = aBeforeStart.getLength(); + sal_Int32 nLen2 = aAfterStop.getLength(); + sal_Int32 nLen = nLen1 >= nLen2 ? nLen1:nLen2; + + ::rtl::OUStringBuffer aRetStr( nLen * 2 + 1); + ::rtl::OUString aLowerValue; + ::rtl::OUString aUpperValue; + if( nNumber < nStart ) + { + aUpperValue = aBeforeStart; + } + else if( nNumber > nStop ) + { + aLowerValue = aAfterStop; + } + else + { + sal_Int32 nLowerValue = nNumber; + sal_Int32 nUpperValue = nLowerValue; + if( nInterval > 1 ) + { + nLowerValue = ((( nNumber - nStart ) / nInterval ) * nInterval ) + nStart; + nUpperValue = nLowerValue + nInterval - 1; + } + + aLowerValue = ::rtl::OUString::valueOf( nLowerValue ); + aUpperValue = ::rtl::OUString::valueOf( nUpperValue ); + } + + nLen1 = aLowerValue.getLength(); + nLen2 = aUpperValue.getLength(); + + if( nLen > nLen1 ) + { + // appending the leading spaces for the lowervalue + for ( sal_Int32 i= (nLen - nLen1) ; i > 0; --i ) + aRetStr.appendAscii(" "); + } + aRetStr.append( aLowerValue ).appendAscii(":"); + if( nLen > nLen2 ) + { + // appending the leading spaces for the uppervalue + for ( sal_Int32 i= (nLen - nLen2) ; i > 0; --i ) + aRetStr.appendAscii(" "); + } + aRetStr.append( aUpperValue ); + rPar.Get(0)->PutString( String(aRetStr.makeStringAndClear()) ); +} |