/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"

#include <tools/date.hxx>
#include <basic/sbxvar.hxx>
#include <vos/process.hxx>
#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 <vcl/dibtools.hxx>

#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;
using namespace com::sun::star::frame;

#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 <basic/vbahelper.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>

// from source/classes/sbxmod.cxx
Reference< XModel > getDocumentModel( StarBASIC* );

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.isEmpty() )
	{
		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().isEmpty() )
				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 );
		}
	}
}

void implChr( SbxArray& rPar, bool bChrW )
{
	if ( rPar.Count() < 2 )
		StarBASIC::Error( SbERR_BAD_ARGUMENT );
	else
	{
		SbxVariableRef pArg = rPar.Get( 1 );

		String aStr;
		if( !bChrW && SbiRuntime::isVBAEnabled() )
		{
			sal_Char c = (sal_Char)pArg->GetByte();
			ByteString s( c );
			aStr = String( s, gsl_getSystemTextEncoding() );
		}
		else
		{
			sal_Unicode aCh = (sal_Unicode)pArg->GetUShort();
			aStr = String( aCh );
		}
		rPar.Get(0)->PutString( aStr );
	}
}

RTLFUNC(Chr)
{
    (void)pBasic;
    (void)bWrite;

	bool bChrW = false;
	implChr( rPar, bChrW );
}

RTLFUNC(ChrW)
{
    (void)pBasic;
    (void)bWrite;

	bool bChrW = true;
	implChr( rPar, bChrW );
}


#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)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
        // VBA: track current directory per document type (separately for Writer, Calc, Impress, etc.)
        if( SbiRuntime::isVBAEnabled() )
            ::basic::vba::registerCurrentDirectory( getDocumentModel( pBasic ), rPar.Get(1)->GetString() );
	}
	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 + nReplaceStrLen;
					nCounts++;
				}
				else
				{
					break;
				}
			}
		}
		rPar.Get(0)->PutString( aExpStr.Copy() );
	}
}

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;
        ReadDIB(aBmp, *pStream, true);
		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, nWinBits, 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()) );
}