diff options
Diffstat (limited to 'basic/source/runtime')
22 files changed, 17053 insertions, 0 deletions
diff --git a/basic/source/runtime/basrdll.cxx b/basic/source/runtime/basrdll.cxx new file mode 100644 index 000000000000..799caf0cd954 --- /dev/null +++ b/basic/source/runtime/basrdll.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/shl.hxx> +#include <vcl/svapp.hxx> +#include <svl/solar.hrc> +#include <tools/debug.hxx> +#include <vcl/msgbox.hxx> + +#include <basic/sbstar.hxx> +#include <basic/basrdll.hxx> +#include <basrid.hxx> +#include <sb.hrc> + +SttResId::SttResId( sal_uInt32 nId ) : + ResId( nId, *((*(BasicDLL**)GetAppData(SHL_BASIC))->GetSttResMgr()) ) +{ +} + +BasResId::BasResId( sal_uInt32 nId ) : + ResId( nId, *((*(BasicDLL**)GetAppData(SHL_BASIC))->GetBasResMgr()) ) +{ +} + +BasicDLL::BasicDLL() +{ + *(BasicDLL**)GetAppData(SHL_BASIC) = this; + ::com::sun::star::lang::Locale aLocale = Application::GetSettings().GetUILocale(); + pSttResMgr = ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(stt), aLocale ); + pBasResMgr = ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(sb), aLocale ); + bDebugMode = FALSE; + bBreakEnabled = TRUE; +} + +BasicDLL::~BasicDLL() +{ + delete pSttResMgr; + delete pBasResMgr; +} + +void BasicDLL::EnableBreak( BOOL bEnable ) +{ + BasicDLL* pThis = *(BasicDLL**)GetAppData(SHL_BASIC); + DBG_ASSERT( pThis, "BasicDLL::EnableBreak: Noch keine Instanz!" ); + if ( pThis ) + pThis->bBreakEnabled = bEnable; +} + +void BasicDLL::SetDebugMode( BOOL bDebugMode ) +{ + BasicDLL* pThis = *(BasicDLL**)GetAppData(SHL_BASIC); + DBG_ASSERT( pThis, "BasicDLL::EnableBreak: Noch keine Instanz!" ); + if ( pThis ) + pThis->bDebugMode = bDebugMode; +} + + +void BasicDLL::BasicBreak() +{ + //bJustStopping: Wenn jemand wie wild x-mal STOP drueckt, aber das Basic + // nicht schnell genug anhaelt, kommt die Box ggf. oefters... + static BOOL bJustStopping = FALSE; + + BasicDLL* pThis = *(BasicDLL**)GetAppData(SHL_BASIC); + DBG_ASSERT( pThis, "BasicDLL::EnableBreak: Noch keine Instanz!" ); + if ( pThis ) + { + if ( StarBASIC::IsRunning() && !bJustStopping && ( pThis->bBreakEnabled || pThis->bDebugMode ) ) + { + bJustStopping = TRUE; + StarBASIC::Stop(); + String aMessageStr( BasResId( IDS_SBERR_TERMINATED ) ); + InfoBox( 0, aMessageStr ).Execute(); + bJustStopping = FALSE; + } + } +} + diff --git a/basic/source/runtime/comenumwrapper.cxx b/basic/source/runtime/comenumwrapper.cxx new file mode 100644 index 000000000000..ba3def41838f --- /dev/null +++ b/basic/source/runtime/comenumwrapper.cxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_basic.hxx" +#include "comenumwrapper.hxx" + +using namespace ::com::sun::star; + +::sal_Bool SAL_CALL ComEnumerationWrapper::hasMoreElements() + throw ( uno::RuntimeException ) +{ + sal_Bool bResult = sal_False; + + try + { + if ( m_xInvocation.is() ) + { + sal_Int32 nLength = 0; + bResult = + ( ( m_xInvocation->getValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "length" ) ) ) >>= nLength ) + && nLength > m_nCurInd ); + } + } + catch( uno::Exception& ) + {} + + return bResult; +} + +uno::Any SAL_CALL ComEnumerationWrapper::nextElement() + throw ( container::NoSuchElementException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + try + { + if ( m_xInvocation.is() ) + { + uno::Sequence< sal_Int16 > aNamedParamIndex; + uno::Sequence< uno::Any > aNamedParam; + uno::Sequence< uno::Any > aArgs( 1 ); + + aArgs[0] <<= m_nCurInd++; + + return m_xInvocation->invoke( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "item" ) ), + aArgs, + aNamedParamIndex, + aNamedParam ); + } + } + catch( uno::Exception& ) + {} + + throw container::NoSuchElementException(); +} + + diff --git a/basic/source/runtime/comenumwrapper.hxx b/basic/source/runtime/comenumwrapper.hxx new file mode 100644 index 000000000000..b2464d686f67 --- /dev/null +++ b/basic/source/runtime/comenumwrapper.hxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _COMENUMWRAPPER_HXX +#define _COMENUMWRAPPER_HXX + +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/script/XInvocation.hpp> + +#include <cppuhelper/implbase1.hxx> + +class ComEnumerationWrapper : public ::cppu::WeakImplHelper1< ::com::sun::star::container::XEnumeration > +{ + ::com::sun::star::uno::Reference< ::com::sun::star::script::XInvocation > m_xInvocation; + sal_Int32 m_nCurInd; + +public: + ComEnumerationWrapper( const ::com::sun::star::uno::Reference< ::com::sun::star::script::XInvocation >& xInvocation ) + : m_xInvocation( xInvocation ) + , m_nCurInd( 0 ) + { + } + + // container::XEnumeration + virtual ::sal_Bool SAL_CALL hasMoreElements() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL nextElement() throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); +}; + +#endif // _COMENUMWRAPPER_HXX + diff --git a/basic/source/runtime/ddectrl.cxx b/basic/source/runtime/ddectrl.cxx new file mode 100644 index 000000000000..89d473099f0b --- /dev/null +++ b/basic/source/runtime/ddectrl.cxx @@ -0,0 +1,192 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <svl/svdde.hxx> +#include "ddectrl.hxx" +#ifndef _SBERRORS_HXX +#include <basic/sberrors.hxx> +#endif + +#define DDE_FREECHANNEL ((DdeConnection*)0xffffffff) + +#define DDE_FIRSTERR 0x4000 +#define DDE_LASTERR 0x4011 + +static const SbError nDdeErrMap[] = +{ + /* DMLERR_ADVACKTIMEOUT */ 0x4000, SbERR_DDE_TIMEOUT, + /* DMLERR_BUSY */ 0x4001, SbERR_DDE_BUSY, + /* DMLERR_DATAACKTIMEOUT */ 0x4002, SbERR_DDE_TIMEOUT, + /* DMLERR_DLL_NOT_INITIALIZED */ 0x4003, SbERR_DDE_ERROR, + /* DMLERR_DLL_USAGE */ 0x4004, SbERR_DDE_ERROR, + /* DMLERR_EXECACKTIMEOUT */ 0x4005, SbERR_DDE_TIMEOUT, + /* DMLERR_INVALIDPARAMETER */ 0x4006, SbERR_DDE_ERROR, + /* DMLERR_LOW_MEMORY */ 0x4007, SbERR_DDE_ERROR, + /* DMLERR_MEMORY_ERROR */ 0x4008, SbERR_DDE_ERROR, + /* DMLERR_NOTPROCESSED */ 0x4009, SbERR_DDE_NOTPROCESSED, + /* DMLERR_NO_CONV_ESTABLISHED */ 0x400a, SbERR_DDE_NO_CHANNEL, + /* DMLERR_POKEACKTIMEOUT */ 0x400b, SbERR_DDE_TIMEOUT, + /* DMLERR_POSTMSG_FAILED */ 0x400c, SbERR_DDE_QUEUE_OVERFLOW, + /* DMLERR_REENTRANCY */ 0x400d, SbERR_DDE_ERROR, + /* DMLERR_SERVER_DIED */ 0x400e, SbERR_DDE_PARTNER_QUIT, + /* DMLERR_SYS_ERROR */ 0x400f, SbERR_DDE_ERROR, + /* DMLERR_UNADVACKTIMEOUT */ 0x4010, SbERR_DDE_TIMEOUT, + /* DMLERR_UNFOUND_QUEUE_ID */ 0x4011, SbERR_DDE_NO_CHANNEL +}; + +SbError SbiDdeControl::GetLastErr( DdeConnection* pConv ) +{ + if( !pConv ) + return 0; + long nErr = pConv->GetError(); + if( !nErr ) + return 0; + if( nErr < DDE_FIRSTERR || nErr > DDE_LASTERR ) + return SbERR_DDE_ERROR; + return nDdeErrMap[ 2*(nErr - DDE_FIRSTERR) + 1 ]; +} + +IMPL_LINK_INLINE( SbiDdeControl,Data , DdeData*, pData, +{ + aData = String::CreateFromAscii( (char*)(const void*)*pData ); + return 1; +} +) + +SbiDdeControl::SbiDdeControl() +{ + pConvList = new DdeConnections; + DdeConnection* pPtr = DDE_FREECHANNEL; + pConvList->Insert( pPtr ); +} + +SbiDdeControl::~SbiDdeControl() +{ + TerminateAll(); + delete pConvList; +} + +INT16 SbiDdeControl::GetFreeChannel() +{ + INT16 nListSize = (INT16)pConvList->Count(); + DdeConnection* pPtr = pConvList->First(); + pPtr = pConvList->Next(); // nullten eintrag ueberspringen + INT16 nChannel; + for( nChannel = 1; nChannel < nListSize; nChannel++ ) + { + if( pPtr == DDE_FREECHANNEL ) + return nChannel; + pPtr = pConvList->Next(); + } + pPtr = DDE_FREECHANNEL; + pConvList->Insert( pPtr, LIST_APPEND ); + return nChannel; +} + +SbError SbiDdeControl::Initiate( const String& rService, const String& rTopic, + INT16& rnHandle ) +{ + SbError nErr; + DdeConnection* pConv = new DdeConnection( rService, rTopic ); + nErr = GetLastErr( pConv ); + if( nErr ) + { + delete pConv; + rnHandle = 0; + } + else + { + INT16 nChannel = GetFreeChannel(); + pConvList->Replace( pConv, (ULONG)nChannel ); + rnHandle = nChannel; + } + return 0; +} + +SbError SbiDdeControl::Terminate( INT16 nChannel ) +{ + DdeConnection* pConv = pConvList->GetObject( (ULONG)nChannel ); + if( !nChannel || !pConv || pConv == DDE_FREECHANNEL ) + return SbERR_DDE_NO_CHANNEL; + pConvList->Replace( DDE_FREECHANNEL, (ULONG)nChannel ); + delete pConv; + return 0L; +} + +SbError SbiDdeControl::TerminateAll() +{ + INT16 nChannel = (INT16)pConvList->Count(); + while( nChannel ) + { + nChannel--; + Terminate( nChannel ); + } + + pConvList->Clear(); + DdeConnection* pPtr = DDE_FREECHANNEL; + pConvList->Insert( pPtr ); + + return 0; +} + +SbError SbiDdeControl::Request( INT16 nChannel, const String& rItem, String& rResult ) +{ + DdeConnection* pConv = pConvList->GetObject( (ULONG)nChannel ); + if( !nChannel || !pConv || pConv == DDE_FREECHANNEL ) + return SbERR_DDE_NO_CHANNEL; + + DdeRequest aRequest( *pConv, rItem, 30000 ); + aRequest.SetDataHdl( LINK( this, SbiDdeControl, Data ) ); + aRequest.Execute(); + rResult = aData; + return GetLastErr( pConv ); +} + +SbError SbiDdeControl::Execute( INT16 nChannel, const String& rCommand ) +{ + DdeConnection* pConv = pConvList->GetObject( (ULONG)nChannel ); + if( !nChannel || !pConv || pConv == DDE_FREECHANNEL ) + return SbERR_DDE_NO_CHANNEL; + DdeExecute aRequest( *pConv, rCommand, 30000 ); + aRequest.Execute(); + return GetLastErr( pConv ); +} + +SbError SbiDdeControl::Poke( INT16 nChannel, const String& rItem, const String& rData ) +{ + DdeConnection* pConv = pConvList->GetObject( (ULONG)nChannel ); + if( !nChannel || !pConv || pConv == DDE_FREECHANNEL ) + return SbERR_DDE_NO_CHANNEL; + DdePoke aRequest( *pConv, rItem, DdeData(rData), 30000 ); + aRequest.Execute(); + return GetLastErr( pConv ); +} + + diff --git a/basic/source/runtime/ddectrl.hxx b/basic/source/runtime/ddectrl.hxx new file mode 100644 index 000000000000..c1e9da823a20 --- /dev/null +++ b/basic/source/runtime/ddectrl.hxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DDECTRL_HXX +#define _DDECTRL_HXX + +#include <tools/link.hxx> +#ifndef _SBERRORS_HXX +#include <basic/sberrors.hxx> +#endif +#include <tools/string.hxx> + +class DdeConnection; +class DdeConnections; +class DdeData; + +class SbiDdeControl +{ +private: + DECL_LINK( Data, DdeData* ); + SbError GetLastErr( DdeConnection* ); + INT16 GetFreeChannel(); + DdeConnections* pConvList; + String aData; + +public: + + SbiDdeControl(); + ~SbiDdeControl(); + + SbError Initiate( const String& rService, const String& rTopic, + INT16& rnHandle ); + SbError Terminate( INT16 nChannel ); + SbError TerminateAll(); + SbError Request( INT16 nChannel, const String& rItem, String& rResult ); + SbError Execute( INT16 nChannel, const String& rCommand ); + SbError Poke( INT16 nChannel, const String& rItem, const String& rData ); +}; + +#endif diff --git a/basic/source/runtime/dllmgr.cxx b/basic/source/runtime/dllmgr.cxx new file mode 100644 index 000000000000..dbef947f4e94 --- /dev/null +++ b/basic/source/runtime/dllmgr.cxx @@ -0,0 +1,739 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_basic.hxx" +#include "sal/config.h" + +#include <algorithm> +#include <cstddef> +#include <list> +#include <map> +#include <vector> + +#include "basic/sbx.hxx" +#include "basic/sbxvar.hxx" +#include "osl/thread.h" +#include "rtl/ref.hxx" +#include "rtl/string.hxx" +#include "rtl/ustring.hxx" +#include "salhelper/simplereferenceobject.hxx" +#include "tools/svwin.h" + +#undef max + +#include "dllmgr.hxx" + +/* Open issues: + + Only 32-bit Windows for now. + + Missing support for functions returning structs (see TODO in call()). + + Missing support for additional data types (64 bit integers, Any, ...; would + trigger OSL_ASSERT(false) in various switches). + + It is assumed that the variables passed into SbiDllMgr::Call to represent + the arguments and return value have types that exactly match the Declare + statement; it would be better if this code had access to the function + signature from the Declare statement, so that it could convert the passed + variables accordingly. +*/ + +#if defined WNT // only 32-bit Windows, actually + +extern "C" { + +int __stdcall DllMgr_call32(FARPROC, void const * stack, std::size_t size); +double __stdcall DllMgr_callFp(FARPROC, void const * stack, std::size_t size); + +} + +namespace { + +char * address(std::vector< char > & blob) { + return blob.empty() ? 0 : &blob[0]; +} + +SbError convert(rtl::OUString const & source, rtl::OString * target) { + return + source.convertToString( + target, osl_getThreadTextEncoding(), + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | + RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) + ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT; + //TODO: more specific errcode? +} + +SbError convert(char const * source, sal_Int32 length, rtl::OUString * target) { + return + rtl_convertStringToUString( + &target->pData, source, length, osl_getThreadTextEncoding(), + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) + ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT; + //TODO: more specific errcode? +} + +struct UnmarshalData { + UnmarshalData(SbxVariable * theVariable, void * theBuffer): + variable(theVariable), buffer(theBuffer) {} + + SbxVariable * variable; + void * buffer; +}; + +struct StringData: public UnmarshalData { + StringData(SbxVariable * theVariable, void * theBuffer, bool theSpecial): + UnmarshalData(theVariable, theBuffer), special(theSpecial) {} + + bool special; +}; + +class MarshalData: private boost::noncopyable { +public: + std::vector< char > * newBlob() { + blobs_.push_front(std::vector< char >()); + return &blobs_.front(); + } + + std::vector< UnmarshalData > unmarshal; + + std::vector< StringData > unmarshalStrings; + +private: + std::list< std::vector< char > > blobs_; +}; + +std::size_t align(std::size_t address, std::size_t alignment) { + // alignment = 2^k for some k >= 0 + return (address + (alignment - 1)) & ~(alignment - 1); +} + +char * align( + std::vector< char > & blob, std::size_t alignment, std::size_t offset, + std::size_t add) +{ + std::vector< char >::size_type n = blob.size(); + n = align(n - offset, alignment) + offset; //TODO: overflow in align() + blob.resize(n + add); //TODO: overflow + return address(blob) + n; +} + +template< typename T > void add( + std::vector< char > & blob, T const & data, std::size_t alignment, + std::size_t offset) +{ + *reinterpret_cast< T * >(align(blob, alignment, offset, sizeof (T))) = data; +} + +std::size_t alignment(SbxVariable * variable) { + OSL_ASSERT(variable != 0); + if ((variable->GetType() & SbxARRAY) == 0) { + switch (variable->GetType()) { + case SbxINTEGER: + return 2; + case SbxLONG: + case SbxSINGLE: + case SbxSTRING: + return 4; + case SbxDOUBLE: + return 8; + case SbxOBJECT: + { + std::size_t n = 1; + SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())-> + GetProperties(); + for (USHORT i = 0; i < props->Count(); ++i) { + n = std::max(n, alignment(props->Get(i))); + } + return n; + } + case SbxBOOL: + case SbxBYTE: + return 1; + default: + OSL_ASSERT(false); + return 1; + } + } else { + SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject()); + int dims = arr->GetDims(); + std::vector< INT32 > low(dims); + for (int i = 0; i < dims; ++i) { + INT32 up; + arr->GetDim32(i + 1, low[i], up); + } + return alignment(arr->Get32(&low[0])); + } +} + +SbError marshal( + bool outer, SbxVariable * variable, bool special, + std::vector< char > & blob, std::size_t offset, MarshalData & data); + +SbError marshalString( + SbxVariable * variable, bool special, MarshalData & data, void ** buffer) +{ + OSL_ASSERT(variable != 0 && buffer != 0); + rtl::OString str; + SbError e = convert(variable->GetString(), &str); + if (e != ERRCODE_NONE) { + return e; + } + std::vector< char > * blob = data.newBlob(); + blob->insert( + blob->begin(), str.getStr(), str.getStr() + str.getLength() + 1); + *buffer = address(*blob); + data.unmarshalStrings.push_back(StringData(variable, *buffer, special)); + return ERRCODE_NONE; +} + +SbError marshalStruct( + SbxVariable * variable, std::vector< char > & blob, std::size_t offset, + MarshalData & data) +{ + OSL_ASSERT(variable != 0); + SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())-> + GetProperties(); + for (USHORT i = 0; i < props->Count(); ++i) { + SbError e = marshal(false, props->Get(i), false, blob, offset, data); + if (e != ERRCODE_NONE) { + return e; + } + } + return ERRCODE_NONE; +} + +SbError marshalArray( + SbxVariable * variable, std::vector< char > & blob, std::size_t offset, + MarshalData & data) +{ + OSL_ASSERT(variable != 0); + SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject()); + int dims = arr->GetDims(); + std::vector< INT32 > low(dims); + std::vector< INT32 > up(dims); + for (int i = 0; i < dims; ++i) { + arr->GetDim32(i + 1, low[i], up[i]); + } + for (std::vector< INT32 > idx = low;;) { + SbError e = marshal( + false, arr->Get32(&idx[0]), false, blob, offset, data); + if (e != ERRCODE_NONE) { + return e; + } + int i = dims - 1; + while (idx[i] == up[i]) { + idx[i] = low[i]; + if (i == 0) { + return ERRCODE_NONE; + } + --i; + } + ++idx[i]; + } +} + +// 8-aligned structs are only 4-aligned on stack, so alignment of members in +// such structs must take that into account via "offset" +SbError marshal( + bool outer, SbxVariable * variable, bool special, + std::vector< char > & blob, std::size_t offset, MarshalData & data) +{ + OSL_ASSERT(variable != 0); + if ((variable->GetFlags() & SBX_REFERENCE) == 0) { + if ((variable->GetType() & SbxARRAY) == 0) { + switch (variable->GetType()) { + case SbxINTEGER: + add(blob, variable->GetInteger(), outer ? 4 : 2, offset); + break; + case SbxLONG: + add(blob, variable->GetLong(), 4, offset); + break; + case SbxSINGLE: + add(blob, variable->GetSingle(), 4, offset); + break; + case SbxDOUBLE: + add(blob, variable->GetDouble(), outer ? 4 : 8, offset); + break; + case SbxSTRING: + { + void * p; + SbError e = marshalString(variable, special, data, &p); + if (e != ERRCODE_NONE) { + return e; + } + add(blob, p, 4, offset); + break; + } + case SbxOBJECT: + { + align(blob, outer ? 4 : alignment(variable), offset, 0); + SbError e = marshalStruct(variable, blob, offset, data); + if (e != ERRCODE_NONE) { + return e; + } + break; + } + case SbxBOOL: + add(blob, variable->GetBool(), outer ? 4 : 1, offset); + break; + case SbxBYTE: + add(blob, variable->GetByte(), outer ? 4 : 1, offset); + break; + default: + OSL_ASSERT(false); + break; + } + } else { + SbError e = marshalArray(variable, blob, offset, data); + if (e != ERRCODE_NONE) { + return e; + } + } + } else { + if ((variable->GetType() & SbxARRAY) == 0) { + switch (variable->GetType()) { + case SbxINTEGER: + case SbxLONG: + case SbxSINGLE: + case SbxDOUBLE: + case SbxBOOL: + case SbxBYTE: + add(blob, variable->data(), 4, offset); + break; + case SbxSTRING: + { + std::vector< char > * blob2 = data.newBlob(); + void * p; + SbError e = marshalString(variable, special, data, &p); + if (e != ERRCODE_NONE) { + return e; + } + add(*blob2, p, 4, 0); + add(blob, address(*blob2), 4, offset); + break; + } + case SbxOBJECT: + { + std::vector< char > * blob2 = data.newBlob(); + SbError e = marshalStruct(variable, *blob2, 0, data); + if (e != ERRCODE_NONE) { + return e; + } + void * p = address(*blob2); + if (outer) { + data.unmarshal.push_back(UnmarshalData(variable, p)); + } + add(blob, p, 4, offset); + break; + } + default: + OSL_ASSERT(false); + break; + } + } else { + std::vector< char > * blob2 = data.newBlob(); + SbError e = marshalArray(variable, *blob2, 0, data); + if (e != ERRCODE_NONE) { + return e; + } + void * p = address(*blob2); + if (outer) { + data.unmarshal.push_back(UnmarshalData(variable, p)); + } + add(blob, p, 4, offset); + } + } + return ERRCODE_NONE; +} + +template< typename T > T read(void const ** pointer) { + T const * p = static_cast< T const * >(*pointer); + *pointer = static_cast< void const * >(p + 1); + return *p; +} + +void const * unmarshal(SbxVariable * variable, void const * data) { + OSL_ASSERT(variable != 0); + if ((variable->GetType() & SbxARRAY) == 0) { + switch (variable->GetType()) { + case SbxINTEGER: + variable->PutInteger(read< sal_Int16 >(&data)); + break; + case SbxLONG: + variable->PutLong(read< sal_Int32 >(&data)); + break; + case SbxSINGLE: + variable->PutSingle(read< float >(&data)); + break; + case SbxDOUBLE: + variable->PutDouble(read< double >(&data)); + break; + case SbxSTRING: + read< char * >(&data); // handled by unmarshalString + break; + case SbxOBJECT: + { + data = reinterpret_cast< void const * >( + align( + reinterpret_cast< sal_uIntPtr >(data), + alignment(variable))); + SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())-> + GetProperties(); + for (USHORT i = 0; i < props->Count(); ++i) { + data = unmarshal(props->Get(i), data); + } + break; + } + case SbxBOOL: + variable->PutBool(read< sal_Bool >(&data)); + break; + case SbxBYTE: + variable->PutByte(read< sal_uInt8 >(&data)); + break; + default: + OSL_ASSERT(false); + break; + } + } else { + SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject()); + int dims = arr->GetDims(); + std::vector< INT32 > low(dims); + std::vector< INT32 > up(dims); + for (int i = 0; i < dims; ++i) { + arr->GetDim32(i + 1, low[i], up[i]); + } + for (std::vector< INT32 > idx = low;;) { + data = unmarshal(arr->Get32(&idx[0]), data); + int i = dims - 1; + while (idx[i] == up[i]) { + idx[i] = low[i]; + if (i == 0) { + goto done; + } + --i; + } + ++idx[i]; + } + done:; + } + return data; +} + +SbError unmarshalString(StringData const & data, SbxVariable & result) { + rtl::OUString str; + if (data.buffer != 0) { + char const * p = static_cast< char const * >(data.buffer); + sal_Int32 len; + if (data.special) { + len = static_cast< sal_Int32 >(result.GetULong()); + if (len < 0) { // i.e., DWORD result >= 2^31 + return ERRCODE_BASIC_BAD_ARGUMENT; + //TODO: more specific errcode? + } + } else { + len = rtl_str_getLength(p); + } + SbError e = convert(p, len, &str); + if (e != ERRCODE_NONE) { + return e; + } + } + data.variable->PutString(String(str)); + return ERRCODE_NONE; +} + +struct ProcData { + rtl::OString name; + FARPROC proc; +}; + +SbError call( + rtl::OUString const & dll, ProcData const & proc, SbxArray * arguments, + SbxVariable & result) +{ + std::vector< char > stack; + MarshalData data; + // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer) + // from kernel32, upon return, filled lpBuffer length is result DWORD, which + // requires special handling in unmarshalString; other functions might + // require similar treatment, too: + bool special = + dll.equalsIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("KERNEL32.DLL")) && + (proc.name == + rtl::OString(RTL_CONSTASCII_STRINGPARAM("GetLogicalDriveStringsA"))); + for (USHORT i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) { + SbError e = marshal( + true, arguments->Get(i), special && i == 2, stack, stack.size(), + data); + if (e != ERRCODE_NONE) { + return e; + } + align(stack, 4, 0, 0); + } + switch (result.GetType()) { + case SbxEMPTY: + DllMgr_call32(proc.proc, address(stack), stack.size()); + break; + case SbxINTEGER: + result.PutInteger( + static_cast< sal_Int16 >( + DllMgr_call32(proc.proc, address(stack), stack.size()))); + break; + case SbxLONG: + result.PutLong( + static_cast< sal_Int32 >( + DllMgr_call32(proc.proc, address(stack), stack.size()))); + break; + case SbxSINGLE: + result.PutSingle( + static_cast< float >( + DllMgr_callFp(proc.proc, address(stack), stack.size()))); + break; + case SbxDOUBLE: + result.PutDouble( + DllMgr_callFp(proc.proc, address(stack), stack.size())); + break; + case SbxSTRING: + { + char const * s1 = reinterpret_cast< char const * >( + DllMgr_call32(proc.proc, address(stack), stack.size())); + rtl::OUString s2; + SbError e = convert(s1, rtl_str_getLength(s1), &s2); + if (e != ERRCODE_NONE) { + return e; + } + result.PutString(String(s2)); + break; + } + case SbxOBJECT: + //TODO + DllMgr_call32(proc.proc, address(stack), stack.size()); + break; + case SbxBOOL: + result.PutBool( + static_cast< sal_Bool >( + DllMgr_call32(proc.proc, address(stack), stack.size()))); + break; + case SbxBYTE: + result.PutByte( + static_cast< sal_uInt8 >( + DllMgr_call32(proc.proc, address(stack), stack.size()))); + break; + default: + OSL_ASSERT(false); + break; + } + for (USHORT i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) { + arguments->Get(i)->ResetFlag(SBX_REFERENCE); + //TODO: skipped for errors?!? + } + for (std::vector< UnmarshalData >::iterator i(data.unmarshal.begin()); + i != data.unmarshal.end(); ++i) + { + unmarshal(i->variable, i->buffer); + } + for (std::vector< StringData >::iterator i(data.unmarshalStrings.begin()); + i != data.unmarshalStrings.end(); ++i) + { + SbError e = unmarshalString(*i, result); + if (e != ERRCODE_NONE) { + return e; + } + } + return ERRCODE_NONE; +} + +SbError getProcData(HMODULE handle, rtl::OUString const & name, ProcData * proc) +{ + OSL_ASSERT(proc != 0); + if (name.getLength() != 0 && name[0] == '@') { //TODO: "@" vs. "#"??? + sal_Int32 n = name.copy(1).toInt32(); //TODO: handle bad input + if (n <= 0 || n > 0xFFFF) { + return ERRCODE_BASIC_BAD_ARGUMENT; //TODO: more specific errcode? + } + FARPROC p = GetProcAddress(handle, reinterpret_cast< LPCSTR >(n)); + if (p != 0) { + proc->name = rtl::OString(RTL_CONSTASCII_STRINGPARAM("#")) + + rtl::OString::valueOf(n); + proc->proc = p; + return ERRCODE_NONE; + } + } else { + rtl::OString name8; + SbError e = convert(name, &name8); + if (e != ERRCODE_NONE) { + return e; + } + FARPROC p = GetProcAddress(handle, name8.getStr()); + if (p != 0) { + proc->name = name8; + proc->proc = p; + return ERRCODE_NONE; + } + sal_Int32 i = name8.indexOf('#'); + if (i != -1) { + name8 = name8.copy(0, i); + p = GetProcAddress(handle, name8.getStr()); + if (p != 0) { + proc->name = name8; + proc->proc = p; + return ERRCODE_NONE; + } + } + rtl::OString real( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("_")) + name8); + p = GetProcAddress(handle, real.getStr()); + if (p != 0) { + proc->name = real; + proc->proc = p; + return ERRCODE_NONE; + } + real = name8 + rtl::OString(RTL_CONSTASCII_STRINGPARAM("A")); + p = GetProcAddress(handle, real.getStr()); + if (p != 0) { + proc->name = real; + proc->proc = p; + return ERRCODE_NONE; + } + } + return ERRCODE_BASIC_PROC_UNDEFINED; +} + +struct Dll: public salhelper::SimpleReferenceObject { +private: + typedef std::map< rtl::OUString, ProcData > Procs; + + virtual ~Dll(); + +public: + Dll(): handle(0) {} + + SbError getProc(rtl::OUString const & name, ProcData * proc); + + HMODULE handle; + Procs procs; +}; + +Dll::~Dll() { + if (handle != 0 && !FreeLibrary(handle)) { + OSL_TRACE("FreeLibrary(%p) failed with %u", handle, GetLastError()); + } +} + +SbError Dll::getProc(rtl::OUString const & name, ProcData * proc) { + Procs::iterator i(procs.find(name)); + if (i != procs.end()) { + *proc = i->second; + return ERRCODE_NONE; + } + SbError e = getProcData(handle, name, proc); + if (e == ERRCODE_NONE) { + procs.insert(Procs::value_type(name, *proc)); + } + return e; +} + +rtl::OUString fullDllName(rtl::OUString const & name) { + rtl::OUString full(name); + if (full.indexOf('.') == -1) { + full += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".DLL")); + } + return full; +} + +} + +struct SbiDllMgr::Impl: private boost::noncopyable { +private: + typedef std::map< rtl::OUString, rtl::Reference< Dll > > Dlls; + +public: + Dll * getDll(rtl::OUString const & name); + + Dlls dlls; +}; + +Dll * SbiDllMgr::Impl::getDll(rtl::OUString const & name) { + Dlls::iterator i(dlls.find(name)); + if (i == dlls.end()) { + i = dlls.insert(Dlls::value_type(name, new Dll)).first; + HMODULE h = LoadLibraryW(reinterpret_cast<LPCWSTR>(name.getStr())); + if (h == 0) { + dlls.erase(i); + return 0; + } + i->second->handle = h; + } + return i->second.get(); +} + +SbError SbiDllMgr::Call( + rtl::OUString const & function, rtl::OUString const & library, + SbxArray * arguments, SbxVariable & result, bool cdeclConvention) +{ + if (cdeclConvention) { + return ERRCODE_BASIC_NOT_IMPLEMENTED; + } + rtl::OUString dllName(fullDllName(library)); + Dll * dll = impl_->getDll(dllName); + if (dll == 0) { + return ERRCODE_BASIC_BAD_DLL_LOAD; + } + ProcData proc; + SbError e = dll->getProc(function, &proc); + if (e != ERRCODE_NONE) { + return e; + } + return call(dllName, proc, arguments, result); +} + +void SbiDllMgr::FreeDll(rtl::OUString const & library) { + impl_->dlls.erase(library); +} + +#else + +struct SbiDllMgr::Impl {}; + +SbError SbiDllMgr::Call( + rtl::OUString const &, rtl::OUString const &, SbxArray *, SbxVariable &, + bool) +{ + return ERRCODE_BASIC_NOT_IMPLEMENTED; +} + +void SbiDllMgr::FreeDll(rtl::OUString const &) {} + +#endif + +SbiDllMgr::SbiDllMgr(): impl_(new Impl) {} + +SbiDllMgr::~SbiDllMgr() {} diff --git a/basic/source/runtime/dllmgr.hxx b/basic/source/runtime/dllmgr.hxx new file mode 100644 index 000000000000..fdff8c2849be --- /dev/null +++ b/basic/source/runtime/dllmgr.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_BASIC_SOURCE_RUNTIME_DLLMGR_HXX +#define INCLUDED_BASIC_SOURCE_RUNTIME_DLLMGR_HXX + +#include "sal/config.h" + +#include <memory> + +#include "basic/sberrors.hxx" +#include "boost/noncopyable.hpp" + +namespace rtl { class OUString; } +class SbxArray; +class SbxVariable; + +class SbiDllMgr: private boost::noncopyable { +public: + SbiDllMgr(); + + ~SbiDllMgr(); + + SbError Call( + rtl::OUString const & function, rtl::OUString const & library, + SbxArray * arguments, SbxVariable & result, bool cdeclConvention); + + void FreeDll(rtl::OUString const & library); + +private: + struct Impl; + + std::auto_ptr< Impl > impl_; +}; + +#endif diff --git a/basic/source/runtime/inputbox.cxx b/basic/source/runtime/inputbox.cxx new file mode 100644 index 000000000000..17b98ad7addd --- /dev/null +++ b/basic/source/runtime/inputbox.cxx @@ -0,0 +1,197 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#ifndef _SV_BUTTON_HXX //autogen +#include <vcl/button.hxx> +#endif +#include <vcl/fixed.hxx> +#include <vcl/edit.hxx> +#include <vcl/dialog.hxx> +#include <vcl/svapp.hxx> +#include "runtime.hxx" +#include "stdobj.hxx" +#include "rtlproto.hxx" + +class SvRTLInputBox : public ModalDialog +{ + Edit aEdit; + OKButton aOk; + CancelButton aCancel; + FixedText aPromptText; + String aText; + + void PositionDialog( long nXTwips, long nYTwips, const Size& rDlgSize ); + void InitButtons( const Size& rDlgSize ); + void PositionEdit( const Size& rDlgSize ); + void PositionPrompt( const String& rPrompt, const Size& rDlgSize ); + DECL_LINK( OkHdl, Button * ); + DECL_LINK( CancelHdl, Button * ); + +public: + SvRTLInputBox( Window* pParent, const String& rPrompt, const String& rTitle, + const String& rDefault, long nXTwips = -1, long nYTwips = -1 ); + String GetText() const { return aText; } +}; + +SvRTLInputBox::SvRTLInputBox( Window* pParent, const String& rPrompt, + const String& rTitle, const String& rDefault, + long nXTwips, long nYTwips ) : + ModalDialog( pParent,WB_3DLOOK | WB_MOVEABLE | WB_CLOSEABLE ), + aEdit( this, WB_LEFT | WB_BORDER ), + aOk( this ), aCancel( this ), aPromptText( this, WB_WORDBREAK ) +{ + SetMapMode( MapMode( MAP_APPFONT ) ); + Size aDlgSizeApp( 280, 80 ); + PositionDialog( nXTwips, nYTwips, aDlgSizeApp ); + InitButtons( aDlgSizeApp ); + PositionEdit( aDlgSizeApp ); + PositionPrompt( rPrompt, aDlgSizeApp ); + aOk.Show(); + aCancel.Show(); + aEdit.Show(); + aPromptText.Show(); + SetText( rTitle ); + Font aFont( GetFont()); + Color aColor( GetBackground().GetColor() ); + aFont.SetFillColor( aColor ); + aEdit.SetFont( aFont ); + aEdit.SetText( rDefault ); + aEdit.SetSelection( Selection( SELECTION_MIN, SELECTION_MAX ) ); +} + +void SvRTLInputBox::InitButtons( const Size& rDlgSize ) +{ + aOk.SetSizePixel( LogicToPixel( Size( 45, 15) )); + aCancel.SetSizePixel( LogicToPixel( Size( 45, 15) )); + Point aPos( rDlgSize.Width()-45-10, 5 ); + aOk.SetPosPixel( LogicToPixel( Point(aPos) )); + aPos.Y() += 16; + aCancel.SetPosPixel( LogicToPixel( Point(aPos) )); + aOk.SetClickHdl(LINK(this,SvRTLInputBox, OkHdl)); + aCancel.SetClickHdl(LINK(this,SvRTLInputBox,CancelHdl)); +} + +void SvRTLInputBox::PositionDialog(long nXTwips, long nYTwips, const Size& rDlgSize) +{ + SetSizePixel( LogicToPixel(rDlgSize) ); + if( nXTwips != -1 && nYTwips != -1 ) + { + Point aDlgPosApp( nXTwips, nYTwips ); + SetPosPixel( LogicToPixel( aDlgPosApp, MAP_TWIP ) ); + } +} + +void SvRTLInputBox::PositionEdit( const Size& rDlgSize ) +{ + aEdit.SetPosPixel( LogicToPixel( Point( 5,rDlgSize.Height()-35))); + aEdit.SetSizePixel( LogicToPixel( Size(rDlgSize.Width()-15,12))); +} + + +void SvRTLInputBox::PositionPrompt(const String& rPrompt,const Size& rDlgSize) +{ + if ( rPrompt.Len() == 0 ) + return; + String aText_( rPrompt ); + aText_.ConvertLineEnd( LINEEND_CR ); + aPromptText.SetPosPixel( LogicToPixel(Point(5,5))); + aPromptText.SetText( aText_ ); + Size aSize( rDlgSize ); + aSize.Width() -= 70; + aSize.Height() -= 50; + aPromptText.SetSizePixel( LogicToPixel(aSize)); +} + + +IMPL_LINK_INLINE_START( SvRTLInputBox, OkHdl, Button *, pButton ) +{ + (void)pButton; + + aText = aEdit.GetText(); + EndDialog( 1 ); + return 0; +} +IMPL_LINK_INLINE_END( SvRTLInputBox, OkHdl, Button *, pButton ) + +IMPL_LINK_INLINE_START( SvRTLInputBox, CancelHdl, Button *, pButton ) +{ + (void)pButton; + + aText.Erase(); + EndDialog( 0 ); + return 0; +} +IMPL_LINK_INLINE_END( SvRTLInputBox, CancelHdl, Button *, pButton ) + + +// ********************************************************************* +// ********************************************************************* +// ********************************************************************* + +// Syntax: String InputBox( Prompt, [Title], [Default] [, nXpos, nYpos ] ) + +RTLFUNC(InputBox) +{ + (void)pBasic; + (void)bWrite; + + ULONG nArgCount = rPar.Count(); + if ( nArgCount < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aTitle; + String aDefault; + INT32 nX = -1, nY = -1; // zentrieren + const String& rPrompt = rPar.Get(1)->GetString(); + if ( nArgCount > 2 && !rPar.Get(2)->IsErr() ) + aTitle = rPar.Get(2)->GetString(); + if ( nArgCount > 3 && !rPar.Get(3)->IsErr() ) + aDefault = rPar.Get(3)->GetString(); + if ( nArgCount > 4 ) + { + if ( nArgCount != 6 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + nX = rPar.Get(4)->GetLong(); + nY = rPar.Get(5)->GetLong(); + } + SvRTLInputBox *pDlg=new SvRTLInputBox(GetpApp()->GetDefDialogParent(), + rPrompt,aTitle,aDefault,nX,nY); + pDlg->Execute(); + rPar.Get(0)->PutString( pDlg->GetText() ); + delete pDlg; + } +} + + + diff --git a/basic/source/runtime/iosys.cxx b/basic/source/runtime/iosys.cxx new file mode 100644 index 000000000000..9940890286b4 --- /dev/null +++ b/basic/source/runtime/iosys.cxx @@ -0,0 +1,1048 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <vcl/dialog.hxx> +#include <vcl/edit.hxx> +#ifndef _SV_BUTTON_HXX //autogen +#include <vcl/button.hxx> +#endif +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <osl/security.h> +#include <osl/file.hxx> +#include <tools/urlobj.hxx> +#include <vos/mutex.hxx> + +#include "runtime.hxx" + +#ifdef _USE_UNO + +// <-- encoding +#include <sal/alloca.h> + +#include <ctype.h> +#include <rtl/byteseq.hxx> +#include <rtl/textenc.h> +#include <rtl/ustrbuf.hxx> +#include <rtl/textenc.h> +#include <rtl/ustrbuf.hxx> +// encoding --> +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/ucb/XContentProvider.hpp> +#include <com/sun/star/ucb/XContentProviderManager.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> +#include <com/sun/star/bridge/XBridge.hpp> +#include <com/sun/star/bridge/XBridgeFactory.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::bridge; + +#endif /* _USE_UNO */ + +#include "iosys.hxx" +#include "sbintern.hxx" + +// Der Input-Dialog: + +class SbiInputDialog : public ModalDialog { + Edit aInput; + OKButton aOk; + CancelButton aCancel; + String aText; + DECL_LINK( Ok, Window * ); + DECL_LINK( Cancel, Window * ); +public: + SbiInputDialog( Window*, const String& ); + const String& GetInput() { return aText; } +}; + +SbiInputDialog::SbiInputDialog( Window* pParent, const String& rPrompt ) + :ModalDialog( pParent, WB_3DLOOK | WB_MOVEABLE | WB_CLOSEABLE ), + aInput( this, WB_3DLOOK | WB_LEFT | WB_BORDER ), + aOk( this ), aCancel( this ) +{ + SetText( rPrompt ); + aOk.SetClickHdl( LINK( this, SbiInputDialog, Ok ) ); + aCancel.SetClickHdl( LINK( this, SbiInputDialog, Cancel ) ); + SetMapMode( MapMode( MAP_APPFONT ) ); + + Point aPt = LogicToPixel( Point( 50, 50 ) ); + Size aSz = LogicToPixel( Size( 145, 65 ) ); + SetPosSizePixel( aPt, aSz ); + aPt = LogicToPixel( Point( 10, 10 ) ); + aSz = LogicToPixel( Size( 120, 12 ) ); + aInput.SetPosSizePixel( aPt, aSz ); + aPt = LogicToPixel( Point( 15, 30 ) ); + aSz = LogicToPixel( Size( 45, 15) ); + aOk.SetPosSizePixel( aPt, aSz ); + aPt = LogicToPixel( Point( 80, 30 ) ); + aSz = LogicToPixel( Size( 45, 15) ); + aCancel.SetPosSizePixel( aPt, aSz ); + + aInput.Show(); + aOk.Show(); + aCancel.Show(); +} + +IMPL_LINK_INLINE_START( SbiInputDialog, Ok, Window *, pWindow ) +{ + (void)pWindow; + + aText = aInput.GetText(); + EndDialog( 1 ); + return 0; +} +IMPL_LINK_INLINE_END( SbiInputDialog, Ok, Window *, pWindow ) + +IMPL_LINK_INLINE_START( SbiInputDialog, Cancel, Window *, pWindow ) +{ + (void)pWindow; + + EndDialog( 0 ); + return 0; +} +IMPL_LINK_INLINE_END( SbiInputDialog, Cancel, Window *, pWindow ) + +////////////////////////////////////////////////////////////////////////// + +SbiStream::SbiStream() + : pStrm( 0 ) +{ +} + +SbiStream::~SbiStream() +{ + delete pStrm; +} + +// Ummappen eines SvStream-Fehlers auf einen StarBASIC-Code + +void SbiStream::MapError() +{ + if( pStrm ) + switch( pStrm->GetError() ) + { + case SVSTREAM_OK: + nError = 0; break; + case SVSTREAM_FILE_NOT_FOUND: + nError = SbERR_FILE_NOT_FOUND; break; + case SVSTREAM_PATH_NOT_FOUND: + nError = SbERR_PATH_NOT_FOUND; break; + case SVSTREAM_TOO_MANY_OPEN_FILES: + nError = SbERR_TOO_MANY_FILES; break; + case SVSTREAM_ACCESS_DENIED: + nError = SbERR_ACCESS_DENIED; break; + case SVSTREAM_INVALID_PARAMETER: + nError = SbERR_BAD_ARGUMENT; break; + case SVSTREAM_OUTOFMEMORY: + nError = SbERR_NO_MEMORY; break; + default: + nError = SbERR_IO_ERROR; break; + } +} + +#ifdef _USE_UNO + +// TODO: Code is copied from daemons2/source/uno/asciiEncoder.cxx + +::rtl::OUString findUserInDescription( const ::rtl::OUString& aDescription ) +{ + ::rtl::OUString user; + + sal_Int32 index; + sal_Int32 lastIndex = 0; + + do + { + index = aDescription.indexOf((sal_Unicode) ',', lastIndex); + ::rtl::OUString token = (index == -1) ? aDescription.copy(lastIndex) : aDescription.copy(lastIndex, index - lastIndex); + + lastIndex = index + 1; + + sal_Int32 eindex = token.indexOf((sal_Unicode)'='); + ::rtl::OUString left = token.copy(0, eindex).toAsciiLowerCase().trim(); + ::rtl::OUString right = INetURLObject::decode( token.copy(eindex + 1).trim(), '%', + INetURLObject::DECODE_WITH_CHARSET ); + + if(left.equals(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("user")))) + { + user = right; + break; + } + } + while(index != -1); + + return user; +} + +#endif + + +// Hack for #83750 +BOOL runsInSetup( void ); + +BOOL needSecurityRestrictions( void ) +{ +#ifdef _USE_UNO + static BOOL bNeedInit = TRUE; + static BOOL bRetVal = TRUE; + + if( bNeedInit ) + { + // Hack for #83750, use internal flag until + // setup provides own service manager + if( runsInSetup() ) + { + // Setup is not critical + bRetVal = FALSE; + return bRetVal; + } + + bNeedInit = FALSE; + + // Get system user to compare to portal user + oslSecurity aSecurity = osl_getCurrentSecurity(); + ::rtl::OUString aSystemUser; + sal_Bool bRet = osl_getUserName( aSecurity, &aSystemUser.pData ); + if( !bRet ) + { + // No valid security! -> Secure mode! + return TRUE; + } + + Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + if( !xSMgr.is() ) + return TRUE; + Reference< XBridgeFactory > xBridgeFac( xSMgr->createInstance + ( ::rtl::OUString::createFromAscii( "com.sun.star.bridge.BridgeFactory" ) ), UNO_QUERY ); + + Sequence< Reference< XBridge > > aBridgeSeq; + sal_Int32 nBridgeCount = 0; + if( xBridgeFac.is() ) + { + aBridgeSeq = xBridgeFac->getExistingBridges(); + nBridgeCount = aBridgeSeq.getLength(); + } + + if( nBridgeCount == 0 ) + { + // No bridges -> local + bRetVal = FALSE; + return bRetVal; + } + + // Iterate through all bridges to find (portal) user property + const Reference< XBridge >* pBridges = aBridgeSeq.getConstArray(); + bRetVal = FALSE; // Now only TRUE if user different from portal user is found + sal_Int32 i; + for( i = 0 ; i < nBridgeCount ; i++ ) + { + const Reference< XBridge >& rxBridge = pBridges[ i ]; + ::rtl::OUString aDescription = rxBridge->getDescription(); + ::rtl::OUString aPortalUser = findUserInDescription( aDescription ); + if( aPortalUser.getLength() > 0 ) + { + // User Found, compare to system user + if( aPortalUser == aSystemUser ) + { + // Same user -> system security is ok, bRetVal stays FALSE + break; + } + else + { + // Different user -> Secure mode! + bRetVal = TRUE; + break; + } + } + } + // No user found or PortalUser != SystemUser -> Secure mode! (Keep default value) + } + + return bRetVal; +#else + return FALSE; +#endif +} + +// Returns TRUE if UNO is available, otherwise the old file +// system implementation has to be used +// #89378 New semantic: Don't just ask for UNO but for UCB +BOOL hasUno( void ) +{ +#ifdef _USE_UNO + static BOOL bNeedInit = TRUE; + static BOOL bRetVal = TRUE; + + if( bNeedInit ) + { + bNeedInit = FALSE; + Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + if( !xSMgr.is() ) + { + // No service manager at all + bRetVal = FALSE; + } + else + { + Reference< XContentProviderManager > xManager( xSMgr->createInstance( ::rtl::OUString::createFromAscii + ( "com.sun.star.ucb.UniversalContentBroker" ) ), UNO_QUERY ); + + if ( !( xManager.is() && xManager->queryContentProvider( ::rtl::OUString::createFromAscii( "file:///" ) ).is() ) ) + { + // No UCB + bRetVal = FALSE; + } + } + } + return bRetVal; +#else + return FALSE; +#endif +} + + + +#ifndef _OLD_FILE_IMPL + +class OslStream : public SvStream +{ + File maFile; + short mnStrmMode; + +public: + OslStream( const String& rName, short nStrmMode ); + ~OslStream(); + virtual ULONG GetData( void* pData, ULONG nSize ); + virtual ULONG PutData( const void* pData, ULONG nSize ); + virtual ULONG SeekPos( ULONG nPos ); + virtual void FlushData(); + virtual void SetSize( ULONG nSize ); +}; + +OslStream::OslStream( const String& rName, short nStrmMode ) + : maFile( rName ) + , mnStrmMode( nStrmMode ) +{ + sal_uInt32 nFlags; + + if( (nStrmMode & (STREAM_READ | STREAM_WRITE)) == (STREAM_READ | STREAM_WRITE) ) + { + nFlags = OpenFlag_Read | OpenFlag_Write; + } + else if( nStrmMode & STREAM_WRITE ) + { + nFlags = OpenFlag_Write; + } + else //if( nStrmMode & STREAM_READ ) + { + nFlags = OpenFlag_Read; + } + + FileBase::RC nRet = maFile.open( nFlags ); + if( nRet == FileBase::E_NOENT && nFlags != OpenFlag_Read ) + { + nFlags |= OpenFlag_Create; + nRet = maFile.open( nFlags ); + } + + if( nRet != FileBase::E_None ) + { + SetError( ERRCODE_IO_GENERAL ); + } +} + + +OslStream::~OslStream() +{ + maFile.close(); +} + +ULONG OslStream::GetData( void* pData, ULONG nSize ) +{ + sal_uInt64 nBytesRead = nSize; + FileBase::RC nRet = FileBase::E_None; + nRet = maFile.read( pData, nBytesRead, nBytesRead ); + return (ULONG)nBytesRead; +} + +ULONG OslStream::PutData( const void* pData, ULONG nSize ) +{ + sal_uInt64 nBytesWritten; + FileBase::RC nRet = FileBase::E_None; + nRet = maFile.write( pData, (sal_uInt64)nSize, nBytesWritten ); + return (ULONG)nBytesWritten; +} + +ULONG OslStream::SeekPos( ULONG nPos ) +{ + FileBase::RC nRet; + if( nPos == STREAM_SEEK_TO_END ) + { + nRet = maFile.setPos( Pos_End, 0 ); + } + else + { + nRet = maFile.setPos( Pos_Absolut, (sal_uInt64)nPos ); + } + sal_uInt64 nRealPos; + nRet = maFile.getPos( nRealPos ); + return sal::static_int_cast<ULONG>(nRealPos); +} + +void OslStream::FlushData() +{ +} + +void OslStream::SetSize( ULONG nSize ) +{ + FileBase::RC nRet = FileBase::E_None; + nRet = maFile.setSize( (sal_uInt64)nSize ); +} + +#endif + + +#ifdef _USE_UNO + +class UCBStream : public SvStream +{ + Reference< XInputStream > xIS; + Reference< XOutputStream > xOS; + Reference< XStream > xS; + Reference< XSeekable > xSeek; +public: + UCBStream( Reference< XInputStream > & xIS ); + UCBStream( Reference< XOutputStream > & xOS ); + UCBStream( Reference< XStream > & xS ); + ~UCBStream(); + virtual ULONG GetData( void* pData, ULONG nSize ); + virtual ULONG PutData( const void* pData, ULONG nSize ); + virtual ULONG SeekPos( ULONG nPos ); + virtual void FlushData(); + virtual void SetSize( ULONG nSize ); +}; + +/* +ULONG UCBErrorToSvStramError( ucb::IOErrorCode nError ) +{ + ULONG eReturn = ERRCODE_IO_GENERAL; + switch( nError ) + { + case ucb::IOErrorCode_ABORT: eReturn = SVSTREAM_GENERALERROR; break; + case ucb::IOErrorCode_NOT_EXISTING: eReturn = SVSTREAM_FILE_NOT_FOUND; break; + case ucb::IOErrorCode_NOT_EXISTING_PATH: eReturn = SVSTREAM_PATH_NOT_FOUND; break; + case ucb::IOErrorCode_OUT_OF_FILE_HANDLES: eReturn = SVSTREAM_TOO_MANY_OPEN_FILES; break; + case ucb::IOErrorCode_ACCESS_DENIED: eReturn = SVSTREAM_ACCESS_DENIED; break; + case ucb::IOErrorCode_LOCKING_VIOLATION: eReturn = SVSTREAM_SHARING_VIOLATION; break; + + case ucb::IOErrorCode_INVALID_ACCESS: eReturn = SVSTREAM_INVALID_ACCESS; break; + case ucb::IOErrorCode_CANT_CREATE: eReturn = SVSTREAM_CANNOT_MAKE; break; + case ucb::IOErrorCode_INVALID_PARAMETER: eReturn = SVSTREAM_INVALID_PARAMETER; break; + + case ucb::IOErrorCode_CANT_READ: eReturn = SVSTREAM_READ_ERROR; break; + case ucb::IOErrorCode_CANT_WRITE: eReturn = SVSTREAM_WRITE_ERROR; break; + case ucb::IOErrorCode_CANT_SEEK: eReturn = SVSTREAM_SEEK_ERROR; break; + case ucb::IOErrorCode_CANT_TELL: eReturn = SVSTREAM_TELL_ERROR; break; + + case ucb::IOErrorCode_OUT_OF_MEMORY: eReturn = SVSTREAM_OUTOFMEMORY; break; + + case SVSTREAM_FILEFORMAT_ERROR: eReturn = SVSTREAM_FILEFORMAT_ERROR; break; + case ucb::IOErrorCode_WRONG_VERSION: eReturn = SVSTREAM_WRONGVERSION; + case ucb::IOErrorCode_OUT_OF_DISK_SPACE: eReturn = SVSTREAM_DISK_FULL; break; + + case ucb::IOErrorCode_BAD_CRC: eReturn = ERRCODE_IO_BADCRC; break; + } + return eReturn; +} +*/ + +UCBStream::UCBStream( Reference< XInputStream > & rStm ) + : xIS( rStm ) + , xSeek( rStm, UNO_QUERY ) +{ +} + +UCBStream::UCBStream( Reference< XOutputStream > & rStm ) + : xOS( rStm ) + , xSeek( rStm, UNO_QUERY ) +{ +} + +UCBStream::UCBStream( Reference< XStream > & rStm ) + : xS( rStm ) + , xSeek( rStm, UNO_QUERY ) +{ +} + + +UCBStream::~UCBStream() +{ + try + { + if( xIS.is() ) + xIS->closeInput(); + else if( xOS.is() ) + xOS->closeOutput(); + else if( xS.is() ) + { + Reference< XInputStream > xIS_ = xS->getInputStream(); + if( xIS_.is() ) + xIS_->closeInput(); + } + } + catch( Exception & ) + { + SetError( ERRCODE_IO_GENERAL ); + } +} + +ULONG UCBStream::GetData( void* pData, ULONG nSize ) +{ + try + { + Reference< XInputStream > xISFromS; + if( xIS.is() ) + { + Sequence<sal_Int8> aData; + nSize = xIS->readBytes( aData, nSize ); + rtl_copyMemory( pData, aData.getConstArray(), nSize ); + return nSize; + } + else if( xS.is() && (xISFromS = xS->getInputStream()).is() ) + { + Sequence<sal_Int8> aData; + nSize = xISFromS->readBytes( aData, nSize ); + rtl_copyMemory( pData, aData.getConstArray(), nSize ); + return nSize; + } + else + SetError( ERRCODE_IO_GENERAL ); + } + catch( Exception & ) + { + SetError( ERRCODE_IO_GENERAL ); + } + return 0; +} + +ULONG UCBStream::PutData( const void* pData, ULONG nSize ) +{ + try + { + Reference< XOutputStream > xOSFromS; + if( xOS.is() ) + { + Sequence<sal_Int8> aData( (const sal_Int8 *)pData, nSize ); + xOS->writeBytes( aData ); + return nSize; + } + else if( xS.is() && (xOSFromS = xS->getOutputStream()).is() ) + { + Sequence<sal_Int8> aData( (const sal_Int8 *)pData, nSize ); + xOSFromS->writeBytes( aData ); + return nSize; + } + else + SetError( ERRCODE_IO_GENERAL ); + } + catch( Exception & ) + { + SetError( ERRCODE_IO_GENERAL ); + } + return 0; +} + +ULONG UCBStream::SeekPos( ULONG nPos ) +{ + try + { + if( xSeek.is() ) + { + ULONG nLen = sal::static_int_cast<ULONG>( xSeek->getLength() ); + if( nPos > nLen ) + nPos = nLen; + xSeek->seek( nPos ); + return nPos; + } + else + SetError( ERRCODE_IO_GENERAL ); + } + catch( Exception & ) + { + SetError( ERRCODE_IO_GENERAL ); + } + return 0; +} + +void UCBStream::FlushData() +{ + try + { + Reference< XOutputStream > xOSFromS; + if( xOS.is() ) + xOS->flush(); + else if( xS.is() && (xOSFromS = xS->getOutputStream()).is() ) + xOSFromS->flush(); + else + SetError( ERRCODE_IO_GENERAL ); + } + catch( Exception & ) + { + SetError( ERRCODE_IO_GENERAL ); + } +} + +void UCBStream::SetSize( ULONG nSize ) +{ + (void)nSize; + + DBG_ERROR( "not allowed to call from basic" ); + SetError( ERRCODE_IO_GENERAL ); +} + +#endif + +// Oeffnen eines Streams +SbError SbiStream::Open +( short nCh, const ByteString& rName, short nStrmMode, short nFlags, short nL ) +{ + nMode = nFlags; + nLen = nL; + nChan = nCh; + nLine = 0; + nExpandOnWriteTo = 0; + if( ( nStrmMode & ( STREAM_READ|STREAM_WRITE ) ) == STREAM_READ ) + nStrmMode |= STREAM_NOCREATE; + String aStr( rName, gsl_getSystemTextEncoding() ); + String aNameStr = getFullPath( aStr ); + +#ifdef _USE_UNO + if( hasUno() ) + { + Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + if( xSMgr.is() ) + { + Reference< XSimpleFileAccess > + xSFI( xSMgr->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY ); + if( xSFI.is() ) + { + try + { + + // #??? For write access delete file if it already exists (not for appending) + if( (nStrmMode & STREAM_WRITE) != 0 && !IsAppend() && !IsBinary() && + xSFI->exists( aNameStr ) && !xSFI->isFolder( aNameStr ) ) + { + xSFI->kill( aNameStr ); + } + + if( (nStrmMode & (STREAM_READ | STREAM_WRITE)) == (STREAM_READ | STREAM_WRITE) ) + { + Reference< XStream > xIS = xSFI->openFileReadWrite( aNameStr ); + pStrm = new UCBStream( xIS ); + } + else if( nStrmMode & STREAM_WRITE ) + { + Reference< XStream > xIS = xSFI->openFileReadWrite( aNameStr ); + pStrm = new UCBStream( xIS ); + // Open for writing is not implemented in ucb yet!!! + //Reference< XOutputStream > xIS = xSFI->openFileWrite( aNameStr ); + //pStrm = new UCBStream( xIS ); + } + else //if( nStrmMode & STREAM_READ ) + { + Reference< XInputStream > xIS = xSFI->openFileRead( aNameStr ); + pStrm = new UCBStream( xIS ); + } + + } + catch( Exception & ) + { + nError = ERRCODE_IO_GENERAL; + } + } + } + } + +#endif + if( !pStrm ) + { +#ifdef _OLD_FILE_IMPL + pStrm = new SvFileStream( aNameStr, nStrmMode ); +#else + pStrm = new OslStream( aNameStr, nStrmMode ); +#endif + } + if( IsAppend() ) + pStrm->Seek( STREAM_SEEK_TO_END ); + MapError(); + if( nError ) + delete pStrm, pStrm = NULL; + return nError; +} + +SbError SbiStream::Close() +{ + if( pStrm ) + { + if( !hasUno() ) + { +#ifdef _OLD_FILE_IMPL + ((SvFileStream *)pStrm)->Close(); +#endif + } + MapError(); + delete pStrm; + pStrm = NULL; + } + nChan = 0; + return nError; +} + +SbError SbiStream::Read( ByteString& rBuf, USHORT n, bool bForceReadingPerByte ) +{ + nExpandOnWriteTo = 0; + if( !bForceReadingPerByte && IsText() ) + { + pStrm->ReadLine( rBuf ); + nLine++; + } + else + { + if( !n ) n = nLen; + if( !n ) + return nError = SbERR_BAD_RECORD_LENGTH; + rBuf.Fill( n, ' ' ); + pStrm->Read( (void*)rBuf.GetBuffer(), n ); + } + MapError(); + if( !nError && pStrm->IsEof() ) + nError = SbERR_READ_PAST_EOF; + return nError; +} + +SbError SbiStream::Read( char& ch ) +{ + nExpandOnWriteTo = 0; + if( !aLine.Len() ) + { + Read( aLine, 0 ); + aLine += '\n'; + } + ch = aLine.GetBuffer()[0]; + aLine.Erase( 0, 1 ); + return nError; +} + +void SbiStream::ExpandFile() +{ + if ( nExpandOnWriteTo ) + { + ULONG nCur = pStrm->Seek(STREAM_SEEK_TO_END); + if( nCur < nExpandOnWriteTo ) + { + ULONG nDiff = nExpandOnWriteTo - nCur; + char c = 0; + while( nDiff-- ) + *pStrm << c; + } + else + { + pStrm->Seek( nExpandOnWriteTo ); + } + nExpandOnWriteTo = 0; + } +} + +SbError SbiStream::Write( const ByteString& rBuf, USHORT n ) +{ + ExpandFile(); + if( IsAppend() ) + pStrm->Seek( STREAM_SEEK_TO_END ); + + if( IsText() ) + { + aLine += rBuf; + // Raus damit, wenn das Ende ein LF ist, aber CRLF vorher + // strippen, da der SvStrm ein CRLF anfuegt! + USHORT nLineLen = aLine.Len(); + if( nLineLen && aLine.GetBuffer()[ --nLineLen ] == 0x0A ) + { + aLine.Erase( nLineLen ); + if( nLineLen && aLine.GetBuffer()[ --nLineLen ] == 0x0D ) + aLine.Erase( nLineLen ); + pStrm->WriteLines( aLine ); + aLine.Erase(); + } + } + else + { + if( !n ) n = nLen; + if( !n ) + return nError = SbERR_BAD_RECORD_LENGTH; + pStrm->Write( rBuf.GetBuffer(), n ); + MapError(); + } + return nError; +} + +////////////////////////////////////////////////////////////////////////// + +// Zugriff auf das aktuelle I/O-System: + +SbiIoSystem* SbGetIoSystem() +{ + SbiInstance* pInst = pINST; + return pInst ? pInst->GetIoSystem() : NULL; +} + +////////////////////////////////////////////////////////////////////////// + +SbiIoSystem::SbiIoSystem() +{ + for( short i = 0; i < CHANNELS; i++ ) + pChan[ i ] = NULL; + nChan = 0; + nError = 0; +} + +SbiIoSystem::~SbiIoSystem() +{ + Shutdown(); +} + +SbError SbiIoSystem::GetError() +{ + SbError n = nError; nError = 0; + return n; +} + +void SbiIoSystem::Open + ( short nCh, const ByteString& rName, short nMode, short nFlags, short nLen ) +{ + nError = 0; + if( nCh >= CHANNELS || !nCh ) + nError = SbERR_BAD_CHANNEL; + else if( pChan[ nCh ] ) + nError = SbERR_FILE_ALREADY_OPEN; + else + { + pChan[ nCh ] = new SbiStream; + nError = pChan[ nCh ]->Open( nCh, rName, nMode, nFlags, nLen ); + if( nError ) + delete pChan[ nCh ], pChan[ nCh ] = NULL; + } + nChan = 0; +} + +// Aktuellen Kanal schliessen + +void SbiIoSystem::Close() +{ + if( !nChan ) + nError = SbERR_BAD_CHANNEL; + else if( !pChan[ nChan ] ) + nError = SbERR_BAD_CHANNEL; + else + { + nError = pChan[ nChan ]->Close(); + delete pChan[ nChan ]; + pChan[ nChan ] = NULL; + } + nChan = 0; +} + +// Shutdown nach Programmlauf + +void SbiIoSystem::Shutdown() +{ + for( short i = 1; i < CHANNELS; i++ ) + { + if( pChan[ i ] ) + { + SbError n = pChan[ i ]->Close(); + delete pChan[ i ]; + pChan[ i ] = NULL; + if( n && !nError ) + nError = n; + } + } + nChan = 0; + // Noch was zu PRINTen? + if( aOut.Len() ) + { + String aOutStr( aOut, gsl_getSystemTextEncoding() ); +#if defined GCC + Window* pParent = Application::GetDefDialogParent(); + MessBox( pParent, WinBits( WB_OK ), String(), aOutStr ).Execute(); +#else + MessBox( GetpApp()->GetDefDialogParent(), WinBits( WB_OK ), String(), aOutStr ).Execute(); +#endif + } + aOut.Erase(); +} + +// Aus aktuellem Kanal lesen + +void SbiIoSystem::Read( ByteString& rBuf, short n ) +{ + if( !nChan ) + ReadCon( rBuf ); + else if( !pChan[ nChan ] ) + nError = SbERR_BAD_CHANNEL; + else + nError = pChan[ nChan ]->Read( rBuf, n ); +} + +char SbiIoSystem::Read() +{ + char ch = ' '; + if( !nChan ) + { + if( !aIn.Len() ) + { + ReadCon( aIn ); + aIn += '\n'; + } + ch = aIn.GetBuffer()[0]; + aIn.Erase( 0, 1 ); + } + else if( !pChan[ nChan ] ) + nError = SbERR_BAD_CHANNEL; + else + nError = pChan[ nChan ]->Read( ch ); + return ch; +} + +void SbiIoSystem::Write( const ByteString& rBuf, short n ) +{ + if( !nChan ) + WriteCon( rBuf ); + else if( !pChan[ nChan ] ) + nError = SbERR_BAD_CHANNEL; + else + nError = pChan[ nChan ]->Write( rBuf, n ); +} + +short SbiIoSystem::NextChannel() +{ + for( short i = 1; i < CHANNELS; i++ ) + { + if( !pChan[ i ] ) + return i; + } + nError = SbERR_TOO_MANY_FILES; + return CHANNELS; +} + +// nChannel == 0..CHANNELS-1 + +SbiStream* SbiIoSystem::GetStream( short nChannel ) const +{ + SbiStream* pRet = 0; + if( nChannel >= 0 && nChannel < CHANNELS ) + pRet = pChan[ nChannel ]; + return pRet; +} + +void SbiIoSystem::CloseAll(void) +{ + for( short i = 1; i < CHANNELS; i++ ) + { + if( pChan[ i ] ) + { + SbError n = pChan[ i ]->Close(); + delete pChan[ i ]; + pChan[ i ] = NULL; + if( n && !nError ) + nError = n; + } + } +} + +/*************************************************************************** +* +* Console Support +* +***************************************************************************/ + +// Einlesen einer Zeile von der Console + +void SbiIoSystem::ReadCon( ByteString& rIn ) +{ + String aPromptStr( aPrompt, gsl_getSystemTextEncoding() ); + SbiInputDialog aDlg( NULL, aPromptStr ); + if( aDlg.Execute() ) + rIn = ByteString( aDlg.GetInput(), gsl_getSystemTextEncoding() ); + else + nError = SbERR_USER_ABORT; + aPrompt.Erase(); +} + +// Ausgabe einer MessageBox, wenn im Console-Puffer ein CR ist + +void SbiIoSystem::WriteCon( const ByteString& rText ) +{ + aOut += rText; + USHORT n1 = aOut.Search( '\n' ); + USHORT n2 = aOut.Search( '\r' ); + if( n1 != STRING_NOTFOUND || n2 != STRING_NOTFOUND ) + { + if( n1 == STRING_NOTFOUND ) n1 = n2; + else + if( n2 == STRING_NOTFOUND ) n2 = n1; + if( n1 > n2 ) n1 = n2; + ByteString s( aOut.Copy( 0, n1 ) ); + aOut.Erase( 0, n1 ); + while( aOut.GetBuffer()[0] == '\n' || aOut.GetBuffer()[0] == '\r' ) + aOut.Erase( 0, 1 ); + String aStr( s, gsl_getSystemTextEncoding() ); + { + vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + if( !MessBox( GetpApp()->GetDefDialogParent(), + WinBits( WB_OK_CANCEL | WB_DEF_OK ), + String(), aStr ).Execute() ) + nError = SbERR_USER_ABORT; + } + } +} + diff --git a/basic/source/runtime/makefile.mk b/basic/source/runtime/makefile.mk new file mode 100644 index 000000000000..8ca052aaae1a --- /dev/null +++ b/basic/source/runtime/makefile.mk @@ -0,0 +1,72 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=basic +TARGET=runtime + +ENABLE_EXCEPTIONS = TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + + +# --- Allgemein ----------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/basrdll.obj \ + $(SLO)$/comenumwrapper.obj \ + $(SLO)$/inputbox.obj \ + $(SLO)$/runtime.obj \ + $(SLO)$/step0.obj \ + $(SLO)$/step1.obj \ + $(SLO)$/step2.obj \ + $(SLO)$/iosys.obj \ + $(SLO)$/stdobj.obj \ + $(SLO)$/stdobj1.obj \ + $(SLO)$/methods.obj \ + $(SLO)$/methods1.obj \ + $(SLO)$/props.obj \ + $(SLO)$/ddectrl.obj \ + $(SLO)$/dllmgr.obj + +.IF "$(GUI)$(COM)$(CPU)" == "WNTMSCI" +SLOFILES+= $(SLO)$/wnt.obj +.ELIF "$(GUI)$(COM)$(CPU)" == "WNTGCCI" +SLOFILES+= $(SLO)$/wnt-mingw.obj +.ENDIF + +# --- Targets ------------------------------------------------------------- + +.INCLUDE : target.mk + +$(SLO)$/%.obj: %.s +#kendy: Cut'n'paste from bridges/source/cpp_uno/mingw_intel/makefile.mk + $(CC) -c -o $(SLO)$/$(@:b).obj $< + touch $@ diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx new file mode 100644 index 000000000000..cfd84567644a --- /dev/null +++ b/basic/source/runtime/methods.cxx @@ -0,0 +1,4540 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + + +#include <tools/date.hxx> +#include <basic/sbxvar.hxx> +#ifndef _VOS_PROCESS_HXX +#include <vos/process.hxx> +#endif +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/sound.hxx> +#include <tools/wintypes.hxx> +#include <vcl/msgbox.hxx> +#include <basic/sbx.hxx> +#include <svl/zforlist.hxx> +#include <rtl/math.hxx> +#include <tools/urlobj.hxx> +#include <osl/time.h> +#include <unotools/charclass.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <tools/wldcrd.hxx> +#include <i18npool/lang.h> + +#include "runtime.hxx" +#include "sbunoobj.hxx" +#ifdef WNT +#include <tools/prewin.h> +#include "winbase.h" +#include <tools/postwin.h> +#ifndef _FSYS_HXX //autogen +#include <tools/fsys.hxx> +#endif +#else +#include <osl/file.hxx> +#endif +#include "errobject.hxx" + +#ifdef _USE_UNO +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess3.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> + +using namespace comphelper; +using namespace osl; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::ucb; +using namespace com::sun::star::io; + +#endif /* _USE_UNO */ + +//#define _ENABLE_CUR_DIR + +#include "stdobj.hxx" +#include <basic/sbstdobj.hxx> +#include "rtlproto.hxx" +#include "basrid.hxx" +#include "image.hxx" +#include "sb.hrc" +#include "iosys.hxx" +#include "ddectrl.hxx" +#include <sbintern.hxx> + +#include <list> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#if defined (WNT) || defined (OS2) +#include <direct.h> // _getdcwd get current work directory, _chdrive +#endif + +#ifdef UNX +#include <errno.h> +#include <unistd.h> +#endif + +#ifdef WNT +#include <io.h> +#endif + +#include <basic/sbobjmod.hxx> + +static void FilterWhiteSpace( String& rStr ) +{ + rStr.EraseAllChars( ' ' ); + rStr.EraseAllChars( '\t' ); + rStr.EraseAllChars( '\n' ); + rStr.EraseAllChars( '\r' ); +} + +static long GetDayDiff( const Date& rDate ) +{ + Date aRefDate( 1,1,1900 ); + long nDiffDays; + if ( aRefDate > rDate ) + { + nDiffDays = (long)(aRefDate - rDate); + nDiffDays *= -1; + } + else + nDiffDays = (long)(rDate - aRefDate); + nDiffDays += 2; // Anpassung VisualBasic: 1.Jan.1900 == 2 + return nDiffDays; +} + +static CharClass& GetCharClass( void ) +{ + static sal_Bool bNeedsInit = sal_True; + static ::com::sun::star::lang::Locale aLocale; + if( bNeedsInit ) + { + bNeedsInit = sal_False; + aLocale = Application::GetSettings().GetLocale(); + } + static CharClass aCharClass( aLocale ); + return aCharClass; +} + +static inline BOOL isFolder( FileStatus::Type aType ) +{ + return ( aType == FileStatus::Directory || aType == FileStatus::Volume ); +} + + +//*** UCB file access *** + +// Converts possibly relative paths to absolute paths +// according to the setting done by ChDir/ChDrive +String getFullPath( const String& aRelPath ) +{ + ::rtl::OUString aFileURL; + + // #80204 Try first if it already is a valid URL + INetURLObject aURLObj( aRelPath ); + aFileURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + + if( !aFileURL.getLength() ) + { + File::getFileURLFromSystemPath( aRelPath, aFileURL ); + } + + return aFileURL; +} + +// Sets (virtual) current path for UCB file access +void implChDir( const String& aDir ) +{ + (void)aDir; + // TODO +} + +// Sets (virtual) current drive for UCB file access +void implChDrive( const String& aDrive ) +{ + (void)aDrive; + // TODO +} + +// Returns (virtual) current path for UCB file access +String implGetCurDir( void ) +{ + String aRetStr; + + return aRetStr; +} + +// TODO: -> SbiGlobals +static com::sun::star::uno::Reference< XSimpleFileAccess3 > getFileAccess( void ) +{ + static com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI; + if( !xSFI.is() ) + { + com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + if( xSMgr.is() ) + { + xSFI = com::sun::star::uno::Reference< XSimpleFileAccess3 >( xSMgr->createInstance + ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY ); + } + } + return xSFI; +} + + + +// Properties und Methoden legen beim Get (bPut = FALSE) den Returnwert +// im Element 0 des Argv ab; beim Put (bPut = 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; + 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( (USHORT)nCode ); + } + + bool bVBA = SbiRuntime::isVBAEnabled(); + String tmpErrMsg; + if( bVBA && aErrorMsg.Len() > 0 ) + { + tmpErrMsg = aErrorMsg; + } + else + { + pBasic->MakeErrorText( nErr, aErrorMsg ); + tmpErrMsg = pBasic->GetErrorText(); + } + // If this rtlfunc 'Error' passed a errcode the same as the active Err Objects's + // current err then return the description for the error message if it is set + // ( complicated isn't it ? ) + if ( bVBA && rPar.Count() > 1 ) + { + com::sun::star::uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() ); + if ( xErrObj.is() && xErrObj->getNumber() == nCode && xErrObj->getDescription().getLength() ) + tmpErrMsg = xErrObj->getDescription(); + } + rPar.Get( 0 )->PutString( tmpErrMsg ); + } +} + +// Sinus + +RTLFUNC(Sin) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( sin( pArg->GetDouble() ) ); + } +} + +// Cosinus + +RTLFUNC(Cos) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( cos( pArg->GetDouble() ) ); + } +} + +// Atn + +RTLFUNC(Atn) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( atan( pArg->GetDouble() ) ); + } +} + + + +RTLFUNC(Abs) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + rPar.Get( 0 )->PutDouble( fabs( pArg->GetDouble() ) ); + } +} + + +RTLFUNC(Asc) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + String aStr( pArg->GetString() ); + if ( aStr.Len() == 0 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + rPar.Get(0)->PutEmpty(); + } + else + { + sal_Unicode aCh = aStr.GetBuffer()[0]; + rPar.Get(0)->PutLong( aCh ); + } + } +} + +RTLFUNC(Chr) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + sal_Unicode aCh = (sal_Unicode)pArg->GetUShort(); + String aStr( aCh ); + rPar.Get(0)->PutString( aStr ); + } +} + + +#ifdef UNX +#define _MAX_PATH 260 +#define _PATH_INCR 250 +#endif + +RTLFUNC(CurDir) +{ + (void)pBasic; + (void)bWrite; + + // #57064 Obwohl diese Funktion nicht mit DirEntry arbeitet, ist sie von + // der Anpassung an virtuelle URLs nich betroffen, da bei Nutzung der + // DirEntry-Funktionalitaet keine Moeglichkeit besteht, das aktuelle so + // zu ermitteln, dass eine virtuelle URL geliefert werden koennte. + +// rPar.Get(0)->PutEmpty(); +#if defined (WNT) || defined (OS2) + int nCurDir = 0; // Current dir // JSM + if ( rPar.Count() == 2 ) + { + String aDrive = rPar.Get(1)->GetString(); + if ( aDrive.Len() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + else + { + nCurDir = (int)aDrive.GetBuffer()[0]; + if ( !isalpha( nCurDir ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + else + nCurDir -= ( 'A' - 1 ); + } + } + char* pBuffer = new char[ _MAX_PATH ]; +#ifdef OS2 + if( !nCurDir ) + nCurDir = _getdrive(); +#endif + if ( _getdcwd( nCurDir, pBuffer, _MAX_PATH ) != 0 ) + rPar.Get(0)->PutString( String::CreateFromAscii( pBuffer ) ); + else + StarBASIC::Error( SbERR_NO_DEVICE ); + delete [] pBuffer; + +#elif defined( UNX ) + + int nSize = _PATH_INCR; + char* pMem; + while( TRUE ) + { + pMem = new char[nSize]; + if( !pMem ) + { + StarBASIC::Error( SbERR_NO_MEMORY ); + return; + } + if( getcwd( pMem, nSize-1 ) != NULL ) + { + rPar.Get(0)->PutString( String::CreateFromAscii(pMem) ); + delete [] pMem; + return; + } + if( errno != ERANGE ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + delete [] pMem; + return; + } + delete [] pMem; + nSize += _PATH_INCR; + }; + +#endif +} + +RTLFUNC(ChDir) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { +#ifdef _ENABLE_CUR_DIR + String aPath = rPar.Get(1)->GetString(); + BOOL bError = 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 = TRUE; +#else + if (!DirEntry(aPath).SetCWD()) + bError = TRUE; +#endif + if( bError ) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#endif + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(ChDrive) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { +#ifdef _ENABLE_CUR_DIR + // Keine Laufwerke in Unix +#ifndef UNX + String aPar1 = rPar.Get(1)->GetString(); + +#if defined (WNT) || defined (OS2) + if (aPar1.Len() > 0) + { + int nCurDrive = (int)aPar1.GetBuffer()[0]; ; + if ( !isalpha( nCurDrive ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + else + nCurDrive -= ( 'A' - 1 ); + if (_chdrive(nCurDrive)) + StarBASIC::Error( SbERR_NO_DEVICE ); + } +#endif + +#endif + // #ifndef UNX +#endif + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + + +// Implementation of StepRENAME with UCB +void implStepRenameUCB( const String& aSource, const String& aDest ) +{ + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + String aSourceFullPath = getFullPath( aSource ); + if( !xSFI->exists( aSourceFullPath ) ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + return; + } + + String aDestFullPath = getFullPath( aDest ); + if( xSFI->exists( aDestFullPath ) ) + StarBASIC::Error( SbERR_FILE_EXISTS ); + else + xSFI->move( aSourceFullPath, aDestFullPath ); + } + catch( Exception & ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + } + } +} + +// Implementation of StepRENAME with OSL +void implStepRenameOSL( const String& aSource, const String& aDest ) +{ + FileBase::RC nRet = File::move( getFullPathUNC( aSource ), getFullPathUNC( aDest ) ); + if( nRet != FileBase::E_None ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } +} + +RTLFUNC(FileCopy) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 3) + { + String aSource = rPar.Get(1)->GetString(); + String aDest = rPar.Get(2)->GetString(); + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) ); + } + catch( Exception & ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aSourceDirEntry(aSource); + if (aSourceDirEntry.Exists()) + { + if (aSourceDirEntry.CopyTo(DirEntry(aDest),FSYS_ACTION_COPYFILE) != FSYS_ERR_OK) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } + else + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + FileBase::RC nRet = File::copy( getFullPathUNC( aSource ), getFullPathUNC( aDest ) ); + if( nRet != FileBase::E_None ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(Kill) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { + String aFileSpec = rPar.Get(1)->GetString(); + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + String aFullPath = getFullPath( aFileSpec ); + if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) ) + { + StarBASIC::Error( SbERR_FILE_NOT_FOUND ); + return; + } + try + { + xSFI->kill( aFullPath ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + if(DirEntry(aFileSpec).Kill() != FSYS_ERR_OK) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + File::remove( getFullPathUNC( aFileSpec ) ); +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(MkDir) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { + String aPath = rPar.Get(1)->GetString(); + + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + xSFI->createFolder( getFullPath( aPath ) ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + if (!DirEntry(aPath).MakeDir()) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + Directory::create( getFullPathUNC( aPath ) ); +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + + +#ifndef _OLD_FILE_IMPL + +// In OSL only empty directories can be deleted +// so we have to delete all files recursively +void implRemoveDirRecursive( const String& aDirPath ) +{ + DirectoryItem aItem; + FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem ); + sal_Bool bExists = (nRet == FileBase::E_None); + + FileStatus aFileStatus( FileStatusMask_Type ); + nRet = aItem.getFileStatus( aFileStatus ); + FileStatus::Type aType = aFileStatus.getFileType(); + sal_Bool bFolder = isFolder( aType ); + + if( !bExists || !bFolder ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + return; + } + + Directory aDir( aDirPath ); + nRet = aDir.open(); + if( nRet != FileBase::E_None ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + return; + } + + for( ;; ) + { + DirectoryItem aItem2; + nRet = aDir.getNextItem( aItem2 ); + if( nRet != FileBase::E_None ) + break; + + // Handle flags + FileStatus aFileStatus2( FileStatusMask_Type | FileStatusMask_FileURL ); + nRet = aItem2.getFileStatus( aFileStatus2 ); + ::rtl::OUString aPath = aFileStatus2.getFileURL(); + + // Directory? + FileStatus::Type aType2 = aFileStatus2.getFileType(); + sal_Bool bFolder2 = isFolder( aType2 ); + if( bFolder2 ) + { + implRemoveDirRecursive( aPath ); + } + else + { + File::remove( aPath ); + } + } + nRet = aDir.close(); + + nRet = Directory::remove( aDirPath ); +} +#endif + + +RTLFUNC(RmDir) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if (rPar.Count() == 2) + { + String aPath = rPar.Get(1)->GetString(); + // <-- UCB + if( hasUno() ) + { + com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess(); + if( xSFI.is() ) + { + try + { + if( !xSFI->isFolder( aPath ) ) + { + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + return; + } + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + Sequence< ::rtl::OUString > aContent = xSFI->getFolderContents( aPath, true ); + sal_Int32 nCount = aContent.getLength(); + if( nCount > 0 ) + { + StarBASIC::Error( SbERR_ACCESS_ERROR ); + return; + } + } + + xSFI->kill( getFullPath( aPath ) ); + } + catch( Exception & ) + { + StarBASIC::Error( ERRCODE_IO_GENERAL ); + } + } + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aDirEntry(aPath); + if (aDirEntry.Kill() != FSYS_ERR_OK) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + implRemoveDirRecursive( getFullPathUNC( aPath ) ); +#endif + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(SendKeys) // JSM +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); +} + +RTLFUNC(Exp) +{ + (void)pBasic; + (void)bWrite; + + if( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double aDouble = rPar.Get( 1 )->GetDouble(); + aDouble = exp( aDouble ); + checkArithmeticOverflow( aDouble ); + rPar.Get( 0 )->PutDouble( aDouble ); + } +} + +RTLFUNC(FileLen) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxVariableRef pArg = rPar.Get( 1 ); + String aStr( pArg->GetString() ); + 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 = (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; + + ULONG nArgCount = rPar.Count()-1; + if ( nArgCount < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + USHORT nStartPos = 1; + + USHORT nFirstStringPos = 1; + if ( nArgCount >= 3 ) + { + INT32 lStartPos = rPar.Get(1)->GetLong(); + if( lStartPos <= 0 || lStartPos > 0xffff ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + lStartPos = 1; + } + nStartPos = (USHORT)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 ) : FALSE; + } + else + { + bTextMode = 1;; + } + if ( nArgCount == 4 ) + bTextMode = rPar.Get(4)->GetInteger(); + + USHORT 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; + + ULONG 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(); + + 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 ) : FALSE; + } + else + { + bTextMode = 1;; + } + if ( nArgCount == 4 ) + bTextMode = rPar.Get(4)->GetInteger(); + + USHORT nStrLen = aStr1.Len(); + USHORT nStartPos = lStartPos == -1 ? nStrLen : (USHORT)lStartPos; + + USHORT nPos = 0; + if( nStartPos <= nStrLen ) + { + USHORT 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 = (USHORT)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 = (USHORT)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() ); + INT32 lResultLen = rPar.Get(2)->GetLong(); + if( lResultLen > 0xffff ) + { + lResultLen = 0xffff; + } + else if( lResultLen < 0 ) + { + lResultLen = 0; + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } + aStr.Erase( (USHORT)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; + + ULONG 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 = TRUE; + + String aArgStr = rPar.Get(1)->GetString(); + USHORT nStartPos = (USHORT)(rPar.Get(2)->GetLong() ); + if ( nStartPos == 0 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + nStartPos--; + USHORT nLen = 0xffff; + bool bWriteNoLenParam = false; + if ( nArgCount == 3 || bWrite ) + { + INT32 n = rPar.Get(3)->GetLong(); + if( bWrite && n == -1 ) + bWriteNoLenParam = true; + nLen = (USHORT)n; + } + String aResultStr; + if ( bWrite ) + { + SbiInstance* pInst = pINST; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + USHORT nArgLen = aArgStr.Len(); + if( nStartPos + 1 > nArgLen ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aReplaceStr = rPar.Get(4)->GetString(); + USHORT nReplaceStrLen = aReplaceStr.Len(); + USHORT nReplaceLen; + if( bWriteNoLenParam ) + { + nReplaceLen = nReplaceStrLen; + } + else + { + nReplaceLen = nLen; + if( nReplaceLen > nReplaceStrLen ) + nReplaceLen = nReplaceStrLen; + } + + USHORT nReplaceEndPos = nStartPos + nReplaceLen; + if( nReplaceEndPos > nArgLen ) + nReplaceLen -= (nReplaceEndPos - nArgLen); + + aResultStr = aArgStr; + USHORT 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; + + ULONG 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(); + + 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; + } + } + + 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 ) : FALSE; + } + else + { + bTextMode = 1; + } + if ( nArgCount == 6 ) + bTextMode = rPar.Get(6)->GetInteger(); + + USHORT nExpStrLen = aExpStr.Len(); + USHORT nFindStrLen = aFindStr.Len(); + USHORT nReplaceStrLen = aReplaceStr.Len(); + + if( lStartPos <= nExpStrLen ) + { + USHORT nPos = static_cast<USHORT>( lStartPos - 1 ); + USHORT nCounts = 0; + while( lCount == -1 || lCount > nCounts ) + { + String aSrcStr( aExpStr ); + if( bTextMode ) + { + aSrcStr.ToUpperAscii(); + aFindStr.ToUpperAscii(); + } + nPos = aSrcStr.Search( aFindStr, nPos ); + if( nPos != STRING_NOTFOUND ) + { + aExpStr.Replace( nPos, nFindStrLen, aReplaceStr ); + nPos = nPos - nFindStrLen + nReplaceStrLen + 1; + nCounts++; + } + else + { + break; + } + } + } + rPar.Get(0)->PutString( aExpStr.Copy( static_cast<USHORT>(lStartPos - 1) ) ); + } +} + +RTLFUNC(Right) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 3 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + const String& rStr = rPar.Get(1)->GetString(); + INT32 lResultLen = rPar.Get(2)->GetLong(); + if( lResultLen > 0xffff ) + { + lResultLen = 0xffff; + } + else if( lResultLen < 0 ) + { + lResultLen = 0; + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } + USHORT nResultLen = (USHORT)lResultLen; + USHORT 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(); + 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( (USHORT)(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( (USHORT)(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] == '-' ); + USHORT iZeroSearch = 0; + if( bNeg ) + iZeroSearch++; + + USHORT 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; + INT16 nTextCompare; + bool bCompatibility = ( pInst && pInst->IsCompatibility() ); + if( bCompatibility ) + { + SbiRuntime* pRT = pInst ? pInst->pRun : NULL; + nTextCompare = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : FALSE; + } + else + { + nTextCompare = 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< INT16 >( nRetValue ) ); +} + +RTLFUNC(String) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr; + sal_Unicode aFiller; + INT32 lCount = rPar.Get(1)->GetLong(); + if( lCount < 0 || lCount > 0xffff ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + USHORT nCount = (USHORT)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( USHORT 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() ); + INT16 nlResult = (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 +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 += (ULONG)aDate; + } + else + { + aDate = ceil( aDate ); + aRefDate -= (ULONG)(-1.0 * aDate); + } + + INT16 nRet = (INT16)( aRefDate.GetDay() ); + return nRet; +} + +INT16 implGetDateMonth( double aDate ) +{ + Date aRefDate( 1,1,1900 ); + long nDays = (long)aDate; + nDays -= 2; // normieren: 1.1.1900 => 0.0 + aRefDate += nDays; + INT16 nRet = (INT16)( aRefDate.GetMonth() ); + return nRet; +} + +INT16 implGetDateYear( double aDate ) +{ + Date aRefDate( 1,1,1900 ); + long nDays = (long) aDate; + nDays -= 2; // normieren: 1.1.1900 => 0.0 + aRefDate += nDays; + INT16 nRet = (INT16)( aRefDate.GetYear() ); + return nRet; +} + +BOOL implDateSerial( INT16 nYear, INT16 nMonth, 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 FALSE; + } + if ( !SbiRuntime::isVBAEnabled() ) + { + if ( (nMonth < 1 || nMonth > 12 )|| + (nDay < 1 || nDay > 31 ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return 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 + 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 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(); + 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( (INT16)aYearStr.ToInt32(), + (INT16)aMonthStr.ToInt32(), (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; + } + INT16 nYear = rPar.Get(1)->GetInteger(); + INT16 nMonth = rPar.Get(2)->GetInteger(); + 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; + } + INT16 nHour = rPar.Get(1)->GetInteger(); + if ( nHour == 24 ) + nHour = 0; // Wegen UNO DateTimes, die bis 24 Uhr gehen + INT16 nMinute = rPar.Get(2)->GetInteger(); + 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; + } + + 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() ); + 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; + 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(); + + 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 + { + INT16 nYear = implGetDateYear( rPar.Get(1)->GetDate() ); + rPar.Get(0)->PutInteger( nYear ); + } +} + +INT16 implGetHour( double dDate ) +{ + if( dDate < 0.0 ) + dDate *= -1.0; + double nFrac = dDate - floor( dDate ); + nFrac *= 86400.0; + INT32 nSeconds = (INT32)(nFrac + 0.5); + INT16 nHour = (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(); + INT16 nHour = implGetHour( nArg ); + rPar.Get(0)->PutInteger( nHour ); + } +} + +INT16 implGetMinute( double dDate ) +{ + if( dDate < 0.0 ) + dDate *= -1.0; + double nFrac = dDate - floor( dDate ); + nFrac *= 86400.0; + INT32 nSeconds = (INT32)(nFrac + 0.5); + INT16 nTemp = (INT16)(nSeconds % 3600); + 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(); + 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 + { + INT16 nMonth = implGetDateMonth( rPar.Get(1)->GetDate() ); + rPar.Get(0)->PutInteger( nMonth ); + } +} + +INT16 implGetSecond( double dDate ) +{ + if( dDate < 0.0 ) + dDate *= -1.0; + double nFrac = dDate - floor( dDate ); + nFrac *= 86400.0; + INT32 nSeconds = (INT32)(nFrac + 0.5); + INT16 nTemp = (INT16)(nSeconds / 3600); + nSeconds -= nTemp * 3600; + nTemp = (INT16)(nSeconds / 60); + nSeconds -= nTemp * 60; + + INT16 nRet = (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(); + 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) ? TRUE : 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; + 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 FALSE + SbxVariableRef xArg = rPar.Get( 1 ); + SbxDataType eType = xArg->GetType(); + BOOL bDate = FALSE; + + if( eType == SbxDATE ) + { + bDate = 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 ); + BOOL bNull = rPar.Get(1)->IsNull(); + if( !bNull && pArg->GetType() == SbxOBJECT ) + { + SbxBase* pObj = pArg->GetObject(); + if( !pObj ) + bNull = 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 ); + BOOL bRoot = FALSE; + + // Check if it's a root directory + sal_Int32 nCount = aDirURLObj.getSegmentCount(); + + // No segment means Unix root directory "file:///" + if( nCount == 0 ) + { + bRoot = 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, TRUE, + INetURLObject::DECODE_WITH_CHARSET ); + if( aSeg1.getStr()[1] == (sal_Unicode)':' ) + { + bRoot = TRUE; + } + } + // More than one segments can never be root + // so bRoot remains FALSE + + return bRoot; +} + +RTLFUNC(Dir) +{ + (void)pBasic; + (void)bWrite; + + String aPath; + + USHORT 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 ); + } + + USHORT 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 ) + { + 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, 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; + } + USHORT 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 + USHORT 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 ); + + USHORT 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 ) + { + 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 ) + { + 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 = (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 + { + 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; + } + 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 + { + INT16 nChannel = rPar.Get(1)->GetInteger(); +// nChannel--; + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nChannel ); + if ( !pSbStrm ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + INT16 nRet; + if ( rPar.Get(2)->GetInteger() == 1 ) + nRet = (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 + { + 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(); + ULONG 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( (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 + { + 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(); + ULONG nOldPos = pSvStrm->Tell(); + ULONG nLen = pSvStrm->Seek( STREAM_SEEK_TO_END ); + pSvStrm->Seek( nOldPos ); + rPar.Get(0)->PutLong( (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; + } + 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 + { + ULONG nPos = pStrm->Tell(); + if( pSbStrm->IsRandom() ) + nPos = nPos / pSbStrm->GetBlockLen(); + nPos++; // Basic zaehlt ab 1 + rPar.Get(0)->PutLong( (INT32)nPos ); + } + else // Seek-Statement + { + 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( (ULONG)nPos ); + pSbStrm->SetExpandOnWriteTo( nPos ); + } +} + +RTLFUNC(Format) +{ + (void)pBasic; + (void)bWrite; + + USHORT nArgCount = (USHORT)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 ); + INT16 nSeed; + if( rPar.Count() == 2 ) + nSeed = (INT16)rPar.Get(1)->GetInteger(); + else + nSeed = (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 = 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; + } + + ULONG nArgCount = rPar.Count(); + if ( nArgCount < 2 || nArgCount > 5 ) + { + rPar.Get(0)->PutLong(0); + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + } + else + { + USHORT 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( " " ); + } + USHORT nLen = aCmdLine.Len(); + + // #55735 Wenn Parameter dabei sind, muessen die abgetrennt werden + // #72471 Auch die einzelnen Parameter trennen + std::list<String> aTokenList; + String aToken; + USHORT i = 0; + sal_Unicode c; + while( i < nLen ) + { + // Spaces weg + for ( ;; ++i ) + { + c = aCmdLine.GetBuffer()[ i ]; + if ( c != ' ' && c != '\t' ) + break; + } + + if( c == '\"' || c == '\'' ) + { + USHORT 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 + { + USHORT iFoundSpacePos = aCmdLine.Search( ' ', i ); + USHORT iFoundTabPos = aCmdLine.Search( '\t', i ); + USHORT 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 + + 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; + } + + BOOL bSync = 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++; + + USHORT nParamCount = sal::static_int_cast< USHORT >( + aTokenList.size() - 1 ); + ::rtl::OUString* pArgumentList = NULL; + //const char** pParamList = NULL; + if( nParamCount ) + { + pArgumentList = new ::rtl::OUString[ nParamCount ]; + //pParamList = new const char*[ nParamCount ]; + USHORT 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 ); + 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 ); + 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( (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; + USHORT 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(); + 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( (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(); + 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; + } + 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; + } + 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; + } + 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; + } + 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; + + USHORT 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 ) + { + 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; + + USHORT 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 ) + { + 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; + } + + ULONG nRed = rPar.Get(1)->GetInteger() & 0xFF; + ULONG nGreen = rPar.Get(2)->GetInteger() & 0xFF; + ULONG nBlue = rPar.Get(3)->GetInteger() & 0xFF; + ULONG 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 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; + } + + INT16 nCol = rPar.Get(1)->GetInteger(); + if( nCol < 0 || nCol > 15 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + INT32 nRGB = pRGB[ nCol ]; + rPar.Get(0)->PutLong( nRGB ); +} + +// StrConv(string, conversion, LCID) +RTLFUNC(StrConv) +{ + (void)pBasic; + (void)bWrite; + + ULONG nArgCount = rPar.Count()-1; + if( nArgCount < 2 || nArgCount > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aOldStr = rPar.Get(1)->GetString(); + INT32 nConversion = rPar.Get(2)->GetLong(); + + USHORT nLanguage = LANGUAGE_SYSTEM; + if( nArgCount == 3 ) + { + // LCID not supported now + //nLanguage = rPar.Get(3)->GetInteger(); + } + + USHORT nOldLen = aOldStr.Len(); + if( nOldLen == 0 ) + { + // null string,return + rPar.Get(0)->PutString(aOldStr); + return; + } + + 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) + USHORT nSize = aNewStr.Len()*2; + const sal_Unicode* pSrc = aNewStr.GetBuffer(); + sal_Char* pChar = new sal_Char[nSize+1]; + for( USHORT 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(); + USHORT nArraySize = static_cast< USHORT >( 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( USHORT 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); + USHORT nFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->PutObject( pArray ); + refVar->SetFlags( nFlags ); + refVar->SetParameters( NULL ); + return; + } + + rPar.Get(0)->PutString(aNewStr); +} + + +RTLFUNC(Beep) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + Sound::Beep(); +} + +RTLFUNC(Load) +{ + (void)pBasic; + (void)bWrite; + + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // Diesen Call einfach an das Object weiterreichen + SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject(); + if ( pObj ) + { + if( pObj->IsA( TYPE( SbUserFormModule ) ) ) + { + ((SbUserFormModule*)pObj)->Load(); + } + else if( pObj->IsA( TYPE( SbxObject ) ) ) + { + SbxVariable* pVar = ((SbxObject*)pObj)-> + Find( String( RTL_CONSTASCII_USTRINGPARAM("Load") ), SbxCLASS_METHOD ); + if( pVar ) + pVar->GetInteger(); + } + } +} + +RTLFUNC(Unload) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // Diesen Call einfach an das Object weitereichen + SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject(); + if ( pObj ) + { + if( pObj->IsA( TYPE( SbUserFormModule ) ) ) + { + SbUserFormModule* pFormModule = ( SbUserFormModule* )pObj; + pFormModule->Unload(); + } + else if( pObj->IsA( TYPE( SbxObject ) ) ) + { + SbxVariable* pVar = ((SbxObject*)pObj)-> + Find( String( RTL_CONSTASCII_USTRINGPARAM("Unload") ), SbxCLASS_METHOD ); + if( pVar ) + pVar->GetInteger(); + } + } +} + +RTLFUNC(LoadPicture) +{ + (void)pBasic; + (void)bWrite; + + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aFileURL = getFullPath( rPar.Get(1)->GetString() ); + SvStream* pStream = utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_READ ); + if( pStream != NULL ) + { + Bitmap aBmp; + *pStream >> aBmp; + Graphic aGraphic( aBmp ); + + SbxObjectRef xRef = new SbStdPicture; + ((SbStdPicture*)(SbxObject*)xRef)->SetGraphic( aGraphic ); + rPar.Get(0)->PutObject( xRef ); + } + delete pStream; +} + +RTLFUNC(SavePicture) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if( rPar.Count() != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject(); + if( pObj->IsA( TYPE( SbStdPicture ) ) ) + { + SvFileStream aOStream( rPar.Get(2)->GetString(), STREAM_WRITE | STREAM_TRUNC ); + Graphic aGraphic = ((SbStdPicture*)pObj)->GetGraphic(); + aOStream << aGraphic; + } +} + + +//----------------------------------------------------------------------------------------- + +RTLFUNC(AboutStarBasic) +{ + (void)pBasic; + (void)bWrite; + (void)rPar; +} + +RTLFUNC(MsgBox) +{ + (void)pBasic; + (void)bWrite; + + static const WinBits nStyleMap[] = + { + WB_OK, // MB_OK + WB_OK_CANCEL, // MB_OKCANCEL + WB_ABORT_RETRY_IGNORE, // MB_ABORTRETRYIGNORE + WB_YES_NO_CANCEL, // MB_YESNOCANCEL + WB_YES_NO, // MB_YESNO + WB_RETRY_CANCEL // MB_RETRYCANCEL + }; + static const INT16 nButtonMap[] = + { + 2, // #define RET_CANCEL FALSE + 1, // #define RET_OK TRUE + 6, // #define RET_YES 2 + 7, // #define RET_NO 3 + 4 // #define RET_RETRY 4 + }; + + + USHORT nArgCount = (USHORT)rPar.Count(); + if( nArgCount < 2 || nArgCount > 6 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + WinBits nWinBits; + WinBits nType = 0; // MB_OK + if( nArgCount >= 3 ) + nType = (WinBits)rPar.Get(2)->GetInteger(); + WinBits nStyle = nType; + nStyle &= 15; // Bits 4-16 loeschen + if( nStyle > 5 ) + nStyle = 0; + + nWinBits = nStyleMap[ nStyle ]; + + WinBits nWinDefBits; + nWinDefBits = (WB_DEF_OK | WB_DEF_RETRY | WB_DEF_YES); + if( nType & 256 ) + { + if( nStyle == 5 ) + nWinDefBits = WB_DEF_CANCEL; + else if( nStyle == 2 ) + nWinDefBits = WB_DEF_RETRY; + else + nWinDefBits = (WB_DEF_CANCEL | WB_DEF_RETRY | WB_DEF_NO); + } + else if( nType & 512 ) + { + if( nStyle == 2) + nWinDefBits = WB_DEF_IGNORE; + else + nWinDefBits = WB_DEF_CANCEL; + } + else if( nStyle == 2) + nWinDefBits = WB_DEF_CANCEL; + nWinBits |= nWinDefBits; + + String aMsg = rPar.Get(1)->GetString(); + String aTitle; + if( nArgCount >= 4 ) + aTitle = rPar.Get(3)->GetString(); + else + aTitle = GetpApp()->GetAppName(); + + nType &= (16+32+64); + MessBox* pBox = 0; + Window* pParent = GetpApp()->GetDefDialogParent(); + switch( nType ) + { + case 16: + pBox = new ErrorBox( pParent, nWinBits, aMsg ); + break; + case 32: + pBox = new QueryBox( pParent, nWinBits, aMsg ); + break; + case 48: + pBox = new WarningBox( pParent, nWinBits, aMsg ); + break; + case 64: + pBox = new InfoBox( pParent, aMsg ); + break; + default: + pBox = new MessBox( pParent, nWinBits, aTitle, aMsg ); + } + pBox->SetText( aTitle ); + USHORT nRet = (USHORT)pBox->Execute(); + if( nRet == TRUE ) + nRet = 1; + + 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(); + 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; + + USHORT nArgCount = (USHORT)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(); + BOOL bExists = 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; + } + + INT32 nNumber = rPar.Get(1)->GetLong(); + INT32 nStart = rPar.Get(2)->GetLong(); + INT32 nStop = rPar.Get(3)->GetLong(); + 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 ); + INT32 nLen1 = aBeforeStart.getLength(); + INT32 nLen2 = aAfterStop.getLength(); + 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 + { + INT32 nLowerValue = nNumber; + 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 ( INT32 i= (nLen - nLen1) ; i > 0; --i ) + aRetStr.appendAscii(" "); + } + aRetStr.append( aLowerValue ).appendAscii(":"); + if( nLen > nLen2 ) + { + // appending the leading spaces for the uppervalue + for ( INT32 i= (nLen - nLen2) ; i > 0; --i ) + aRetStr.appendAscii(" "); + } + aRetStr.append( aUpperValue ); + rPar.Get(0)->PutString( String(aRetStr.makeStringAndClear()) ); +} diff --git a/basic/source/runtime/methods1.cxx b/basic/source/runtime/methods1.cxx new file mode 100755 index 000000000000..6b955fed3d8a --- /dev/null +++ b/basic/source/runtime/methods1.cxx @@ -0,0 +1,2715 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include <stdlib.h> // getenv +#include <vcl/svapp.hxx> +#include <vcl/mapmod.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/timer.hxx> +#include <basic/sbxvar.hxx> +#ifndef _SBX_HXX +#include <basic/sbx.hxx> +#endif +#include <svl/zforlist.hxx> +#include <tools/fsys.hxx> +#include <tools/urlobj.hxx> +#include <osl/file.hxx> + +#ifdef OS2 +#define INCL_DOS +#define INCL_DOSPROCESS +#include <svpm.h> +#endif + +#ifndef CLK_TCK +#define CLK_TCK CLOCKS_PER_SEC +#endif + +#include <vcl/jobset.hxx> +#include <basic/sbobjmod.hxx> + +#include "sbintern.hxx" +#include "runtime.hxx" +#include "stdobj.hxx" +#include "rtlproto.hxx" +#include "dllmgr.hxx" +#include <iosys.hxx> +#include "sbunoobj.hxx" +#include "propacc.hxx" + + +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/XCalendar.hpp> + +using namespace comphelper; +using namespace com::sun::star::uno; +using namespace com::sun::star::i18n; + + +static Reference< XCalendar > getLocaleCalendar( void ) +{ + static Reference< XCalendar > xCalendar; + if( !xCalendar.is() ) + { + Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory(); + if( xSMgr.is() ) + { + xCalendar = Reference< XCalendar >( xSMgr->createInstance + ( ::rtl::OUString::createFromAscii( "com.sun.star.i18n.LocaleCalendar" ) ), UNO_QUERY ); + } + } + + static com::sun::star::lang::Locale aLastLocale; + static bool bNeedsInit = true; + + com::sun::star::lang::Locale aLocale = Application::GetSettings().GetLocale(); + bool bNeedsReload = false; + if( bNeedsInit ) + { + bNeedsInit = false; + bNeedsReload = true; + } + else if( aLocale.Language != aLastLocale.Language || + aLocale.Country != aLastLocale.Country ) + { + bNeedsReload = true; + } + if( bNeedsReload ) + { + aLastLocale = aLocale; + xCalendar->loadDefaultCalendar( aLocale ); + } + return xCalendar; +} + +RTLFUNC(CallByName) +{ + (void)pBasic; + (void)bWrite; + + const INT16 vbGet = 2; + const INT16 vbLet = 4; + const INT16 vbMethod = 1; + const INT16 vbSet = 8; + + // At least 3 parameter needed plus function itself -> 4 + USHORT nParCount = rPar.Count(); + if ( nParCount < 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // 1. parameter is object + SbxBase* pObjVar = (SbxObject*)rPar.Get(1)->GetObject(); + SbxObject* pObj = NULL; + if( pObjVar ) + pObj = PTR_CAST(SbxObject,pObjVar); + if( !pObj && pObjVar && pObjVar->ISA(SbxVariable) ) + { + SbxBase* pObjVarObj = ((SbxVariable*)pObjVar)->GetObject(); + pObj = PTR_CAST(SbxObject,pObjVarObj); + } + if( !pObj ) + { + StarBASIC::Error( SbERR_BAD_PARAMETER ); + return; + } + + // 2. parameter is ProcedureName + String aNameStr = rPar.Get(2)->GetString(); + + // 3. parameter is CallType + INT16 nCallType = rPar.Get(3)->GetInteger(); + + //SbxObject* pFindObj = NULL; + SbxVariable* pFindVar = pObj->Find( aNameStr, SbxCLASS_DONTCARE ); + if( pFindVar == NULL ) + { + StarBASIC::Error( SbERR_PROC_UNDEFINED ); + return; + } + + switch( nCallType ) + { + case vbGet: + { + SbxValues aVals; + aVals.eType = SbxVARIANT; + pFindVar->Get( aVals ); + + SbxVariableRef refVar = rPar.Get(0); + refVar->Put( aVals ); + } + break; + case vbLet: + case vbSet: + { + if ( nParCount != 5 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + SbxVariableRef pValVar = rPar.Get(4); + if( nCallType == vbLet ) + { + SbxValues aVals; + aVals.eType = SbxVARIANT; + pValVar->Get( aVals ); + pFindVar->Put( aVals ); + } + else + { + SbxVariableRef rFindVar = pFindVar; + SbiInstance* pInst = pINST; + SbiRuntime* pRT = pInst ? pInst->pRun : NULL; + if( pRT != NULL ) + pRT->StepSET_Impl( pValVar, rFindVar, false ); + } + } + break; + case vbMethod: + { + SbMethod* pMeth = PTR_CAST(SbMethod,pFindVar); + if( pMeth == NULL ) + { + StarBASIC::Error( SbERR_PROC_UNDEFINED ); + return; + } + + // Setup parameters + SbxArrayRef xArray; + USHORT nMethParamCount = nParCount - 4; + if( nMethParamCount > 0 ) + { + xArray = new SbxArray; + for( USHORT i = 0 ; i < nMethParamCount ; i++ ) + { + SbxVariable* pPar = rPar.Get( i + 4 ); + xArray->Put( pPar, i + 1 ); + } + } + + // Call method + SbxVariableRef refVar = rPar.Get(0); + if( xArray.Is() ) + pMeth->SetParameters( xArray ); + pMeth->Call( refVar ); + pMeth->SetParameters( NULL ); + } + break; + default: + StarBASIC::Error( SbERR_PROC_UNDEFINED ); + } +} + +RTLFUNC(CBool) // JSM +{ + (void)pBasic; + (void)bWrite; + + BOOL bVal = FALSE; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + bVal = pSbxVariable->GetBool(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutBool(bVal); +} + +RTLFUNC(CByte) // JSM +{ + (void)pBasic; + (void)bWrite; + + BYTE nByte = 0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + nByte = pSbxVariable->GetByte(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutByte(nByte); +} + +RTLFUNC(CCur) // JSM +{ + (void)pBasic; + (void)bWrite; + + SbxINT64 nCur; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + nCur = pSbxVariable->GetCurrency(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutCurrency( nCur ); +} + +RTLFUNC(CDec) // JSM +{ + (void)pBasic; + (void)bWrite; + +#ifdef WNT + SbxDecimal* pDec = NULL; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + pDec = pSbxVariable->GetDecimal(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutDecimal( pDec ); +#else + rPar.Get(0)->PutEmpty(); + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); +#endif +} + +RTLFUNC(CDate) // JSM +{ + (void)pBasic; + (void)bWrite; + + double nVal = 0.0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + nVal = pSbxVariable->GetDate(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutDate(nVal); +} + +RTLFUNC(CDbl) // JSM +{ + (void)pBasic; + (void)bWrite; + + double nVal = 0.0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + if( pSbxVariable->GetType() == SbxSTRING ) + { + // AB #41690 , String holen + String aScanStr = pSbxVariable->GetString(); + SbError Error = SbxValue::ScanNumIntnl( aScanStr, nVal ); + if( Error != SbxERR_OK ) + StarBASIC::Error( Error ); + } + else + { + nVal = pSbxVariable->GetDouble(); + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutDouble(nVal); +} + +RTLFUNC(CInt) // JSM +{ + (void)pBasic; + (void)bWrite; + + INT16 nVal = 0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + nVal = pSbxVariable->GetInteger(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutInteger(nVal); +} + +RTLFUNC(CLng) // JSM +{ + (void)pBasic; + (void)bWrite; + + INT32 nVal = 0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + nVal = pSbxVariable->GetLong(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutLong(nVal); +} + +RTLFUNC(CSng) // JSM +{ + (void)pBasic; + (void)bWrite; + + float nVal = (float)0.0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + if( pSbxVariable->GetType() == SbxSTRING ) + { + // AB #41690 , String holen + double dVal = 0.0; + String aScanStr = pSbxVariable->GetString(); + SbError Error = SbxValue::ScanNumIntnl( aScanStr, dVal, /*bSingle=*/TRUE ); + if( SbxBase::GetError() == SbxERR_OK && Error != SbxERR_OK ) + StarBASIC::Error( Error ); + nVal = (float)dVal; + } + else + { + nVal = pSbxVariable->GetSingle(); + } + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutSingle(nVal); +} + +RTLFUNC(CStr) // JSM +{ + (void)pBasic; + (void)bWrite; + + String aString; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + aString = pSbxVariable->GetString(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutString(aString); +} + +RTLFUNC(CVar) // JSM +{ + (void)pBasic; + (void)bWrite; + + SbxValues aVals( SbxVARIANT ); + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + pSbxVariable->Get( aVals ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->Put( aVals ); +} + +RTLFUNC(CVErr) +{ + (void)pBasic; + (void)bWrite; + + INT16 nErrCode = 0; + if ( rPar.Count() == 2 ) + { + SbxVariable *pSbxVariable = rPar.Get(1); + nErrCode = pSbxVariable->GetInteger(); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + rPar.Get(0)->PutErr( nErrCode ); +} + +RTLFUNC(Iif) // JSM +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 4 ) + { + if (rPar.Get(1)->GetBool()) + *rPar.Get(0) = *rPar.Get(2); + else + *rPar.Get(0) = *rPar.Get(3); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(GetSystemType) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + // Removed for SRC595 + rPar.Get(0)->PutInteger( -1 ); +} + +RTLFUNC(GetGUIType) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // 17.7.2000 Make simple solution for testtool / fat office +#if defined (WNT) + rPar.Get(0)->PutInteger( 1 ); +#elif defined OS2 + rPar.Get(0)->PutInteger( 2 ); +#elif defined UNX + rPar.Get(0)->PutInteger( 4 ); +#else + rPar.Get(0)->PutInteger( -1 ); +#endif + } +} + +RTLFUNC(Red) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + ULONG nRGB = (ULONG)rPar.Get(1)->GetLong(); + nRGB &= 0x00FF0000; + nRGB >>= 16; + rPar.Get(0)->PutInteger( (INT16)nRGB ); + } +} + +RTLFUNC(Green) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + ULONG nRGB = (ULONG)rPar.Get(1)->GetLong(); + nRGB &= 0x0000FF00; + nRGB >>= 8; + rPar.Get(0)->PutInteger( (INT16)nRGB ); + } +} + +RTLFUNC(Blue) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + ULONG nRGB = (ULONG)rPar.Get(1)->GetLong(); + nRGB &= 0x000000FF; + rPar.Get(0)->PutInteger( (INT16)nRGB ); + } +} + + +RTLFUNC(Switch) +{ + (void)pBasic; + (void)bWrite; + + USHORT nCount = rPar.Count(); + if( !(nCount & 0x0001 )) + // Anzahl der Argumente muss ungerade sein + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + USHORT nCurExpr = 1; + while( nCurExpr < (nCount-1) ) + { + if( rPar.Get( nCurExpr )->GetBool()) + { + (*rPar.Get(0)) = *(rPar.Get(nCurExpr+1)); + return; + } + nCurExpr += 2; + } + rPar.Get(0)->PutNull(); +} + +//i#64882# Common wait impl for existing Wait and new WaitUntil +// rtl functions +void Wait_Impl( bool bDurationBased, SbxArray& rPar ) +{ + if( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + long nWait = 0; + if ( bDurationBased ) + { + double dWait = rPar.Get(1)->GetDouble(); + double dNow = Now_Impl(); + double dSecs = (double)( ( dWait - dNow ) * (double)( 24.0*3600.0) ); + nWait = (long)( dSecs * 1000 ); // wait in thousands of sec + } + else + nWait = rPar.Get(1)->GetLong(); + if( nWait < 0 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + Timer aTimer; + aTimer.SetTimeout( nWait ); + aTimer.Start(); + while ( aTimer.IsActive() ) + Application::Yield(); +} + +//i#64882# +RTLFUNC(Wait) +{ + (void)pBasic; + (void)bWrite; + Wait_Impl( false, rPar ); +} + +//i#64882# add new WaitUntil ( for application.wait ) +// share wait_impl with 'normal' oobasic wait +RTLFUNC(WaitUntil) +{ + (void)pBasic; + (void)bWrite; + Wait_Impl( true, rPar ); +} + +RTLFUNC(DoEvents) +{ + (void)pBasic; + (void)bWrite; + (void)rPar; + // Dummy implementation as the following code leads + // to performance problems for unknown reasons + //Timer aTimer; + //aTimer.SetTimeout( 1 ); + //aTimer.Start(); + //while ( aTimer.IsActive() ) + // Application::Reschedule(); + Application::Reschedule( true ); +} + +RTLFUNC(GetGUIVersion) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + // Removed for SRC595 + rPar.Get(0)->PutLong( -1 ); + } +} + +RTLFUNC(Choose) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + INT16 nIndex = rPar.Get(1)->GetInteger(); + USHORT nCount = rPar.Count(); + nCount--; + if( nCount == 1 || nIndex > (nCount-1) || nIndex < 1 ) + { + rPar.Get(0)->PutNull(); + return; + } + (*rPar.Get(0)) = *(rPar.Get(nIndex+1)); +} + + +RTLFUNC(Trim) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + String aStr( rPar.Get(1)->GetString() ); + aStr.EraseLeadingChars(); + aStr.EraseTrailingChars(); + rPar.Get(0)->PutString( aStr ); + } +} + +RTLFUNC(GetSolarVersion) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutLong( (INT32)SUPD ); +} + +RTLFUNC(TwipsPerPixelX) +{ + (void)pBasic; + (void)bWrite; + + INT32 nResult = 0; + Size aSize( 100,0 ); + MapMode aMap( MAP_TWIP ); + OutputDevice* pDevice = Application::GetDefaultDevice(); + if( pDevice ) + { + aSize = pDevice->PixelToLogic( aSize, aMap ); + nResult = aSize.Width() / 100; + } + rPar.Get(0)->PutLong( nResult ); +} + +RTLFUNC(TwipsPerPixelY) +{ + (void)pBasic; + (void)bWrite; + + INT32 nResult = 0; + Size aSize( 0,100 ); + MapMode aMap( MAP_TWIP ); + OutputDevice* pDevice = Application::GetDefaultDevice(); + if( pDevice ) + { + aSize = pDevice->PixelToLogic( aSize, aMap ); + nResult = aSize.Height() / 100; + } + rPar.Get(0)->PutLong( nResult ); +} + + +RTLFUNC(FreeLibrary) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + pINST->GetDllMgr()->FreeDll( rPar.Get(1)->GetString() ); +} +bool IsBaseIndexOne() +{ + bool result = false; + if ( pINST && pINST->pRun ) + { + USHORT res = pINST->pRun->GetBase(); + if ( res ) + result = true; + } + return result; +} + +RTLFUNC(Array) +{ + (void)pBasic; + (void)bWrite; + + SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); + USHORT nArraySize = rPar.Count() - 1; + + // Option Base zunaechst ignorieren (kennt leider nur der Compiler) + bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() ); + if( nArraySize ) + { + if ( bIncIndex ) + pArray->AddDim( 1, nArraySize ); + else + pArray->AddDim( 0, nArraySize-1 ); + } + else + { + pArray->unoAddDim( 0, -1 ); + } + + // Parameter ins Array uebernehmen + // ATTENTION: Using type USHORT for loop variable is + // mandatory to workaround a problem with the + // Solaris Intel compiler optimizer! See i104354 + for( USHORT i = 0 ; i < nArraySize ; i++ ) + { + SbxVariable* pVar = rPar.Get(i+1); + SbxVariable* pNew = new SbxVariable( *pVar ); + pNew->SetFlag( SBX_WRITE ); + short index = static_cast< short >(i); + if ( bIncIndex ) + ++index; + pArray->Put( pNew, &index ); + } + + // Array zurueckliefern + SbxVariableRef refVar = rPar.Get(0); + USHORT nFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->PutObject( pArray ); + refVar->SetFlags( nFlags ); + refVar->SetParameters( NULL ); +} + + +// Featurewunsch #57868 +// Die Funktion liefert ein Variant-Array, wenn keine Parameter angegeben +// werden, wird ein leeres Array erzeugt (entsprechend dim a(), entspricht +// einer Sequence der Laenge 0 in Uno). +// Wenn Parameter angegeben sind, wird fuer jeden eine Dimension erzeugt +// DimArray( 2, 2, 4 ) entspricht DIM a( 2, 2, 4 ) +// Das Array ist immer vom Typ Variant +RTLFUNC(DimArray) +{ + (void)pBasic; + (void)bWrite; + + SbxDimArray * pArray = new SbxDimArray( SbxVARIANT ); + USHORT nArrayDims = rPar.Count() - 1; + if( nArrayDims > 0 ) + { + for( USHORT i = 0; i < nArrayDims ; i++ ) + { + INT32 ub = rPar.Get(i+1)->GetLong(); + if( ub < 0 ) + { + StarBASIC::Error( SbERR_OUT_OF_RANGE ); + ub = 0; + } + pArray->AddDim32( 0, ub ); + } + } + else + pArray->unoAddDim( 0, -1 ); + + // Array zurueckliefern + SbxVariableRef refVar = rPar.Get(0); + USHORT nFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->PutObject( pArray ); + refVar->SetFlags( nFlags ); + refVar->SetParameters( NULL ); +} + +/* + * FindObject und FindPropertyObject ermoeglichen es, + * Objekte und Properties vom Typ Objekt zur Laufzeit + * ueber ihren Namen als String-Parameter anzusprechen. + * + * Bsp.: + * MyObj.Prop1.Bla = 5 + * + * entspricht: + * dim ObjVar as Object + * dim ObjProp as Object + * ObjName$ = "MyObj" + * ObjVar = FindObject( ObjName$ ) + * PropName$ = "Prop1" + * ObjProp = FindPropertyObject( ObjVar, PropName$ ) + * ObjProp.Bla = 5 + * + * Dabei koennen die Namen zur Laufzeit dynamisch + * erzeugt werden und, so dass z.B. ueber Controls + * "TextEdit1" bis "TextEdit5" in einem Dialog in + * einer Schleife iteriert werden kann. + */ + +// Objekt ueber den Namen ansprechen +// 1. Parameter = Name des Objekts als String +RTLFUNC(FindObject) +{ + (void)pBasic; + (void)bWrite; + + // Wir brauchen einen Parameter + if ( rPar.Count() < 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // 1. Parameter ist der Name + String aNameStr = rPar.Get(1)->GetString(); + + // Basic-Suchfunktion benutzen + SbxBase* pFind = StarBASIC::FindSBXInCurrentScope( aNameStr ); + SbxObject* pFindObj = NULL; + if( pFind ) + pFindObj = PTR_CAST(SbxObject,pFind); + /* + if( !pFindObj ) + { + StarBASIC::Error( SbERR_VAR_UNDEFINED ); + return; + } + */ + + // Objekt zurueckliefern + SbxVariableRef refVar = rPar.Get(0); + refVar->PutObject( pFindObj ); +} + +// Objekt-Property in einem Objekt ansprechen +// 1. Parameter = Objekt +// 2. Parameter = Name der Property als String +RTLFUNC(FindPropertyObject) +{ + (void)pBasic; + (void)bWrite; + + // Wir brauchen 2 Parameter + if ( rPar.Count() < 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + // 1. Parameter holen, muss Objekt sein + SbxBase* pObjVar = (SbxObject*)rPar.Get(1)->GetObject(); + SbxObject* pObj = NULL; + if( pObjVar ) + pObj = PTR_CAST(SbxObject,pObjVar); + if( !pObj && pObjVar && pObjVar->ISA(SbxVariable) ) + { + SbxBase* pObjVarObj = ((SbxVariable*)pObjVar)->GetObject(); + pObj = PTR_CAST(SbxObject,pObjVarObj); + } + /* + if( !pObj ) + { + StarBASIC::Error( SbERR_VAR_UNDEFINED ); + return; + } + */ + + // 2. Parameter ist der Name + String aNameStr = rPar.Get(2)->GetString(); + + // Jetzt muss ein Objekt da sein, sonst Error + SbxObject* pFindObj = NULL; + if( pObj ) + { + // Im Objekt nach Objekt suchen + SbxVariable* pFindVar = pObj->Find( aNameStr, SbxCLASS_OBJECT ); + pFindObj = PTR_CAST(SbxObject,pFindVar); + } + else + StarBASIC::Error( SbERR_BAD_PARAMETER ); + + // Objekt zurueckliefern + SbxVariableRef refVar = rPar.Get(0); + refVar->PutObject( pFindObj ); +} + + + +BOOL lcl_WriteSbxVariable( const SbxVariable& rVar, SvStream* pStrm, + BOOL bBinary, short nBlockLen, BOOL bIsArray ) +{ + ULONG nFPos = pStrm->Tell(); + + BOOL bIsVariant = !rVar.IsFixed(); + SbxDataType eType = rVar.GetType(); + + switch( eType ) + { + case SbxBOOL: + case SbxCHAR: + case SbxBYTE: + if( bIsVariant ) + *pStrm << (USHORT)SbxBYTE; // VarType Id + *pStrm << rVar.GetByte(); + break; + + case SbxEMPTY: + case SbxNULL: + case SbxVOID: + case SbxINTEGER: + case SbxUSHORT: + case SbxINT: + case SbxUINT: + if( bIsVariant ) + *pStrm << (USHORT)SbxINTEGER; // VarType Id + *pStrm << rVar.GetInteger(); + break; + + case SbxLONG: + case SbxULONG: + case SbxLONG64: + case SbxULONG64: + if( bIsVariant ) + *pStrm << (USHORT)SbxLONG; // VarType Id + *pStrm << rVar.GetLong(); + break; + + case SbxSINGLE: + if( bIsVariant ) + *pStrm << (USHORT)eType; // VarType Id + *pStrm << rVar.GetSingle(); + break; + + case SbxDOUBLE: + case SbxCURRENCY: + case SbxDATE: + if( bIsVariant ) + *pStrm << (USHORT)eType; // VarType Id + *pStrm << rVar.GetDouble(); + break; + + case SbxSTRING: + case SbxLPSTR: + { + const String& rStr = rVar.GetString(); + if( !bBinary || bIsArray ) + { + if( bIsVariant ) + *pStrm << (USHORT)SbxSTRING; + pStrm->WriteByteString( rStr, gsl_getSystemTextEncoding() ); + //*pStrm << rStr; + } + else + { + // ohne Laengenangabe! ohne Endekennung! + // What does that mean for Unicode?! Choosing conversion to ByteString... + ByteString aByteStr( rStr, gsl_getSystemTextEncoding() ); + *pStrm << (const char*)aByteStr.GetBuffer(); + //*pStrm << (const char*)rStr.GetStr(); + } + } + break; + + default: + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return FALSE; + } + + if( nBlockLen ) + pStrm->Seek( nFPos + nBlockLen ); + return pStrm->GetErrorCode() ? FALSE : TRUE; +} + +BOOL lcl_ReadSbxVariable( SbxVariable& rVar, SvStream* pStrm, + BOOL bBinary, short nBlockLen, BOOL bIsArray ) +{ + (void)bBinary; + (void)bIsArray; + + double aDouble; + + ULONG nFPos = pStrm->Tell(); + + BOOL bIsVariant = !rVar.IsFixed(); + SbxDataType eVarType = rVar.GetType(); + + SbxDataType eSrcType = eVarType; + if( bIsVariant ) + { + USHORT nTemp; + *pStrm >> nTemp; + eSrcType = (SbxDataType)nTemp; + } + + switch( eSrcType ) + { + case SbxBOOL: + case SbxCHAR: + case SbxBYTE: + { + BYTE aByte; + *pStrm >> aByte; + rVar.PutByte( aByte ); + } + break; + + case SbxEMPTY: + case SbxNULL: + case SbxVOID: + case SbxINTEGER: + case SbxUSHORT: + case SbxINT: + case SbxUINT: + { + INT16 aInt; + *pStrm >> aInt; + rVar.PutInteger( aInt ); + } + break; + + case SbxLONG: + case SbxULONG: + case SbxLONG64: + case SbxULONG64: + { + INT32 aInt; + *pStrm >> aInt; + rVar.PutLong( aInt ); + } + break; + + case SbxSINGLE: + { + float nS; + *pStrm >> nS; + rVar.PutSingle( nS ); + } + break; + + case SbxDOUBLE: + case SbxCURRENCY: + { + *pStrm >> aDouble; + rVar.PutDouble( aDouble ); + } + break; + + case SbxDATE: + { + *pStrm >> aDouble; + rVar.PutDate( aDouble ); + } + break; + + case SbxSTRING: + case SbxLPSTR: + { + String aStr; + pStrm->ReadByteString( aStr, gsl_getSystemTextEncoding() ); + rVar.PutString( aStr ); + } + break; + + default: + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return FALSE; + } + + if( nBlockLen ) + pStrm->Seek( nFPos + nBlockLen ); + return pStrm->GetErrorCode() ? FALSE : TRUE; +} + + +// nCurDim = 1...n +BOOL lcl_WriteReadSbxArray( SbxDimArray& rArr, SvStream* pStrm, + BOOL bBinary, short nCurDim, short* pOtherDims, BOOL bWrite ) +{ + DBG_ASSERT( nCurDim > 0,"Bad Dim"); + short nLower, nUpper; + if( !rArr.GetDim( nCurDim, nLower, nUpper ) ) + return FALSE; + for( short nCur = nLower; nCur <= nUpper; nCur++ ) + { + pOtherDims[ nCurDim-1 ] = nCur; + if( nCurDim != 1 ) + lcl_WriteReadSbxArray(rArr, pStrm, bBinary, nCurDim-1, pOtherDims, bWrite); + else + { + SbxVariable* pVar = rArr.Get( (const short*)pOtherDims ); + BOOL bRet; + if( bWrite ) + bRet = lcl_WriteSbxVariable(*pVar, pStrm, bBinary, 0, TRUE ); + else + bRet = lcl_ReadSbxVariable(*pVar, pStrm, bBinary, 0, TRUE ); + if( !bRet ) + return FALSE; + } + } + return TRUE; +} + +void PutGet( SbxArray& rPar, BOOL bPut ) +{ + // Wir brauchen 3 Parameter + if ( rPar.Count() != 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + INT16 nFileNo = rPar.Get(1)->GetInteger(); + SbxVariable* pVar2 = rPar.Get(2); + BOOL bHasRecordNo = (BOOL)(pVar2->GetType() != SbxEMPTY); + long nRecordNo = pVar2->GetLong(); + if ( nFileNo < 1 || ( bHasRecordNo && nRecordNo < 1 ) ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + nRecordNo--; // wir moegen's ab 0! + SbiIoSystem* pIO = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIO->GetStream( nFileNo ); + // das File muss Random (feste Record-Laenge) oder Binary sein + if ( !pSbStrm || !(pSbStrm->GetMode() & (SBSTRM_BINARY | SBSTRM_RANDOM)) ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + + SvStream* pStrm = pSbStrm->GetStrm(); + BOOL bRandom = pSbStrm->IsRandom(); + short nBlockLen = bRandom ? pSbStrm->GetBlockLen() : 0; + + if( bPut ) + { + // Datei aufplustern, falls jemand uebers Dateiende hinaus geseekt hat + pSbStrm->ExpandFile(); + } + + // auf die Startposition seeken + if( bHasRecordNo ) + { + ULONG nFilePos = bRandom ? (ULONG)(nBlockLen*nRecordNo) : (ULONG)nRecordNo; + pStrm->Seek( nFilePos ); + } + + SbxDimArray* pArr = 0; + SbxVariable* pVar = rPar.Get(3); + if( pVar->GetType() & SbxARRAY ) + { + SbxBase* pParObj = pVar->GetObject(); + pArr = PTR_CAST(SbxDimArray,pParObj); + } + + BOOL bRet; + + if( pArr ) + { + ULONG nFPos = pStrm->Tell(); + short nDims = pArr->GetDims(); + short* pDims = new short[ nDims ]; + bRet = lcl_WriteReadSbxArray(*pArr,pStrm,!bRandom,nDims,pDims,bPut); + delete [] pDims; + if( nBlockLen ) + pStrm->Seek( nFPos + nBlockLen ); + } + else + { + if( bPut ) + bRet = lcl_WriteSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, FALSE); + else + bRet = lcl_ReadSbxVariable(*pVar, pStrm, !bRandom, nBlockLen, FALSE); + } + if( !bRet || pStrm->GetErrorCode() ) + StarBASIC::Error( SbERR_IO_ERROR ); +} + +RTLFUNC(Put) +{ + (void)pBasic; + (void)bWrite; + + PutGet( rPar, TRUE ); +} + +RTLFUNC(Get) +{ + (void)pBasic; + (void)bWrite; + + PutGet( rPar, FALSE ); +} + +RTLFUNC(Environ) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + String aResult; + // sollte ANSI sein, aber unter Win16 in DLL nicht moeglich + ByteString aByteStr( rPar.Get(1)->GetString(), gsl_getSystemTextEncoding() ); + const char* pEnvStr = getenv( aByteStr.GetBuffer() ); + if ( pEnvStr ) + aResult = String::CreateFromAscii( pEnvStr ); + rPar.Get(0)->PutString( aResult ); +} + +static double GetDialogZoomFactor( BOOL bX, long nValue ) +{ + OutputDevice* pDevice = Application::GetDefaultDevice(); + double nResult = 0; + if( pDevice ) + { + Size aRefSize( nValue, nValue ); + Fraction aFracX( 1, 26 ); + Fraction aFracY( 1, 24 ); + MapMode aMap( MAP_APPFONT, Point(), aFracX, aFracY ); + Size aScaledSize = pDevice->LogicToPixel( aRefSize, aMap ); + aRefSize = pDevice->LogicToPixel( aRefSize, MapMode(MAP_TWIP) ); + + double nRef, nScaled; + if( bX ) + { + nRef = aRefSize.Width(); + nScaled = aScaledSize.Width(); + } + else + { + nRef = aRefSize.Height(); + nScaled = aScaledSize.Height(); + } + nResult = nScaled / nRef; + } + return nResult; +} + + +RTLFUNC(GetDialogZoomFactorX) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + rPar.Get(0)->PutDouble( GetDialogZoomFactor( TRUE, rPar.Get(1)->GetLong() )); +} + +RTLFUNC(GetDialogZoomFactorY) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + rPar.Get(0)->PutDouble( GetDialogZoomFactor( FALSE, rPar.Get(1)->GetLong())); +} + + +RTLFUNC(EnableReschedule) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutEmpty(); + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + if( pINST ) + pINST->EnableReschedule( rPar.Get(1)->GetBool() ); +} + +RTLFUNC(GetSystemTicks) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + rPar.Get(0)->PutLong( Time::GetSystemTicks() ); +} + +RTLFUNC(GetPathSeparator) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + rPar.Get(0)->PutString( DirEntry::GetAccessDelimiter() ); +} + +RTLFUNC(ResolvePath) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + String aStr = rPar.Get(1)->GetString(); + DirEntry aEntry( aStr ); + //if( aEntry.IsVirtual() ) + //aStr = aEntry.GetRealPathFromVirtualURL(); + rPar.Get(0)->PutString( aStr ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(TypeLen) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + SbxDataType eType = rPar.Get(1)->GetType(); + INT16 nLen = 0; + switch( eType ) + { + case SbxEMPTY: + case SbxNULL: + case SbxVECTOR: + case SbxARRAY: + case SbxBYREF: + case SbxVOID: + case SbxHRESULT: + case SbxPOINTER: + case SbxDIMARRAY: + case SbxCARRAY: + case SbxUSERDEF: + nLen = 0; + break; + + case SbxINTEGER: + case SbxERROR: + case SbxUSHORT: + case SbxINT: + case SbxUINT: + nLen = 2; + break; + + case SbxLONG: + case SbxSINGLE: + case SbxULONG: + nLen = 4; + break; + + case SbxDOUBLE: + case SbxCURRENCY: + case SbxDATE: + case SbxLONG64: + case SbxULONG64: + nLen = 8; + break; + + case SbxOBJECT: + case SbxVARIANT: + case SbxDATAOBJECT: + nLen = 0; + break; + + case SbxCHAR: + case SbxBYTE: + case SbxBOOL: + nLen = 1; + break; + + case SbxLPSTR: + case SbxLPWSTR: + case SbxCoreSTRING: + case SbxSTRING: + nLen = (INT16)rPar.Get(1)->GetString().Len(); + break; + + default: + nLen = 0; + } + rPar.Get(0)->PutInteger( nLen ); + } +} + + +// Uno-Struct eines beliebigen Typs erzeugen +// 1. Parameter == Klassename, weitere Parameter zur Initialisierung +RTLFUNC(CreateUnoStruct) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_CreateUnoStruct( pBasic, rPar, bWrite ); +} + +// Uno-Service erzeugen +// 1. Parameter == Service-Name +RTLFUNC(CreateUnoService) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_CreateUnoService( pBasic, rPar, bWrite ); +} + +RTLFUNC(CreateUnoServiceWithArguments) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_CreateUnoServiceWithArguments( pBasic, rPar, bWrite ); +} + + +RTLFUNC(CreateUnoValue) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_CreateUnoValue( pBasic, rPar, bWrite ); +} + + +// ServiceManager liefern (keine Parameter) +RTLFUNC(GetProcessServiceManager) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_GetProcessServiceManager( pBasic, rPar, bWrite ); +} + +// PropertySet erzeugen +// 1. Parameter == Sequence<PropertyValue> +RTLFUNC(CreatePropertySet) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_CreatePropertySet( pBasic, rPar, bWrite ); +} + +// Abfragen, ob ein Interface unterstuetzt wird +// Mehrere Interface-Namen als Parameter +RTLFUNC(HasUnoInterfaces) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_HasInterfaces( pBasic, rPar, bWrite ); +} + +// Abfragen, ob ein Basic-Objekt ein Uno-Struct repraesentiert +RTLFUNC(IsUnoStruct) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_IsUnoStruct( pBasic, rPar, bWrite ); +} + +// Abfragen, ob zwei Uno-Objekte identisch sind +RTLFUNC(EqualUnoObjects) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_EqualUnoObjects( pBasic, rPar, bWrite ); +} + +// Instanciate "com.sun.star.awt.UnoControlDialog" on basis +// of a DialogLibrary entry: Convert from XML-ByteSequence +// and attach events. Implemented in classes\eventatt.cxx +void RTL_Impl_CreateUnoDialog( StarBASIC* pBasic, SbxArray& rPar, BOOL bWrite ); + +RTLFUNC(CreateUnoDialog) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_CreateUnoDialog( pBasic, rPar, bWrite ); +} + +// Return the application standard lib as root scope +RTLFUNC(GlobalScope) +{ + (void)pBasic; + (void)bWrite; + + SbxObject* p = pBasic; + while( p->GetParent() ) + p = p->GetParent(); + + SbxVariableRef refVar = rPar.Get(0); + refVar->PutObject( p ); +} + +// Helper functions to convert Url from/to system paths +RTLFUNC(ConvertToUrl) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + String aStr = rPar.Get(1)->GetString(); + INetURLObject aURLObj( aStr, INET_PROT_FILE ); + ::rtl::OUString aFileURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + if( !aFileURL.getLength() ) + ::osl::File::getFileURLFromSystemPath( aFileURL, aFileURL ); + if( !aFileURL.getLength() ) + aFileURL = aStr; + rPar.Get(0)->PutString( String(aFileURL) ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + +RTLFUNC(ConvertFromUrl) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() == 2 ) + { + String aStr = rPar.Get(1)->GetString(); + ::rtl::OUString aSysPath; + ::osl::File::getSystemPathFromFileURL( aStr, aSysPath ); + if( !aSysPath.getLength() ) + aSysPath = aStr; + rPar.Get(0)->PutString( String(aSysPath) ); + } + else + StarBASIC::Error( SbERR_BAD_ARGUMENT ); +} + + +// Provide DefaultContext +RTLFUNC(GetDefaultContext) +{ + (void)pBasic; + (void)bWrite; + + RTL_Impl_GetDefaultContext( pBasic, rPar, bWrite ); +} + +#ifdef DBG_TRACE_BASIC +RTLFUNC(TraceCommand) +{ + RTL_Impl_TraceCommand( pBasic, rPar, bWrite ); +} +#endif + +RTLFUNC(Join) +{ + (void)pBasic; + (void)bWrite; + + USHORT 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 ) + { + if( pArr->GetDims() != 1 ) + StarBASIC::Error( SbERR_WRONG_DIMS ); // Syntax Error?! + + String aDelim; + if( nParCount == 3 ) + aDelim = rPar.Get(2)->GetString(); + else + aDelim = String::CreateFromAscii( " " ); + + String aRetStr; + short nLower, nUpper; + pArr->GetDim( 1, nLower, nUpper ); + for( short i = nLower ; i <= nUpper ; ++i ) + { + String aStr = pArr->Get( &i )->GetString(); + aRetStr += aStr; + if( i != nUpper ) + aRetStr += aDelim; + } + rPar.Get(0)->PutString( aRetStr ); + } + else + StarBASIC::Error( SbERR_MUST_HAVE_DIMS ); +} + + +RTLFUNC(Split) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if ( nParCount < 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aExpression = rPar.Get(1)->GetString(); + short nArraySize = 0; + StringVector vRet; + if( aExpression.Len() ) + { + String aDelim; + if( nParCount >= 3 ) + aDelim = rPar.Get(2)->GetString(); + else + aDelim = String::CreateFromAscii( " " ); + + INT32 nCount = -1; + if( nParCount == 4 ) + nCount = rPar.Get(3)->GetLong(); + + xub_StrLen nDelimLen = aDelim.Len(); + if( nDelimLen ) + { + xub_StrLen iSearch = STRING_NOTFOUND; + xub_StrLen iStart = 0; + do + { + bool bBreak = false; + if( nCount >= 0 && nArraySize == nCount - 1 ) + bBreak = true; + + iSearch = aExpression.Search( aDelim, iStart ); + String aSubStr; + if( iSearch != STRING_NOTFOUND && !bBreak ) + { + aSubStr = aExpression.Copy( iStart, iSearch - iStart ); + iStart = iSearch + nDelimLen; + } + else + { + aSubStr = aExpression.Copy( iStart ); + } + vRet.push_back( aSubStr ); + nArraySize++; + + if( bBreak ) + break; + } + while( iSearch != STRING_NOTFOUND ); + } + else + { + vRet.push_back( aExpression ); + nArraySize = 1; + } + } + + SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); + pArray->unoAddDim( 0, nArraySize-1 ); + + // Parameter ins Array uebernehmen + for( short i = 0 ; i < nArraySize ; i++ ) + { + SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); + xVar->PutString( vRet[i] ); + pArray->Put( (SbxVariable*)xVar, &i ); + } + + // Array zurueckliefern + SbxVariableRef refVar = rPar.Get(0); + USHORT nFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->PutObject( pArray ); + refVar->SetFlags( nFlags ); + refVar->SetParameters( NULL ); +} + +// MonthName(month[, abbreviate]) +RTLFUNC(MonthName) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if( nParCount != 2 && nParCount != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + Reference< XCalendar > xCalendar = getLocaleCalendar(); + if( !xCalendar.is() ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + return; + } + Sequence< CalendarItem > aMonthSeq = xCalendar->getMonths(); + sal_Int32 nMonthCount = aMonthSeq.getLength(); + + INT16 nVal = rPar.Get(1)->GetInteger(); + if( nVal < 1 || nVal > nMonthCount ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + BOOL bAbbreviate = false; + if( nParCount == 3 ) + bAbbreviate = rPar.Get(2)->GetBool(); + + const CalendarItem* pCalendarItems = aMonthSeq.getConstArray(); + const CalendarItem& rItem = pCalendarItems[nVal - 1]; + + ::rtl::OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName ); + rPar.Get(0)->PutString( String(aRetStr) ); +} + +// WeekdayName(weekday, abbreviate, firstdayofweek) +RTLFUNC(WeekdayName) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if( nParCount < 2 || nParCount > 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + Reference< XCalendar > xCalendar = getLocaleCalendar(); + if( !xCalendar.is() ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + return; + } + + Sequence< CalendarItem > aDaySeq = xCalendar->getDays(); + INT16 nDayCount = (INT16)aDaySeq.getLength(); + INT16 nDay = rPar.Get(1)->GetInteger(); + INT16 nFirstDay = 0; + if( nParCount == 4 ) + { + nFirstDay = rPar.Get(3)->GetInteger(); + if( nFirstDay < 0 || nFirstDay > 7 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + } + if( nFirstDay == 0 ) + nFirstDay = INT16( xCalendar->getFirstDayOfWeek() + 1 ); + + nDay = 1 + (nDay + nDayCount + nFirstDay - 2) % nDayCount; + if( nDay < 1 || nDay > nDayCount ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + BOOL bAbbreviate = false; + if( nParCount >= 3 ) + { + SbxVariable* pPar2 = rPar.Get(2); + if( !pPar2->IsErr() ) + bAbbreviate = pPar2->GetBool(); + } + + const CalendarItem* pCalendarItems = aDaySeq.getConstArray(); + const CalendarItem& rItem = pCalendarItems[nDay - 1]; + + ::rtl::OUString aRetStr = ( bAbbreviate ? rItem.AbbrevName : rItem.FullName ); + rPar.Get(0)->PutString( String(aRetStr) ); +} + +INT16 implGetWeekDay( double aDate, bool bFirstDayParam = false, INT16 nFirstDay = 0 ) +{ + Date aRefDate( 1,1,1900 ); + long nDays = (long) aDate; + nDays -= 2; // normieren: 1.1.1900 => 0 + aRefDate += nDays; + DayOfWeek aDay = aRefDate.GetDayOfWeek(); + INT16 nDay; + if ( aDay != SUNDAY ) + nDay = (INT16)aDay + 2; + else + nDay = 1; // 1==Sonntag + + // #117253 Optional 2. parameter "firstdayofweek" + if( bFirstDayParam ) + { + if( nFirstDay < 0 || nFirstDay > 7 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return 0; + } + if( nFirstDay == 0 ) + { + Reference< XCalendar > xCalendar = getLocaleCalendar(); + if( !xCalendar.is() ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + return 0; + } + nFirstDay = INT16( xCalendar->getFirstDayOfWeek() + 1 ); + } + nDay = 1 + (nDay + 7 - nFirstDay) % 7; + } + return nDay; +} + +RTLFUNC(Weekday) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if ( nParCount < 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + else + { + double aDate = rPar.Get(1)->GetDate(); + + bool bFirstDay = false; + INT16 nFirstDay = 0; + if ( nParCount > 2 ) + { + nFirstDay = rPar.Get(2)->GetInteger(); + bFirstDay = true; + } + INT16 nDay = implGetWeekDay( aDate, bFirstDay, nFirstDay ); + rPar.Get(0)->PutInteger( nDay ); + } +} + + +enum Interval +{ + INTERVAL_NONE, + INTERVAL_YYYY, + INTERVAL_Q, + INTERVAL_M, + INTERVAL_Y, + INTERVAL_D, + INTERVAL_W, + INTERVAL_WW, + INTERVAL_H, + INTERVAL_N, + INTERVAL_S +}; + +struct IntervalInfo +{ + Interval meInterval; + const char* mpStringCode; + double mdValue; + bool mbSimple; + + IntervalInfo( Interval eInterval, const char* pStringCode, double dValue, bool bSimple ) + : meInterval( eInterval ) + , mpStringCode( pStringCode ) + , mdValue( dValue ) + , mbSimple( bSimple ) + {} +}; + +static IntervalInfo pIntervalTable[] = +{ + IntervalInfo( INTERVAL_YYYY, "yyyy", 0.0, false ), // Year + IntervalInfo( INTERVAL_Q, "q", 0.0, false ), // Quarter + IntervalInfo( INTERVAL_M, "m", 0.0, false ), // Month + IntervalInfo( INTERVAL_Y, "y", 1.0, true ), // Day of year + IntervalInfo( INTERVAL_D, "d", 1.0, true ), // Day + IntervalInfo( INTERVAL_W, "w", 1.0, true ), // Weekday + IntervalInfo( INTERVAL_WW, "ww", 7.0, true ), // Week + IntervalInfo( INTERVAL_H, "h", (1.0 / 24.0), true ), // Hour + IntervalInfo( INTERVAL_N, "n", (1.0 / 1440.0), true), // Minute + IntervalInfo( INTERVAL_S, "s", (1.0 / 86400.0), true ), // Second + IntervalInfo( INTERVAL_NONE, NULL, 0.0, false ) +}; + +IntervalInfo* getIntervalInfo( const String& rStringCode ) +{ + IntervalInfo* pInfo = NULL; + INT16 i = 0; + while( (pInfo = pIntervalTable + i)->mpStringCode != NULL ) + { + if( rStringCode.EqualsIgnoreCaseAscii( pInfo->mpStringCode ) ) + break; + i++; + } + return pInfo; +} + +// From methods.cxx +BOOL implDateSerial( INT16 nYear, INT16 nMonth, INT16 nDay, double& rdRet ); +INT16 implGetDateDay( double aDate ); +INT16 implGetDateMonth( double aDate ); +INT16 implGetDateYear( double aDate ); + +INT16 implGetHour( double dDate ); +INT16 implGetMinute( double dDate ); +INT16 implGetSecond( double dDate ); + + +inline void implGetDayMonthYear( INT16& rnYear, INT16& rnMonth, INT16& rnDay, double dDate ) +{ + rnDay = implGetDateDay( dDate ); + rnMonth = implGetDateMonth( dDate ); + rnYear = implGetDateYear( dDate ); +} + +inline INT16 limitToINT16( INT32 n32 ) +{ + if( n32 > 32767 ) + n32 = 32767; + else if( n32 < -32768 ) + n32 = -32768; + return (INT16)n32; +} + +RTLFUNC(DateAdd) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if( nParCount != 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aStringCode = rPar.Get(1)->GetString(); + IntervalInfo* pInfo = getIntervalInfo( aStringCode ); + if( !pInfo ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + INT32 lNumber = rPar.Get(2)->GetLong(); + double dDate = rPar.Get(3)->GetDate(); + double dNewDate = 0; + if( pInfo->mbSimple ) + { + double dAdd = pInfo->mdValue * lNumber; + dNewDate = dDate + dAdd; + } + else + { + // Keep hours, minutes, seconds + double dHoursMinutesSeconds = dDate - floor( dDate ); + + BOOL bOk = TRUE; + INT16 nYear, nMonth, nDay; + INT16 nTargetYear16 = 0, nTargetMonth = 0; + implGetDayMonthYear( nYear, nMonth, nDay, dDate ); + switch( pInfo->meInterval ) + { + case INTERVAL_YYYY: + { + INT32 nTargetYear = lNumber + nYear; + nTargetYear16 = limitToINT16( nTargetYear ); + nTargetMonth = nMonth; + bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, dNewDate ); + break; + } + case INTERVAL_Q: + case INTERVAL_M: + { + bool bNeg = (lNumber < 0); + if( bNeg ) + lNumber = -lNumber; + INT32 nYearsAdd; + INT16 nMonthAdd; + if( pInfo->meInterval == INTERVAL_Q ) + { + nYearsAdd = lNumber / 4; + nMonthAdd = (INT16)( 3 * (lNumber % 4) ); + } + else + { + nYearsAdd = lNumber / 12; + nMonthAdd = (INT16)( lNumber % 12 ); + } + + INT32 nTargetYear; + if( bNeg ) + { + nTargetMonth = nMonth - nMonthAdd; + if( nTargetMonth <= 0 ) + { + nTargetMonth += 12; + nYearsAdd++; + } + nTargetYear = (INT32)nYear - nYearsAdd; + } + else + { + nTargetMonth = nMonth + nMonthAdd; + if( nTargetMonth > 12 ) + { + nTargetMonth -= 12; + nYearsAdd++; + } + nTargetYear = (INT32)nYear + nYearsAdd; + } + nTargetYear16 = limitToINT16( nTargetYear ); + bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, dNewDate ); + break; + } + default: break; + } + + if( bOk ) + { + // Overflow? + INT16 nNewYear, nNewMonth, nNewDay; + implGetDayMonthYear( nNewYear, nNewMonth, nNewDay, dNewDate ); + if( nNewYear > 9999 || nNewYear < 100 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + INT16 nCorrectionDay = nDay; + while( nNewMonth > nTargetMonth ) + { + nCorrectionDay--; + implDateSerial( nTargetYear16, nTargetMonth, nCorrectionDay, dNewDate ); + implGetDayMonthYear( nNewYear, nNewMonth, nNewDay, dNewDate ); + } + dNewDate += dHoursMinutesSeconds; + } + } + + rPar.Get(0)->PutDate( dNewDate ); +} + +inline double RoundImpl( double d ) +{ + return ( d >= 0 ) ? floor( d + 0.5 ) : -floor( -d + 0.5 ); +} + +RTLFUNC(DateDiff) +{ + (void)pBasic; + (void)bWrite; + + // DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]]) + + USHORT nParCount = rPar.Count(); + if( nParCount < 4 || nParCount > 6 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aStringCode = rPar.Get(1)->GetString(); + IntervalInfo* pInfo = getIntervalInfo( aStringCode ); + if( !pInfo ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + double dDate1 = rPar.Get(2)->GetDate(); + double dDate2 = rPar.Get(3)->GetDate(); + + double dRet = 0.0; + switch( pInfo->meInterval ) + { + case INTERVAL_YYYY: + { + INT16 nYear1 = implGetDateYear( dDate1 ); + INT16 nYear2 = implGetDateYear( dDate2 ); + dRet = nYear2 - nYear1; + break; + } + case INTERVAL_Q: + { + INT16 nYear1 = implGetDateYear( dDate1 ); + INT16 nYear2 = implGetDateYear( dDate2 ); + INT16 nQ1 = 1 + (implGetDateMonth( dDate1 ) - 1) / 3; + INT16 nQ2 = 1 + (implGetDateMonth( dDate2 ) - 1) / 3; + INT16 nQGes1 = 4 * nYear1 + nQ1; + INT16 nQGes2 = 4 * nYear2 + nQ2; + dRet = nQGes2 - nQGes1; + break; + } + case INTERVAL_M: + { + INT16 nYear1 = implGetDateYear( dDate1 ); + INT16 nYear2 = implGetDateYear( dDate2 ); + INT16 nMonth1 = implGetDateMonth( dDate1 ); + INT16 nMonth2 = implGetDateMonth( dDate2 ); + INT16 nMonthGes1 = 12 * nYear1 + nMonth1; + INT16 nMonthGes2 = 12 * nYear2 + nMonth2; + dRet = nMonthGes2 - nMonthGes1; + break; + } + case INTERVAL_Y: + case INTERVAL_D: + { + double dDays1 = floor( dDate1 ); + double dDays2 = floor( dDate2 ); + dRet = dDays2 - dDays1; + break; + } + case INTERVAL_W: + case INTERVAL_WW: + { + double dDays1 = floor( dDate1 ); + double dDays2 = floor( dDate2 ); + if( pInfo->meInterval == INTERVAL_WW ) + { + INT16 nFirstDay = 1; // Default + if( nParCount >= 5 ) + { + nFirstDay = rPar.Get(4)->GetInteger(); + if( nFirstDay < 0 || nFirstDay > 7 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + if( nFirstDay == 0 ) + { + Reference< XCalendar > xCalendar = getLocaleCalendar(); + if( !xCalendar.is() ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + return; + } + nFirstDay = INT16( xCalendar->getFirstDayOfWeek() + 1 ); + } + } + INT16 nDay1 = implGetWeekDay( dDate1 ); + INT16 nDay1_Diff = nDay1 - nFirstDay; + if( nDay1_Diff < 0 ) + nDay1_Diff += 7; + dDays1 -= nDay1_Diff; + + INT16 nDay2 = implGetWeekDay( dDate2 ); + INT16 nDay2_Diff = nDay2 - nFirstDay; + if( nDay2_Diff < 0 ) + nDay2_Diff += 7; + dDays2 -= nDay2_Diff; + } + + double dDiff = dDays2 - dDays1; + dRet = ( dDiff >= 0 ) ? floor( dDiff / 7.0 ) : -floor( -dDiff / 7.0 ); + break; + } + case INTERVAL_H: + { + double dFactor = 24.0; + dRet = RoundImpl( dFactor * (dDate2 - dDate1) ); + break; + } + case INTERVAL_N: + { + double dFactor =1440.0; + dRet = RoundImpl( dFactor * (dDate2 - dDate1) ); + break; + } + case INTERVAL_S: + { + double dFactor = 86400.0; + dRet = RoundImpl( dFactor * (dDate2 - dDate1) ); + break; + } + case INTERVAL_NONE: + break; + } + rPar.Get(0)->PutDouble( dRet ); +} + +double implGetDateOfFirstDayInFirstWeek + ( INT16 nYear, INT16& nFirstDay, INT16& nFirstWeek, bool* pbError = NULL ) +{ + SbError nError = 0; + if( nFirstDay < 0 || nFirstDay > 7 ) + nError = SbERR_BAD_ARGUMENT; + + if( nFirstWeek < 0 || nFirstWeek > 3 ) + nError = SbERR_BAD_ARGUMENT; + + Reference< XCalendar > xCalendar; + if( nFirstDay == 0 || nFirstWeek == 0 ) + { + xCalendar = getLocaleCalendar(); + if( !xCalendar.is() ) + nError = SbERR_BAD_ARGUMENT; + } + + if( nError != 0 ) + { + StarBASIC::Error( nError ); + if( pbError ) + *pbError = true; + return 0.0; + } + + if( nFirstDay == 0 ) + nFirstDay = INT16( xCalendar->getFirstDayOfWeek() + 1 ); + + INT16 nFirstWeekMinDays = 0; // Not used for vbFirstJan1 = default + if( nFirstWeek == 0 ) + { + nFirstWeekMinDays = xCalendar->getMinimumNumberOfDaysForFirstWeek(); + if( nFirstWeekMinDays == 1 ) + { + nFirstWeekMinDays = 0; + nFirstWeek = 1; + } + else if( nFirstWeekMinDays == 4 ) + nFirstWeek = 2; + else if( nFirstWeekMinDays == 7 ) + nFirstWeek = 3; + } + else if( nFirstWeek == 2 ) + nFirstWeekMinDays = 4; // vbFirstFourDays + else if( nFirstWeek == 3 ) + nFirstWeekMinDays = 7; // vbFirstFourDays + + double dBaseDate; + implDateSerial( nYear, 1, 1, dBaseDate ); + double dRetDate = dBaseDate; + + INT16 nWeekDay0101 = implGetWeekDay( dBaseDate ); + INT16 nDayDiff = nWeekDay0101 - nFirstDay; + if( nDayDiff < 0 ) + nDayDiff += 7; + + if( nFirstWeekMinDays ) + { + INT16 nThisWeeksDaysInYearCount = 7 - nDayDiff; + if( nThisWeeksDaysInYearCount < nFirstWeekMinDays ) + nDayDiff -= 7; + } + dRetDate = dBaseDate - nDayDiff; + return dRetDate; +} + +RTLFUNC(DatePart) +{ + (void)pBasic; + (void)bWrite; + + // DatePart(interval, date[,firstdayofweek[, firstweekofyear]]) + + USHORT nParCount = rPar.Count(); + if( nParCount < 3 || nParCount > 5 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aStringCode = rPar.Get(1)->GetString(); + IntervalInfo* pInfo = getIntervalInfo( aStringCode ); + if( !pInfo ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + double dDate = rPar.Get(2)->GetDate(); + + INT32 nRet = 0; + switch( pInfo->meInterval ) + { + case INTERVAL_YYYY: + { + nRet = implGetDateYear( dDate ); + break; + } + case INTERVAL_Q: + { + nRet = 1 + (implGetDateMonth( dDate ) - 1) / 3; + break; + } + case INTERVAL_M: + { + nRet = implGetDateMonth( dDate ); + break; + } + case INTERVAL_Y: + { + INT16 nYear = implGetDateYear( dDate ); + double dBaseDate; + implDateSerial( nYear, 1, 1, dBaseDate ); + nRet = 1 + INT32( dDate - dBaseDate ); + break; + } + case INTERVAL_D: + { + nRet = implGetDateDay( dDate ); + break; + } + case INTERVAL_W: + { + bool bFirstDay = false; + INT16 nFirstDay = 1; // Default + if( nParCount >= 4 ) + { + nFirstDay = rPar.Get(3)->GetInteger(); + bFirstDay = true; + } + nRet = implGetWeekDay( dDate, bFirstDay, nFirstDay ); + break; + } + case INTERVAL_WW: + { + INT16 nFirstDay = 1; // Default + if( nParCount >= 4 ) + nFirstDay = rPar.Get(3)->GetInteger(); + + INT16 nFirstWeek = 1; // Default + if( nParCount == 5 ) + nFirstWeek = rPar.Get(4)->GetInteger(); + + INT16 nYear = implGetDateYear( dDate ); + bool bError = false; + double dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear, nFirstDay, nFirstWeek, &bError ); + if( !bError ) + { + if( dYearFirstDay > dDate ) + { + // Date belongs to last year's week + dYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear - 1, nFirstDay, nFirstWeek ); + } + else if( nFirstWeek != 1 ) + { + // Check if date belongs to next year + double dNextYearFirstDay = implGetDateOfFirstDayInFirstWeek( nYear + 1, nFirstDay, nFirstWeek ); + if( dDate >= dNextYearFirstDay ) + dYearFirstDay = dNextYearFirstDay; + } + + // Calculate week + double dDiff = dDate - dYearFirstDay; + nRet = 1 + INT32( dDiff / 7 ); + } + break; + } + case INTERVAL_H: + { + nRet = implGetHour( dDate ); + break; + } + case INTERVAL_N: + { + nRet = implGetMinute( dDate ); + break; + } + case INTERVAL_S: + { + nRet = implGetSecond( dDate ); + break; + } + case INTERVAL_NONE: + break; + } + rPar.Get(0)->PutLong( nRet ); +} + +// FormatDateTime(Date[,NamedFormat]) +RTLFUNC(FormatDateTime) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if( nParCount < 2 || nParCount > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + double dDate = rPar.Get(1)->GetDate(); + INT16 nNamedFormat = 0; + if( nParCount > 2 ) + { + nNamedFormat = rPar.Get(2)->GetInteger(); + if( nNamedFormat < 0 || nNamedFormat > 4 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + } + + Reference< XCalendar > xCalendar = getLocaleCalendar(); + if( !xCalendar.is() ) + { + StarBASIC::Error( SbERR_INTERNAL_ERROR ); + return; + } + + String aRetStr; + SbxVariableRef pSbxVar = new SbxVariable( SbxSTRING ); + switch( nNamedFormat ) + { + // GeneralDate: + // Display a date and/or time. If there is a date part, + // display it as a short date. If there is a time part, + // display it as a long time. If present, both parts are displayed. + + // 12/21/2004 11:24:50 AM + // 21.12.2004 12:13:51 + case 0: + pSbxVar->PutDate( dDate ); + aRetStr = pSbxVar->GetString(); + break; + + // LongDate: Display a date using the long date format specified + // in your computer's regional settings. + // Tuesday, December 21, 2004 + // Dienstag, 21. December 2004 + case 1: + { + SvNumberFormatter* pFormatter = NULL; + if( pINST ) + pFormatter = pINST->GetNumberFormatter(); + else + { + sal_uInt32 n; // Dummy + SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n ); + } + + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + ULONG nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, eLangType ); + Color* pCol; + pFormatter->GetOutputString( dDate, nIndex, aRetStr, &pCol ); + + if( !pINST ) + delete pFormatter; + + break; + } + + // ShortDate: Display a date using the short date format specified + // in your computer's regional settings. + // 12/21/2004 + // 21.12.2004 + case 2: + pSbxVar->PutDate( floor(dDate) ); + aRetStr = pSbxVar->GetString(); + break; + + // LongTime: Display a time using the time format specified + // in your computer's regional settings. + // 11:24:50 AM + // 12:13:51 + case 3: + // ShortTime: Display a time using the 24-hour format (hh:mm). + // 11:24 + case 4: + double n; + double dTime = modf( dDate, &n ); + pSbxVar->PutDate( dTime ); + if( nNamedFormat == 3 ) + aRetStr = pSbxVar->GetString(); + else + aRetStr = pSbxVar->GetString().Copy( 0, 5 ); + break; + } + + rPar.Get(0)->PutString( aRetStr ); +} + +RTLFUNC(Round) +{ + (void)pBasic; + (void)bWrite; + + USHORT nParCount = rPar.Count(); + if( nParCount != 2 && nParCount != 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + SbxVariable *pSbxVariable = rPar.Get(1); + double dVal = pSbxVariable->GetDouble(); + double dRes = 0.0; + if( dVal != 0.0 ) + { + bool bNeg = false; + if( dVal < 0.0 ) + { + bNeg = true; + dVal = -dVal; + } + + INT16 numdecimalplaces = 0; + if( nParCount == 3 ) + { + numdecimalplaces = rPar.Get(2)->GetInteger(); + if( numdecimalplaces < 0 || numdecimalplaces > 22 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + } + + if( numdecimalplaces == 0 ) + { + dRes = floor( dVal + 0.5 ); + } + else + { + double dFactor = pow( 10.0, numdecimalplaces ); + dVal *= dFactor; + dRes = floor( dVal + 0.5 ); + dRes /= dFactor; + } + + if( bNeg ) + dRes = -dRes; + } + rPar.Get(0)->PutDouble( dRes ); +} + +RTLFUNC(StrReverse) +{ + (void)pBasic; + (void)bWrite; + + if ( rPar.Count() != 2 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + SbxVariable *pSbxVariable = rPar.Get(1); + if( pSbxVariable->IsNull() ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + String aStr = pSbxVariable->GetString(); + aStr.Reverse(); + rPar.Get(0)->PutString( aStr ); +} + +RTLFUNC(CompatibilityMode) +{ + (void)pBasic; + (void)bWrite; + + bool bEnabled = false; + USHORT nCount = rPar.Count(); + if ( nCount != 1 && nCount != 2 ) + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + + SbiInstance* pInst = pINST; + if( pInst ) + { + if ( nCount == 2 ) + pInst->EnableCompatibility( rPar.Get(1)->GetBool() ); + + bEnabled = pInst->IsCompatibility(); + } + rPar.Get(0)->PutBool( bEnabled ); +} + +RTLFUNC(Input) +{ + (void)pBasic; + (void)bWrite; + + // 2 parameters needed + if ( rPar.Count() < 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + USHORT nByteCount = rPar.Get(1)->GetUShort(); + INT16 nFileNumber = rPar.Get(2)->GetInteger(); + + SbiIoSystem* pIosys = pINST->GetIoSystem(); + SbiStream* pSbStrm = pIosys->GetStream( nFileNumber ); + if ( !pSbStrm || !(pSbStrm->GetMode() & (SBSTRM_BINARY | SBSTRM_INPUT)) ) + { + StarBASIC::Error( SbERR_BAD_CHANNEL ); + return; + } + + ByteString aByteBuffer; + SbError err = pSbStrm->Read( aByteBuffer, nByteCount, true ); + if( !err ) + err = pIosys->GetError(); + + if( err ) + { + StarBASIC::Error( err ); + return; + } + rPar.Get(0)->PutString( String( aByteBuffer, gsl_getSystemTextEncoding() ) ); +} + +// #115824 +RTLFUNC(Me) +{ + (void)pBasic; + (void)bWrite; + + SbModule* pActiveModule = pINST->GetActiveModule(); + SbClassModuleObject* pClassModuleObject = PTR_CAST(SbClassModuleObject,pActiveModule); + SbxVariableRef refVar = rPar.Get(0); + if( pClassModuleObject == NULL ) + { + SbObjModule* pMod = PTR_CAST(SbObjModule,pActiveModule); + if ( pMod ) + refVar->PutObject( pMod ); + else + StarBASIC::Error( SbERR_INVALID_USAGE_OBJECT ); + } + else + refVar->PutObject( pClassModuleObject ); +} + diff --git a/basic/source/runtime/props.cxx b/basic/source/runtime/props.cxx new file mode 100644 index 000000000000..663d12fbcd72 --- /dev/null +++ b/basic/source/runtime/props.cxx @@ -0,0 +1,776 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include "runtime.hxx" +#include "stdobj.hxx" +#include "rtlproto.hxx" +#include "errobject.hxx" + + +// Properties und Methoden legen beim Get (bWrite = FALSE) den Returnwert +// im Element 0 des Argv ab; beim Put (bWrite = TRUE) wird der Wert aus +// Element 0 gespeichert. + +RTLFUNC(Erl) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get( 0 )->PutLong( StarBASIC::GetErl() ); +} + +RTLFUNC(Err) +{ + (void)pBasic; + (void)bWrite; + + if( SbiRuntime::isVBAEnabled() ) + { + rPar.Get( 0 )->PutObject( SbxErrObject::getErrObject() ); + } + else + { + if( bWrite ) + { + INT32 nVal = rPar.Get( 0 )->GetLong(); + if( nVal <= 65535L ) + StarBASIC::Error( StarBASIC::GetSfxFromVBError( (USHORT) nVal ) ); + } + else + rPar.Get( 0 )->PutLong( StarBASIC::GetVBErrorCode( StarBASIC::GetErrBasic() ) ); + } +} + +RTLFUNC(False) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutBool( FALSE ); +} + +RTLFUNC(Empty) +{ + (void)pBasic; + (void)bWrite; + (void)rPar; +} + +RTLFUNC(Nothing) +{ + (void)pBasic; + (void)bWrite; + + // liefert eine leere Objekt-Variable. + rPar.Get( 0 )->PutObject( NULL ); +} + +RTLFUNC(Null) +{ + (void)pBasic; + (void)bWrite; + + // liefert eine leere Objekt-Variable. + rPar.Get( 0 )->PutNull(); +} + +RTLFUNC(PI) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get( 0 )->PutDouble( F_PI ); +} + +RTLFUNC(True) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get( 0 )->PutBool( TRUE ); +} + +RTLFUNC(ATTR_NORMAL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(ATTR_READONLY) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(ATTR_HIDDEN) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(ATTR_SYSTEM) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(4); +} +RTLFUNC(ATTR_VOLUME) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(8); +} +RTLFUNC(ATTR_DIRECTORY) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(16); +} +RTLFUNC(ATTR_ARCHIVE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(32); +} + +RTLFUNC(V_EMPTY) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(V_NULL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(V_INTEGER) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(V_LONG) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(3); +} +RTLFUNC(V_SINGLE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(4); +} +RTLFUNC(V_DOUBLE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(5); +} +RTLFUNC(V_CURRENCY) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(6); +} +RTLFUNC(V_DATE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(7); +} +RTLFUNC(V_STRING) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(8); +} + +RTLFUNC(MB_OK) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(MB_OKCANCEL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(MB_ABORTRETRYIGNORE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(MB_YESNOCANCEL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(3); +} +RTLFUNC(MB_YESNO) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(4); +} +RTLFUNC(MB_RETRYCANCEL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(5); +} +RTLFUNC(MB_ICONSTOP) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(16); +} +RTLFUNC(MB_ICONQUESTION) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(32); +} +RTLFUNC(MB_ICONEXCLAMATION) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(48); +} +RTLFUNC(MB_ICONINFORMATION) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(64); +} +RTLFUNC(MB_DEFBUTTON1) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(MB_DEFBUTTON2) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(256); +} +RTLFUNC(MB_DEFBUTTON3) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(512); +} +RTLFUNC(MB_APPLMODAL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(MB_SYSTEMMODAL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(4096); +} + +RTLFUNC(IDOK) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} + +RTLFUNC(IDCANCEL) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(IDABORT) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(3); +} +RTLFUNC(IDRETRY) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(4); +} +RTLFUNC(IDYES) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(6); +} +RTLFUNC(IDNO) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(7); +} + +RTLFUNC(CF_TEXT) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(CF_BITMAP) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(CF_METAFILEPICT) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(3); +} + +RTLFUNC(TYP_AUTHORFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(7); +} +RTLFUNC(TYP_CHAPTERFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(4); +} +RTLFUNC(TYP_CONDTXTFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(27); +} +RTLFUNC(TYP_DATEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(TYP_DBFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(19); +} +RTLFUNC(TYP_DBNAMEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(3); +} +RTLFUNC(TYP_DBNEXTSETFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(24); +} +RTLFUNC(TYP_DBNUMSETFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(25); +} +RTLFUNC(TYP_DBSETNUMBERFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(26); +} +RTLFUNC(TYP_DDEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(14); +} +RTLFUNC(TYP_DOCINFOFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(18); +} +RTLFUNC(TYP_DOCSTATFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(6); +} +RTLFUNC(TYP_EXTUSERFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(30); +} +RTLFUNC(TYP_FILENAMEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(TYP_FIXDATEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(31); +} +RTLFUNC(TYP_FIXTIMEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(32); +} +RTLFUNC(TYP_FORMELFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(10); +} +RTLFUNC(TYP_GETFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(9); +} +RTLFUNC(TYP_GETREFFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(13); +} +RTLFUNC(TYP_HIDDENPARAFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(17); +} +RTLFUNC(TYP_HIDDENTXTFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(11); +} +RTLFUNC(TYP_INPUTFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(16); +} +RTLFUNC(TYP_MACROFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(15); +} +RTLFUNC(TYP_NEXTPAGEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(28); +} +RTLFUNC(TYP_PAGENUMBERFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(5); +} +RTLFUNC(TYP_POSTITFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(21); +} +RTLFUNC(TYP_PREVPAGEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(29); +} +RTLFUNC(TYP_SEQFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(23); +} +RTLFUNC(TYP_SETFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(8); +} +RTLFUNC(TYP_SETINPFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(33); +} +RTLFUNC(TYP_SETREFFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(12); +} +RTLFUNC(TYP_TEMPLNAMEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(22); +} +RTLFUNC(TYP_TIMEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(TYP_USERFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(20); +} +RTLFUNC(TYP_USRINPFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(34); +} +RTLFUNC(TYP_SETREFPAGEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(35); +} +RTLFUNC(TYP_GETREFPAGEFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(36); +} +RTLFUNC(TYP_INTERNETFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(37); +} + +RTLFUNC(SET_ON) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(SET_OFF) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(TOGGLE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} + +RTLFUNC(FRAMEANCHORPAGE) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(FRAMEANCHORPARA) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(14); +} +RTLFUNC(FRAMEANCHORCHAR) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(15); +} + +RTLFUNC(CLEAR_ALLTABS) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(CLEAR_TAB) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(SET_TAB) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} + +RTLFUNC(LINEPROP) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(0); +} +RTLFUNC(LINE_1) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(1); +} +RTLFUNC(LINE_15) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(2); +} +RTLFUNC(LINE_2) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(3); +} + +RTLFUNC(TYP_JUMPEDITFLD) +{ + (void)pBasic; + (void)bWrite; + + rPar.Get(0)->PutInteger(38); +} + + diff --git a/basic/source/runtime/rtlproto.hxx b/basic/source/runtime/rtlproto.hxx new file mode 100644 index 000000000000..ba7af48c8472 --- /dev/null +++ b/basic/source/runtime/rtlproto.hxx @@ -0,0 +1,355 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <basic/sbstar.hxx> +#include "sbtrace.hxx" + +#define RTLFUNC( name ) void SbRtl_##name( StarBASIC* pBasic, SbxArray& rPar, BOOL bWrite ) +#define RTLNAME( name ) &SbRtl_##name + +typedef void( *RtlCall ) ( StarBASIC* p, SbxArray& rArgs, BOOL bWrite ); + +// Properties + +extern RTLFUNC(Date); +extern RTLFUNC(Err); +extern RTLFUNC(Erl); +extern RTLFUNC(False); +extern RTLFUNC(Empty); +extern RTLFUNC(Nothing); +extern RTLFUNC(Null); +extern RTLFUNC(True); + +extern RTLFUNC(ATTR_NORMAL); +extern RTLFUNC(ATTR_READONLY); +extern RTLFUNC(ATTR_HIDDEN); +extern RTLFUNC(ATTR_SYSTEM); +extern RTLFUNC(ATTR_VOLUME); +extern RTLFUNC(ATTR_DIRECTORY); +extern RTLFUNC(ATTR_ARCHIVE); + +extern RTLFUNC(V_EMPTY); +extern RTLFUNC(V_NULL); +extern RTLFUNC(V_INTEGER); +extern RTLFUNC(V_LONG); +extern RTLFUNC(V_SINGLE); +extern RTLFUNC(V_DOUBLE); +extern RTLFUNC(V_CURRENCY); +extern RTLFUNC(V_DATE); +extern RTLFUNC(V_STRING); + +extern RTLFUNC(MB_OK); +extern RTLFUNC(MB_OKCANCEL); +extern RTLFUNC(MB_ABORTRETRYIGNORE); +extern RTLFUNC(MB_YESNOCANCEL); +extern RTLFUNC(MB_YESNO); +extern RTLFUNC(MB_RETRYCANCEL); +extern RTLFUNC(MB_ICONSTOP); +extern RTLFUNC(MB_ICONQUESTION); +extern RTLFUNC(MB_ICONEXCLAMATION); +extern RTLFUNC(MB_ICONINFORMATION); +extern RTLFUNC(MB_DEFBUTTON1); +extern RTLFUNC(MB_DEFBUTTON2); +extern RTLFUNC(MB_DEFBUTTON3); +extern RTLFUNC(MB_APPLMODAL); +extern RTLFUNC(MB_SYSTEMMODAL); + +extern RTLFUNC(IDOK); +extern RTLFUNC(IDCANCEL); +extern RTLFUNC(IDABORT); +extern RTLFUNC(IDRETRY); +extern RTLFUNC(IDYES); +extern RTLFUNC(IDNO); + +extern RTLFUNC(CF_TEXT); +extern RTLFUNC(CF_BITMAP); +extern RTLFUNC(CF_METAFILEPICT); + +extern RTLFUNC(PI); + +extern RTLFUNC(SET_OFF); +extern RTLFUNC(SET_ON); +extern RTLFUNC(TOGGLE); + +extern RTLFUNC(TYP_AUTHORFLD); +extern RTLFUNC(TYP_CHAPTERFLD); +extern RTLFUNC(TYP_CONDTXTFLD); +extern RTLFUNC(TYP_DATEFLD); +extern RTLFUNC(TYP_DBFLD); +extern RTLFUNC(TYP_DBNAMEFLD); +extern RTLFUNC(TYP_DBNEXTSETFLD); +extern RTLFUNC(TYP_DBNUMSETFLD); +extern RTLFUNC(TYP_DBSETNUMBERFLD); +extern RTLFUNC(TYP_DDEFLD); +extern RTLFUNC(TYP_DOCINFOFLD); +extern RTLFUNC(TYP_DOCSTATFLD); +extern RTLFUNC(TYP_EXTUSERFLD); +extern RTLFUNC(TYP_FILENAMEFLD); +extern RTLFUNC(TYP_FIXDATEFLD); +extern RTLFUNC(TYP_FIXTIMEFLD); +extern RTLFUNC(TYP_FORMELFLD); +extern RTLFUNC(TYP_GETFLD); +extern RTLFUNC(TYP_GETREFFLD); +extern RTLFUNC(TYP_HIDDENPARAFLD); +extern RTLFUNC(TYP_HIDDENTXTFLD); +extern RTLFUNC(TYP_INPUTFLD); +extern RTLFUNC(TYP_MACROFLD); +extern RTLFUNC(TYP_NEXTPAGEFLD); +extern RTLFUNC(TYP_PAGENUMBERFLD); +extern RTLFUNC(TYP_POSTITFLD); +extern RTLFUNC(TYP_PREVPAGEFLD); +extern RTLFUNC(TYP_SEQFLD); +extern RTLFUNC(TYP_SETFLD); +extern RTLFUNC(TYP_SETINPFLD); +extern RTLFUNC(TYP_SETREFFLD); +extern RTLFUNC(TYP_TEMPLNAMEFLD); +extern RTLFUNC(TYP_TIMEFLD); +extern RTLFUNC(TYP_USERFLD); +extern RTLFUNC(TYP_USRINPFLD); +extern RTLFUNC(TYP_SETREFPAGEFLD); +extern RTLFUNC(TYP_GETREFPAGEFLD); +extern RTLFUNC(TYP_INTERNETFLD); +extern RTLFUNC(TYP_JUMPEDITFLD); + +extern RTLFUNC(FRAMEANCHORPAGE); +extern RTLFUNC(FRAMEANCHORPARA); +extern RTLFUNC(FRAMEANCHORCHAR); + +extern RTLFUNC(CLEAR_ALLTABS); +extern RTLFUNC(CLEAR_TAB); +extern RTLFUNC(SET_TAB); + +extern RTLFUNC(LINEPROP); +extern RTLFUNC(LINE_1); +extern RTLFUNC(LINE_15); +extern RTLFUNC(LINE_2); + +// Methoden + +extern RTLFUNC(CreateObject); +extern RTLFUNC(Error); +extern RTLFUNC(Sin); +extern RTLFUNC(Abs); +extern RTLFUNC(Asc); +extern RTLFUNC(Atn); +extern RTLFUNC(Chr); +extern RTLFUNC(Cos); +extern RTLFUNC(CurDir); +extern RTLFUNC(ChDir); // JSM +extern RTLFUNC(ChDrive); // JSM +extern RTLFUNC(FileCopy); // JSM +extern RTLFUNC(Kill); // JSM +extern RTLFUNC(MkDir); // JSM +extern RTLFUNC(RmDir); // JSM +extern RTLFUNC(SendKeys); // JSM +extern RTLFUNC(DimArray); +extern RTLFUNC(Dir); +extern RTLFUNC(DoEvents); +extern RTLFUNC(Exp); +extern RTLFUNC(FileLen); +extern RTLFUNC(Fix); +extern RTLFUNC(Hex); +extern RTLFUNC(Input); +extern RTLFUNC(InStr); +extern RTLFUNC(InStrRev); +extern RTLFUNC(Int); +extern RTLFUNC(Join); +extern RTLFUNC(LCase); +extern RTLFUNC(Left); +extern RTLFUNC(Log); +extern RTLFUNC(LTrim); +extern RTLFUNC(Mid); +extern RTLFUNC(Oct); +extern RTLFUNC(Replace); +extern RTLFUNC(Right); +extern RTLFUNC(RTrim); +extern RTLFUNC(RTL); +extern RTLFUNC(Sgn); +extern RTLFUNC(Space); +extern RTLFUNC(Split); +extern RTLFUNC(Sqr); +extern RTLFUNC(Str); +extern RTLFUNC(StrComp); +extern RTLFUNC(String); +extern RTLFUNC(StrReverse); +extern RTLFUNC(Tan); +extern RTLFUNC(UCase); +extern RTLFUNC(Val); +extern RTLFUNC(Len); +extern RTLFUNC(Spc); +extern RTLFUNC(DateSerial); +extern RTLFUNC(TimeSerial); +extern RTLFUNC(DateValue); +extern RTLFUNC(TimeValue); +extern RTLFUNC(Day); +extern RTLFUNC(Hour); +extern RTLFUNC(Minute); +extern RTLFUNC(Month); +extern RTLFUNC(MonthName); +extern RTLFUNC(Now); +extern RTLFUNC(Second); +extern RTLFUNC(Time); +extern RTLFUNC(Timer); +extern RTLFUNC(Weekday); +extern RTLFUNC(WeekdayName); +extern RTLFUNC(Year); +extern RTLFUNC(Date); +extern RTLFUNC(InputBox); +extern RTLFUNC(Me); +extern RTLFUNC(MsgBox); +extern RTLFUNC(IsArray); +extern RTLFUNC(IsDate); +extern RTLFUNC(IsEmpty); +extern RTLFUNC(IsError); +extern RTLFUNC(IsNull); +extern RTLFUNC(IsNumeric); +extern RTLFUNC(IsObject); +extern RTLFUNC(IsUnoStruct); + +extern RTLFUNC(FileDateTime); +extern RTLFUNC(Format); +extern RTLFUNC(GetAttr); +extern RTLFUNC(Randomize); // JSM +extern RTLFUNC(Round); +extern RTLFUNC(Rnd); +extern RTLFUNC(Shell); +extern RTLFUNC(VarType); +extern RTLFUNC(TypeName); +extern RTLFUNC(TypeLen); + +extern RTLFUNC(EOF); +extern RTLFUNC(FileAttr); +extern RTLFUNC(Loc); +extern RTLFUNC(Lof); +extern RTLFUNC(Seek); +extern RTLFUNC(SetAttr); // JSM +extern RTLFUNC(Reset); // JSM + +extern RTLFUNC(DDEInitiate); +extern RTLFUNC(DDETerminate); +extern RTLFUNC(DDETerminateAll); +extern RTLFUNC(DDERequest); +extern RTLFUNC(DDEExecute); +extern RTLFUNC(DDEPoke); + +extern RTLFUNC(FreeFile); +extern RTLFUNC(IsMissing); +extern RTLFUNC(LBound); +extern RTLFUNC(UBound); +extern RTLFUNC(RGB); +extern RTLFUNC(QBColor); +extern RTLFUNC(StrConv); + +extern RTLFUNC(Beep); + +extern RTLFUNC(Load); +extern RTLFUNC(Unload); +extern RTLFUNC(AboutStarBasic); +extern RTLFUNC(LoadPicture); +extern RTLFUNC(SavePicture); + +extern RTLFUNC(CallByName); +extern RTLFUNC(CBool); // JSM +extern RTLFUNC(CByte); // JSM +extern RTLFUNC(CCur); // JSM +extern RTLFUNC(CDate); // JSM +extern RTLFUNC(CDbl); // JSM +extern RTLFUNC(CInt); // JSM +extern RTLFUNC(CLng); // JSM +extern RTLFUNC(CSng); // JSM +extern RTLFUNC(CStr); // JSM +extern RTLFUNC(CVar); // JSM +extern RTLFUNC(CVErr); // JSM + +extern RTLFUNC(Iif); // JSM + +extern RTLFUNC(DumpAllObjects); + +extern RTLFUNC(GetSystemType); +extern RTLFUNC(GetGUIType); +extern RTLFUNC(Red); +extern RTLFUNC(Green); +extern RTLFUNC(Blue); + +extern RTLFUNC(Switch); +extern RTLFUNC(Wait); +//i#64882# add new WaitUntil +extern RTLFUNC(WaitUntil); + +extern RTLFUNC(GetGUIVersion); +extern RTLFUNC(Choose); +extern RTLFUNC(Trim); + +extern RTLFUNC(DateAdd); +extern RTLFUNC(DateDiff); +extern RTLFUNC(DatePart); +extern RTLFUNC(FormatDateTime); +extern RTLFUNC(GetSolarVersion); +extern RTLFUNC(TwipsPerPixelX); +extern RTLFUNC(TwipsPerPixelY); +extern RTLFUNC(FreeLibrary); +extern RTLFUNC(Array); +extern RTLFUNC(FindObject); +extern RTLFUNC(FindPropertyObject); +extern RTLFUNC(EnableReschedule); + +extern RTLFUNC(Put); +extern RTLFUNC(Get); +extern RTLFUNC(Environ); +extern RTLFUNC(GetDialogZoomFactorX); +extern RTLFUNC(GetDialogZoomFactorY); +extern RTLFUNC(GetSystemTicks); +extern RTLFUNC(GetPathSeparator); +extern RTLFUNC(ResolvePath); +extern RTLFUNC(CreateUnoStruct); +extern RTLFUNC(CreateUnoService); +extern RTLFUNC(CreateUnoServiceWithArguments); +extern RTLFUNC(CreateUnoValue); +extern RTLFUNC(GetProcessServiceManager); +extern RTLFUNC(GetDefaultContext); +extern RTLFUNC(CreatePropertySet); +extern RTLFUNC(CreateUnoListener); +extern RTLFUNC(HasUnoInterfaces); +extern RTLFUNC(EqualUnoObjects); +extern RTLFUNC(CreateUnoDialog); +extern RTLFUNC(GlobalScope); +extern RTLFUNC(FileExists); +extern RTLFUNC(ConvertToUrl); +extern RTLFUNC(ConvertFromUrl); +extern RTLFUNC(CDateToIso); +extern RTLFUNC(CDateFromIso); +extern RTLFUNC(CompatibilityMode); +extern RTLFUNC(CDec); + +extern RTLFUNC(Partition); // Fong + +#ifdef DBG_TRACE_BASIC +extern RTLFUNC(TraceCommand); +#endif + +extern double Now_Impl(); +extern void Wait_Impl( bool bDurationBased, SbxArray& rPar ); diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx new file mode 100644 index 000000000000..62aa639e4c7e --- /dev/null +++ b/basic/source/runtime/runtime.cxx @@ -0,0 +1,1287 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/fsys.hxx> +#include <vcl/svapp.hxx> +#include <tools/wldcrd.hxx> +#include <svl/zforlist.hxx> +#include <unotools/syslocale.hxx> +#include "runtime.hxx" +#include "sbintern.hxx" +#include "opcodes.hxx" +#include "codegen.hxx" +#include "iosys.hxx" +#include "image.hxx" +#include "ddectrl.hxx" +#include "dllmgr.hxx" +#include <comphelper/processfactory.hxx> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include "sbunoobj.hxx" +#include "errobject.hxx" +#include "sbtrace.hxx" +#include "comenumwrapper.hxx" + +using namespace ::com::sun::star; + +bool SbiRuntime::isVBAEnabled() +{ + bool result = false; + SbiInstance* pInst = pINST; + if ( pInst && pINST->pRun ) + result = pInst->pRun->bVBAEnabled; + return result; +} + +// #91147 Global reschedule flag +static BOOL bStaticGlobalEnableReschedule = TRUE; + +void StarBASIC::StaticEnableReschedule( BOOL bReschedule ) +{ + bStaticGlobalEnableReschedule = bReschedule; +} +void StarBASIC::SetVBAEnabled( BOOL bEnabled ) +{ + if ( bDocBasic ) + { + bVBAEnabled = bEnabled; + } +} + +BOOL StarBASIC::isVBAEnabled() +{ + if ( bDocBasic ) + { + if( SbiRuntime::isVBAEnabled() ) + return TRUE; + return bVBAEnabled; + } + return FALSE; +} + + +struct SbiArgvStack { // Argv stack: + SbiArgvStack* pNext; // Stack Chain + SbxArrayRef refArgv; // Argv + short nArgc; // Argc +}; + +SbiRuntime::pStep0 SbiRuntime::aStep0[] = { // Alle Opcodes ohne Operanden + &SbiRuntime::StepNOP, + &SbiRuntime::StepEXP, + &SbiRuntime::StepMUL, + &SbiRuntime::StepDIV, + &SbiRuntime::StepMOD, + &SbiRuntime::StepPLUS, + &SbiRuntime::StepMINUS, + &SbiRuntime::StepNEG, + &SbiRuntime::StepEQ, + &SbiRuntime::StepNE, + &SbiRuntime::StepLT, + &SbiRuntime::StepGT, + &SbiRuntime::StepLE, + &SbiRuntime::StepGE, + &SbiRuntime::StepIDIV, + &SbiRuntime::StepAND, + &SbiRuntime::StepOR, + &SbiRuntime::StepXOR, + &SbiRuntime::StepEQV, + &SbiRuntime::StepIMP, + &SbiRuntime::StepNOT, + &SbiRuntime::StepCAT, + + &SbiRuntime::StepLIKE, + &SbiRuntime::StepIS, + // Laden/speichern + &SbiRuntime::StepARGC, // neuen Argv einrichten + &SbiRuntime::StepARGV, // TOS ==> aktueller Argv + &SbiRuntime::StepINPUT, // Input ==> TOS + &SbiRuntime::StepLINPUT, // Line Input ==> TOS + &SbiRuntime::StepGET, // TOS anfassen + &SbiRuntime::StepSET, // Speichern Objekt TOS ==> TOS-1 + &SbiRuntime::StepPUT, // TOS ==> TOS-1 + &SbiRuntime::StepPUTC, // TOS ==> TOS-1, dann ReadOnly + &SbiRuntime::StepDIM, // DIM + &SbiRuntime::StepREDIM, // REDIM + &SbiRuntime::StepREDIMP, // REDIM PRESERVE + &SbiRuntime::StepERASE, // TOS loeschen + // Verzweigen + &SbiRuntime::StepSTOP, // Programmende + &SbiRuntime::StepINITFOR, // FOR-Variable initialisieren + &SbiRuntime::StepNEXT, // FOR-Variable inkrementieren + &SbiRuntime::StepCASE, // Anfang CASE + &SbiRuntime::StepENDCASE, // Ende CASE + &SbiRuntime::StepSTDERROR, // Standard-Fehlerbehandlung + &SbiRuntime::StepNOERROR, // keine Fehlerbehandlung + &SbiRuntime::StepLEAVE, // UP verlassen + // E/A + &SbiRuntime::StepCHANNEL, // TOS = Kanalnummer + &SbiRuntime::StepPRINT, // print TOS + &SbiRuntime::StepPRINTF, // print TOS in field + &SbiRuntime::StepWRITE, // write TOS + &SbiRuntime::StepRENAME, // Rename Tos+1 to Tos + &SbiRuntime::StepPROMPT, // Input Prompt aus TOS definieren + &SbiRuntime::StepRESTART, // Set restart point + &SbiRuntime::StepCHANNEL0, // E/A-Kanal 0 einstellen + &SbiRuntime::StepEMPTY, // Leeren Ausdruck auf Stack + &SbiRuntime::StepERROR, // TOS = Fehlercode + &SbiRuntime::StepLSET, // Speichern Objekt TOS ==> TOS-1 + &SbiRuntime::StepRSET, // Speichern Objekt TOS ==> TOS-1 + &SbiRuntime::StepREDIMP_ERASE,// Copy array object for REDIMP + &SbiRuntime::StepINITFOREACH,// Init for each loop + &SbiRuntime::StepVBASET,// vba-like set statement + &SbiRuntime::StepERASE_CLEAR,// vba-like set statement + &SbiRuntime::StepARRAYACCESS,// access TOS as array + &SbiRuntime::StepBYVAL, // access TOS as array +}; + +SbiRuntime::pStep1 SbiRuntime::aStep1[] = { // Alle Opcodes mit einem Operanden + &SbiRuntime::StepLOADNC, // Laden einer numerischen Konstanten (+ID) + &SbiRuntime::StepLOADSC, // Laden einer Stringkonstanten (+ID) + &SbiRuntime::StepLOADI, // Immediate Load (+Wert) + &SbiRuntime::StepARGN, // Speichern eines named Args in Argv (+StringID) + &SbiRuntime::StepPAD, // String auf feste Laenge bringen (+Laenge) + // Verzweigungen + &SbiRuntime::StepJUMP, // Sprung (+Target) + &SbiRuntime::StepJUMPT, // TOS auswerten), bedingter Sprung (+Target) + &SbiRuntime::StepJUMPF, // TOS auswerten), bedingter Sprung (+Target) + &SbiRuntime::StepONJUMP, // TOS auswerten), Sprung in JUMP-Tabelle (+MaxVal) + &SbiRuntime::StepGOSUB, // UP-Aufruf (+Target) + &SbiRuntime::StepRETURN, // UP-Return (+0 oder Target) + &SbiRuntime::StepTESTFOR, // FOR-Variable testen), inkrementieren (+Endlabel) + &SbiRuntime::StepCASETO, // Tos+1 <= Case <= Tos), 2xremove (+Target) + &SbiRuntime::StepERRHDL, // Fehler-Handler (+Offset) + &SbiRuntime::StepRESUME, // Resume nach Fehlern (+0 or 1 or Label) + // E/A + &SbiRuntime::StepCLOSE, // (+Kanal/0) + &SbiRuntime::StepPRCHAR, // (+char) + // Verwaltung + &SbiRuntime::StepSETCLASS, // Set + Klassennamen testen (+StringId) + &SbiRuntime::StepTESTCLASS, // Check TOS class (+StringId) + &SbiRuntime::StepLIB, // Lib fuer Declare-Call (+StringId) + &SbiRuntime::StepBASED, // TOS wird um BASE erhoeht, BASE davor gepusht + &SbiRuntime::StepARGTYP, // Letzten Parameter in Argv konvertieren (+Typ) + &SbiRuntime::StepVBASETCLASS,// vba-like set statement +}; + +SbiRuntime::pStep2 SbiRuntime::aStep2[] = {// Alle Opcodes mit zwei Operanden + &SbiRuntime::StepRTL, // Laden aus RTL (+StringID+Typ) + &SbiRuntime::StepFIND, // Laden (+StringID+Typ) + &SbiRuntime::StepELEM, // Laden Element (+StringID+Typ) + &SbiRuntime::StepPARAM, // Parameter (+Offset+Typ) + // Verzweigen + &SbiRuntime::StepCALL, // Declare-Call (+StringID+Typ) + &SbiRuntime::StepCALLC, // CDecl-Declare-Call (+StringID+Typ) + &SbiRuntime::StepCASEIS, // Case-Test (+Test-Opcode+False-Target) + // Verwaltung + &SbiRuntime::StepSTMNT, // Beginn eines Statements (+Line+Col) + // E/A + &SbiRuntime::StepOPEN, // (+SvStreamFlags+Flags) + // Objekte + &SbiRuntime::StepLOCAL, // Lokale Variable definieren (+StringId+Typ) + &SbiRuntime::StepPUBLIC, // Modulglobale Variable (+StringID+Typ) + &SbiRuntime::StepGLOBAL, // Globale Variable definieren (+StringID+Typ) + &SbiRuntime::StepCREATE, // Objekt kreieren (+StringId+StringId) + &SbiRuntime::StepSTATIC, // Statische Variable (+StringId+StringId) + &SbiRuntime::StepTCREATE, // User Defined Objekte (+StringId+StringId) + &SbiRuntime::StepDCREATE, // Objekt-Array kreieren (+StringID+StringID) + &SbiRuntime::StepGLOBAL_P, // Globale Variable definieren, die beim Neustart + // von Basic nicht ueberschrieben wird (+StringID+Typ) + &SbiRuntime::StepFIND_G, // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P + &SbiRuntime::StepDCREATE_REDIMP, // Objekt-Array redimensionieren (+StringID+StringID) + &SbiRuntime::StepFIND_CM, // Search inside a class module (CM) to enable global search in time + &SbiRuntime::StepPUBLIC_P, // Search inside a class module (CM) to enable global search in time + &SbiRuntime::StepFIND_STATIC, // Search inside a class module (CM) to enable global search in time +}; + + +////////////////////////////////////////////////////////////////////////// +// SbiRTLData // +////////////////////////////////////////////////////////////////////////// + +SbiRTLData::SbiRTLData() +{ + pDir = 0; + nDirFlags = 0; + nCurDirPos = 0; + pWildCard = NULL; +} + +SbiRTLData::~SbiRTLData() +{ + delete pDir; + pDir = 0; + delete pWildCard; +} + +////////////////////////////////////////////////////////////////////////// +// SbiInstance // +////////////////////////////////////////////////////////////////////////// + +// 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out +// Die Entscheidung, ob StepPoint aufgerufen werden soll, wird anhand des +// CallLevels getroffen. Angehalten wird, wenn der aktuelle CallLevel <= +// nBreakCallLvl ist. Der aktuelle CallLevel kann niemals kleiner als 1 +// sein, da er beim Aufruf einer Methode (auch main) inkrementiert wird. +// Daher bedeutet ein BreakCallLvl von 0, dass das Programm gar nicht +// angehalten wird. +// (siehe auch step2.cxx, SbiRuntime::StepSTMNT() ) + +// Hilfsfunktion, um den BreakCallLevel gemaess der der Debug-Flags zu ermitteln +void SbiInstance::CalcBreakCallLevel( USHORT nFlags ) +{ + // Break-Flag wegfiltern + nFlags &= ~((USHORT)SbDEBUG_BREAK); + + USHORT nRet; + switch( nFlags ) + { + case SbDEBUG_STEPINTO: + nRet = nCallLvl + 1; // CallLevel+1 wird auch angehalten + break; + case SbDEBUG_STEPOVER | SbDEBUG_STEPINTO: + nRet = nCallLvl; // Aktueller CallLevel wird angehalten + break; + case SbDEBUG_STEPOUT: + nRet = nCallLvl - 1; // Kleinerer CallLevel wird angehalten + break; + case SbDEBUG_CONTINUE: + // Basic-IDE liefert 0 statt SbDEBUG_CONTINUE, also auch default=continue + default: + nRet = 0; // CallLevel ist immer >0 -> kein StepPoint + } + nBreakCallLvl = nRet; // Ergebnis uebernehmen +} + +SbiInstance::SbiInstance( StarBASIC* p ) +{ + pBasic = p; + pNext = NULL; + pRun = NULL; + pIosys = new SbiIoSystem; + pDdeCtrl = new SbiDdeControl; + pDllMgr = 0; // on demand + pNumberFormatter = 0; // on demand + nCallLvl = 0; + nBreakCallLvl = 0; + nErr = + nErl = 0; + bReschedule = TRUE; + bCompatibility = FALSE; +} + +SbiInstance::~SbiInstance() +{ + while( pRun ) + { + SbiRuntime* p = pRun->pNext; + delete pRun; + pRun = p; + } + delete pIosys; + delete pDdeCtrl; + delete pDllMgr; + delete pNumberFormatter; + + try + { + int nSize = ComponentVector.size(); + if( nSize ) + { + for( int i = nSize - 1 ; i >= 0 ; --i ) + { + Reference< XComponent > xDlgComponent = ComponentVector[i]; + if( xDlgComponent.is() ) + xDlgComponent->dispose(); + } + } + } + catch( const Exception& ) + { + DBG_ERROR( "SbiInstance::~SbiInstance: caught an exception while disposing the components!" ); + } + + ComponentVector.clear(); +} + +SbiDllMgr* SbiInstance::GetDllMgr() +{ + if( !pDllMgr ) + pDllMgr = new SbiDllMgr; + return pDllMgr; +} + +// #39629 NumberFormatter jetzt ueber statische Methode anlegen +SvNumberFormatter* SbiInstance::GetNumberFormatter() +{ + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + SvtSysLocale aSysLocale; + DateFormat eDate = aSysLocale.GetLocaleData().getDateFormat(); + if( pNumberFormatter ) + { + if( eLangType != meFormatterLangType || + eDate != meFormatterDateFormat ) + { + delete pNumberFormatter; + pNumberFormatter = NULL; + } + } + meFormatterLangType = eLangType; + meFormatterDateFormat = eDate; + if( !pNumberFormatter ) + PrepareNumberFormatter( pNumberFormatter, nStdDateIdx, nStdTimeIdx, nStdDateTimeIdx, + &meFormatterLangType, &meFormatterDateFormat ); + return pNumberFormatter; +} + +// #39629 NumberFormatter auch statisch anbieten +void SbiInstance::PrepareNumberFormatter( SvNumberFormatter*& rpNumberFormatter, + sal_uInt32 &rnStdDateIdx, sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx, + LanguageType* peFormatterLangType, DateFormat* peFormatterDateFormat ) +{ + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > + xFactory = comphelper::getProcessServiceFactory(); + + LanguageType eLangType; + if( peFormatterLangType ) + eLangType = *peFormatterLangType; + else + eLangType = GetpApp()->GetSettings().GetLanguage(); + + DateFormat eDate; + if( peFormatterDateFormat ) + eDate = *peFormatterDateFormat; + else + { + SvtSysLocale aSysLocale; + eDate = aSysLocale.GetLocaleData().getDateFormat(); + } + + rpNumberFormatter = new SvNumberFormatter( xFactory, eLangType ); + + xub_StrLen nCheckPos = 0; short nType; + rnStdTimeIdx = rpNumberFormatter->GetStandardFormat( NUMBERFORMAT_TIME, eLangType ); + + // Standard-Vorlagen des Formatters haben nur zweistellige + // Jahreszahl. Deshalb eigenes Format registrieren + + // HACK, da der Numberformatter in PutandConvertEntry die Platzhalter + // fuer Monat, Tag, Jahr nicht entsprechend der Systemeinstellung + // austauscht. Problem: Print Year(Date) unter engl. BS + // siehe auch svtools\source\sbx\sbxdate.cxx + + String aDateStr; + switch( eDate ) + { + case MDY: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("MM.TT.JJJJ") ); break; + case DMY: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("TT.MM.JJJJ") ); break; + case YMD: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("JJJJ.MM.TT") ); break; + default: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("MM.TT.JJJJ") ); + } + String aStr( aDateStr ); + rpNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, + rnStdDateIdx, LANGUAGE_GERMAN, eLangType ); + nCheckPos = 0; + String aStrHHMMSS( RTL_CONSTASCII_USTRINGPARAM(" HH:MM:SS") ); + aStr = aDateStr; + aStr += aStrHHMMSS; + rpNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, + rnStdDateTimeIdx, LANGUAGE_GERMAN, eLangType ); +} + + + +// Engine laufenlassen. Falls Flags == SbDEBUG_CONTINUE, Flags uebernehmen + +void SbiInstance::Stop() +{ + for( SbiRuntime* p = pRun; p; p = p->pNext ) + p->Stop(); +} + +// Allows Basic IDE to set watch mode to suppress errors +static bool bWatchMode = false; + +void setBasicWatchMode( bool bOn ) +{ + bWatchMode = bOn; +} + +void SbiInstance::Error( SbError n ) +{ + Error( n, String() ); +} + +void SbiInstance::Error( SbError n, const String& rMsg ) +{ + if( !bWatchMode ) + { + aErrorMsg = rMsg; + pRun->Error( n ); + } +} + +void SbiInstance::ErrorVB( sal_Int32 nVBNumber, const String& rMsg ) +{ + if( !bWatchMode ) + { + SbError n = StarBASIC::GetSfxFromVBError( static_cast< USHORT >( nVBNumber ) ); + if ( !n ) + n = nVBNumber; // force orig number, probably should have a specific table of vb ( localized ) errors + + aErrorMsg = rMsg; + SbiRuntime::translateErrorToVba( n, aErrorMsg ); + + bool bVBATranslationAlreadyDone = true; + pRun->Error( SbERR_BASIC_COMPAT, bVBATranslationAlreadyDone ); + } +} + +void SbiInstance::setErrorVB( sal_Int32 nVBNumber, const String& rMsg ) +{ + SbError n = StarBASIC::GetSfxFromVBError( static_cast< USHORT >( nVBNumber ) ); + if( !n ) + n = nVBNumber; // force orig number, probably should have a specific table of vb ( localized ) errors + + aErrorMsg = rMsg; + SbiRuntime::translateErrorToVba( n, aErrorMsg ); + + nErr = n; +} + + +void SbiInstance::FatalError( SbError n ) +{ + pRun->FatalError( n ); +} + +void SbiInstance::FatalError( SbError _errCode, const String& _details ) +{ + pRun->FatalError( _errCode, _details ); +} + +void SbiInstance::Abort() +{ + // Basic suchen, in dem der Fehler auftrat + StarBASIC* pErrBasic = GetCurrentBasic( pBasic ); + pErrBasic->RTError( nErr, aErrorMsg, pRun->nLine, pRun->nCol1, pRun->nCol2 ); + pBasic->Stop(); +} + +// Hilfsfunktion, um aktives Basic zu finden, kann ungleich pRTBasic sein +StarBASIC* GetCurrentBasic( StarBASIC* pRTBasic ) +{ + StarBASIC* pCurBasic = pRTBasic; + SbModule* pActiveModule = pRTBasic->GetActiveModule(); + if( pActiveModule ) + { + SbxObject* pParent = pActiveModule->GetParent(); + if( pParent && pParent->ISA(StarBASIC) ) + pCurBasic = (StarBASIC*)pParent; + } + return pCurBasic; +} + +SbModule* SbiInstance::GetActiveModule() +{ + if( pRun ) + return pRun->GetModule(); + else + return NULL; +} + +SbMethod* SbiInstance::GetCaller( USHORT nLevel ) +{ + SbiRuntime* p = pRun; + while( nLevel-- && p ) + p = p->pNext; + if( p ) + return p->GetCaller(); + else + return NULL; +} + +SbxArray* SbiInstance::GetLocals( SbMethod* pMeth ) +{ + SbiRuntime* p = pRun; + while( p && p->GetMethod() != pMeth ) + p = p->pNext; + if( p ) + return p->GetLocals(); + else + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +// SbiInstance // +////////////////////////////////////////////////////////////////////////// + +// Achtung: pMeth kann auch NULL sein (beim Aufruf des Init-Codes) + +SbiRuntime::SbiRuntime( SbModule* pm, SbMethod* pe, UINT32 nStart ) + : rBasic( *(StarBASIC*)pm->pParent ), pInst( pINST ), + pMod( pm ), pMeth( pe ), pImg( pMod->pImage ), m_nLastTime(0) +{ + nFlags = pe ? pe->GetDebugFlags() : 0; + pIosys = pInst->pIosys; + pArgvStk = NULL; + pGosubStk = NULL; + pForStk = NULL; + pError = NULL; + pErrCode = + pErrStmnt = + pRestart = NULL; + pNext = NULL; + pCode = + pStmnt = (const BYTE* ) pImg->GetCode() + nStart; + bRun = + bError = TRUE; + bInError = FALSE; + bBlocked = FALSE; + nLine = 0; + nCol1 = 0; + nCol2 = 0; + nExprLvl = 0; + nArgc = 0; + nError = 0; + nGosubLvl = 0; + nForLvl = 0; + nOps = 0; + refExprStk = new SbxArray; + SetVBAEnabled( pMod->IsVBACompat() ); +#if defined GCC + SetParameters( pe ? pe->GetParameters() : (class SbxArray *)NULL ); +#else + SetParameters( pe ? pe->GetParameters() : NULL ); +#endif + pRefSaveList = NULL; + pItemStoreList = NULL; +} + +SbiRuntime::~SbiRuntime() +{ + ClearGosubStack(); + ClearArgvStack(); + ClearForStack(); + + // #74254 Items zum Sichern temporaere Referenzen freigeben + ClearRefs(); + while( pItemStoreList ) + { + RefSaveItem* pToDeleteItem = pItemStoreList; + pItemStoreList = pToDeleteItem->pNext; + delete pToDeleteItem; + } +} + +void SbiRuntime::SetVBAEnabled(bool bEnabled ) +{ + bVBAEnabled = bEnabled; +} + +// Aufbau der Parameterliste. Alle ByRef-Parameter werden direkt +// uebernommen; von ByVal-Parametern werden Kopien angelegt. Falls +// ein bestimmter Datentyp verlangt wird, wird konvertiert. + +void SbiRuntime::SetParameters( SbxArray* pParams ) +{ + refParams = new SbxArray; + // fuer den Returnwert + refParams->Put( pMeth, 0 ); + + SbxInfo* pInfo = pMeth ? pMeth->GetInfo() : NULL; + USHORT nParamCount = pParams ? pParams->Count() : 1; + if( nParamCount > 1 ) + { + for( USHORT i = 1 ; i < nParamCount ; i++ ) + { + const SbxParamInfo* p = pInfo ? pInfo->GetParam( i ) : NULL; + + // #111897 ParamArray + if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) + { + SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); + USHORT nParamArrayParamCount = nParamCount - i; + pArray->unoAddDim( 0, nParamArrayParamCount - 1 ); + for( USHORT j = i ; j < nParamCount ; j++ ) + { + SbxVariable* v = pParams->Get( j ); + short nDimIndex = j - i; + pArray->Put( v, &nDimIndex ); + } + SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); + pArrayVar->SetFlag( SBX_READWRITE ); + pArrayVar->PutObject( pArray ); + refParams->Put( pArrayVar, i ); + + // Block ParamArray for missing parameter + pInfo = NULL; + break; + } + + SbxVariable* v = pParams->Get( i ); + // Methoden sind immer byval! + BOOL bByVal = v->IsA( TYPE(SbxMethod) ); + SbxDataType t = v->GetType(); + if( p ) + { + bByVal |= BOOL( ( p->eType & SbxBYREF ) == 0 ); + t = (SbxDataType) ( p->eType & 0x0FFF ); + + if( !bByVal && t != SbxVARIANT && + (!v->IsFixed() || (SbxDataType)(v->GetType() & 0x0FFF ) != t) ) + bByVal = TRUE; + } + if( bByVal ) + { + SbxVariable* v2 = new SbxVariable( t ); + v2->SetFlag( SBX_READWRITE ); + *v2 = *v; + refParams->Put( v2, i ); + } + else + { + if( t != SbxVARIANT && t != ( v->GetType() & 0x0FFF ) ) + { + // Array konvertieren?? + if( p && (p->eType & SbxARRAY) ) + Error( SbERR_CONVERSION ); + else + v->Convert( t ); + } + refParams->Put( v, i ); + } + if( p ) + refParams->PutAlias( p->aName, i ); + } + } + + // ParamArray for missing parameter + if( pInfo ) + { + // #111897 Check first missing parameter for ParamArray + const SbxParamInfo* p = pInfo->GetParam( nParamCount ); + if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) + { + SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); + pArray->unoAddDim( 0, -1 ); + SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); + pArrayVar->SetFlag( SBX_READWRITE ); + pArrayVar->PutObject( pArray ); + refParams->Put( pArrayVar, nParamCount ); + } + } +} + + +// Einen P-Code ausfuehren + +BOOL SbiRuntime::Step() +{ + if( bRun ) + { + // Unbedingt gelegentlich die Kontrolle abgeben! + if( !( ++nOps & 0xF ) && pInst->IsReschedule() && bStaticGlobalEnableReschedule ) + { + sal_uInt32 nTime = osl_getGlobalTimer(); + if (nTime - m_nLastTime > 5 ) // 20 ms + { + Application::Reschedule(); + m_nLastTime = nTime; + } + } + + // #i48868 blocked by next call level? + while( bBlocked ) + { + if( pInst->IsReschedule() && bStaticGlobalEnableReschedule ) + Application::Reschedule(); + } + +#ifdef DBG_TRACE_BASIC + UINT32 nPC = ( pCode - (const BYTE* )pImg->GetCode() ); + dbg_traceStep( pMod, nPC, pINST->nCallLvl ); +#endif + + SbiOpcode eOp = (SbiOpcode ) ( *pCode++ ); + UINT32 nOp1, nOp2; + if( eOp <= SbOP0_END ) + { + (this->*( aStep0[ eOp ] ) )(); + } + else if( eOp >= SbOP1_START && eOp <= SbOP1_END ) + { + nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; + + (this->*( aStep1[ eOp - SbOP1_START ] ) )( nOp1 ); + } + else if( eOp >= SbOP2_START && eOp <= SbOP2_END ) + { + nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; + nOp2 = *pCode++; nOp2 |= *pCode++ << 8; nOp2 |= *pCode++ << 16; nOp2 |= *pCode++ << 24; + (this->*( aStep2[ eOp - SbOP2_START ] ) )( nOp1, nOp2 ); + } + else + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + + // SBX-Fehler aufgetreten? + SbError nSbError = SbxBase::GetError(); + Error( ERRCODE_TOERROR(nSbError) ); // Warnings rausfiltern + + // AB 13.2.1997, neues Error-Handling: + // ACHTUNG: Hier kann nError auch dann gesetzt sein, wenn !nSbError, + // da nError jetzt auch von anderen RT-Instanzen gesetzt werden kann + + if( nError ) + SbxBase::ResetError(); + + // AB,15.3.96: Fehler nur anzeigen, wenn BASIC noch aktiv + // (insbesondere nicht nach Compiler-Fehlern zur Laufzeit) + if( nError && bRun ) + { +#ifdef DBG_TRACE_BASIC + SbError nTraceErr = nError; + String aTraceErrMsg = GetSbData()->aErrMsg; + bool bTraceErrHandled = true; +#endif + SbError err = nError; + ClearExprStack(); + nError = 0; + pInst->nErr = err; + pInst->nErl = nLine; + pErrCode = pCode; + pErrStmnt = pStmnt; + // An error occured in an error handler + // force parent handler ( if there is one ) + // to handle the error + bool bLetParentHandleThis = false; + + // Im Error Handler? Dann Std-Error + if ( !bInError ) + { + bInError = TRUE; + + if( !bError ) // On Error Resume Next + StepRESUME( 1 ); + else if( pError ) // On Error Goto ... + pCode = pError; + else + bLetParentHandleThis = true; + } + else + { + bLetParentHandleThis = true; + pError = NULL; //terminate the handler + } + if ( bLetParentHandleThis ) + { + // AB 13.2.1997, neues Error-Handling: + // Uebergeordnete Error-Handler beruecksichtigen + + // Wir haben keinen Error-Handler -> weiter oben suchen + SbiRuntime* pRtErrHdl = NULL; + SbiRuntime* pRt = this; + while( NULL != (pRt = pRt->pNext) ) + { + // Gibt es einen Error-Handler? + if( pRt->bError == FALSE || pRt->pError != NULL ) + { + pRtErrHdl = pRt; + break; + } + } + + // Error-Hdl gefunden? + if( pRtErrHdl ) + { + // (Neuen) Error-Stack anlegen + SbErrorStack*& rErrStack = GetSbData()->pErrStack; + if( rErrStack ) + delete rErrStack; + rErrStack = new SbErrorStack(); + + // Alle im Call-Stack darunter stehenden RTs manipulieren + pRt = this; + do + { + // Fehler setzen + pRt->nError = err; + if( pRt != pRtErrHdl ) + pRt->bRun = FALSE; + + // In Error-Stack eintragen + SbErrorStackEntry *pEntry = new SbErrorStackEntry + ( pRt->pMeth, pRt->nLine, pRt->nCol1, pRt->nCol2 ); + rErrStack->C40_INSERT(SbErrorStackEntry, pEntry, rErrStack->Count() ); + + // Nach RT mit Error-Handler aufhoeren + if( pRt == pRtErrHdl ) + break; + pRt = pRt->pNext; + } + while( pRt ); + } + // Kein Error-Hdl gefunden -> altes Vorgehen + else + { +#ifdef DBG_TRACE_BASIC + bTraceErrHandled = false; +#endif + pInst->Abort(); + } + + // ALT: Nur + // pInst->Abort(); + } + +#ifdef DBG_TRACE_BASIC + dbg_traceNotifyError( nTraceErr, aTraceErrMsg, bTraceErrHandled, pINST->nCallLvl ); +#endif + } + } + return bRun; +} + +void SbiRuntime::Error( SbError n, bool bVBATranslationAlreadyDone ) +{ + if( n ) + { + nError = n; + if( isVBAEnabled() && !bVBATranslationAlreadyDone ) + { + String aMsg = pInst->GetErrorMsg(); + sal_Int32 nVBAErrorNumber = translateErrorToVba( nError, aMsg ); + SbxVariable* pSbxErrObjVar = SbxErrObject::getErrObject(); + SbxErrObject* pGlobErr = static_cast< SbxErrObject* >( pSbxErrObjVar ); + if( pGlobErr != NULL ) + pGlobErr->setNumberAndDescription( nVBAErrorNumber, aMsg ); + + pInst->aErrorMsg = aMsg; + nError = SbERR_BASIC_COMPAT; + } + } +} + +void SbiRuntime::Error( SbError _errCode, const String& _details ) +{ + if ( _errCode ) + { + // Not correct for class module usage, remove for now + //OSL_ENSURE( pInst->pRun == this, "SbiRuntime::Error: can't propagate the error message details!" ); + if ( pInst->pRun == this ) + { + pInst->Error( _errCode, _details ); + //OSL_POSTCOND( nError == _errCode, "SbiRuntime::Error: the instance is expecte to propagate the error code back to me!" ); + } + else + { + nError = _errCode; + } + } +} + +void SbiRuntime::FatalError( SbError n ) +{ + StepSTDERROR(); + Error( n ); +} + +void SbiRuntime::FatalError( SbError _errCode, const String& _details ) +{ + StepSTDERROR(); + Error( _errCode, _details ); +} + +sal_Int32 SbiRuntime::translateErrorToVba( SbError nError, String& rMsg ) +{ + // If a message is defined use that ( in preference to + // the defined one for the error ) NB #TODO + // if there is an error defined it more than likely + // is not the one you want ( some are the same though ) + // we really need a new vba compatible error list + if ( !rMsg.Len() ) + { + // TEST, has to be vb here always +#ifdef DBG_UTIL + SbError nTmp = StarBASIC::GetSfxFromVBError( (USHORT)nError ); + DBG_ASSERT( nTmp, "No VB error!" ); +#endif + + StarBASIC::MakeErrorText( nError, rMsg ); + rMsg = StarBASIC::GetErrorText(); + if ( !rMsg.Len() ) // no message for err no, need localized resource here + rMsg = String( RTL_CONSTASCII_USTRINGPARAM("Internal Object Error:") ); + } + // no num? most likely then it *is* really a vba err + USHORT nVBErrorCode = StarBASIC::GetVBErrorCode( nError ); + sal_Int32 nVBAErrorNumber = ( nVBErrorCode == 0 ) ? nError : nVBErrorCode; + return nVBAErrorNumber; +} + +////////////////////////////////////////////////////////////////////////// +// +// Parameter, Locals, Caller +// +////////////////////////////////////////////////////////////////////////// + +SbMethod* SbiRuntime::GetCaller() +{ + return pMeth; +} + +SbxArray* SbiRuntime::GetLocals() +{ + return refLocals; +} + +SbxArray* SbiRuntime::GetParams() +{ + return refParams; +} + +////////////////////////////////////////////////////////////////////////// +// +// Stacks +// +////////////////////////////////////////////////////////////////////////// + +// Der Expression-Stack steht fuer die laufende Auswertung von Expressions +// zur Verfuegung. + +void SbiRuntime::PushVar( SbxVariable* pVar ) +{ + if( pVar ) + refExprStk->Put( pVar, nExprLvl++ ); +} + +SbxVariableRef SbiRuntime::PopVar() +{ +#ifdef DBG_UTIL + if( !nExprLvl ) + { + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + return new SbxVariable; + } +#endif + SbxVariableRef xVar = refExprStk->Get( --nExprLvl ); +#ifdef DBG_UTIL + if ( xVar->GetName().EqualsAscii( "Cells" ) ) + DBG_TRACE( "" ); +#endif + // Methods halten im 0.Parameter sich selbst, also weghauen + if( xVar->IsA( TYPE(SbxMethod) ) ) + xVar->SetParameters(0); + return xVar; +} + +BOOL SbiRuntime::ClearExprStack() +{ + // Achtung: Clear() reicht nicht, da Methods geloescht werden muessen + while ( nExprLvl ) + { + PopVar(); + } + refExprStk->Clear(); + return FALSE; +} + +// Variable auf dem Expression-Stack holen, ohne sie zu entfernen +// n zaehlt ab 0. + +SbxVariable* SbiRuntime::GetTOS( short n ) +{ + n = nExprLvl - n - 1; +#ifdef DBG_UTIL + if( n < 0 ) + { + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + return new SbxVariable; + } +#endif + return refExprStk->Get( (USHORT) n ); +} + +// Sicherstellen, dass TOS eine temporaere Variable ist + +void SbiRuntime::TOSMakeTemp() +{ + SbxVariable* p = refExprStk->Get( nExprLvl - 1 ); + if( p->GetRefCount() != 1 ) + { + SbxVariable* pNew = new SbxVariable( *p ); + pNew->SetFlag( SBX_READWRITE ); + refExprStk->Put( pNew, nExprLvl - 1 ); + } +} + +// Der GOSUB-Stack nimmt Returnadressen fuer GOSUBs auf + +void SbiRuntime::PushGosub( const BYTE* pc ) +{ + if( ++nGosubLvl > MAXRECURSION ) + StarBASIC::FatalError( SbERR_STACK_OVERFLOW ); + SbiGosubStack* p = new SbiGosubStack; + p->pCode = pc; + p->pNext = pGosubStk; + p->nStartForLvl = nForLvl; + pGosubStk = p; +} + +void SbiRuntime::PopGosub() +{ + if( !pGosubStk ) + Error( SbERR_NO_GOSUB ); + else + { + SbiGosubStack* p = pGosubStk; + pCode = p->pCode; + pGosubStk = p->pNext; + delete p; + nGosubLvl--; + } +} + +// Entleeren des GOSUB-Stacks + +void SbiRuntime::ClearGosubStack() +{ + SbiGosubStack* p; + while(( p = pGosubStk ) != NULL ) + pGosubStk = p->pNext, delete p; + nGosubLvl = 0; +} + +// Der Argv-Stack nimmt aktuelle Argument-Vektoren auf + +void SbiRuntime::PushArgv() +{ + SbiArgvStack* p = new SbiArgvStack; + p->refArgv = refArgv; + p->nArgc = nArgc; + nArgc = 1; + refArgv.Clear(); + p->pNext = pArgvStk; + pArgvStk = p; +} + +void SbiRuntime::PopArgv() +{ + if( pArgvStk ) + { + SbiArgvStack* p = pArgvStk; + pArgvStk = p->pNext; + refArgv = p->refArgv; + nArgc = p->nArgc; + delete p; + } +} + +// Entleeren des Argv-Stacks + +void SbiRuntime::ClearArgvStack() +{ + while( pArgvStk ) + PopArgv(); +} + +// Push des For-Stacks. Der Stack hat Inkrement, Ende, Beginn und Variable. +// Nach Aufbau des Stack-Elements ist der Stack leer. + +void SbiRuntime::PushFor() +{ + SbiForStack* p = new SbiForStack; + p->eForType = FOR_TO; + p->pNext = pForStk; + pForStk = p; + // Der Stack ist wie folgt aufgebaut: + p->refInc = PopVar(); + p->refEnd = PopVar(); + SbxVariableRef xBgn = PopVar(); + p->refVar = PopVar(); + *(p->refVar) = *xBgn; + nForLvl++; +} + +void SbiRuntime::PushForEach() +{ + SbiForStack* p = new SbiForStack; + p->pNext = pForStk; + pForStk = p; + + SbxVariableRef xObjVar = PopVar(); + SbxBase* pObj = xObjVar.Is() ? xObjVar->GetObject() : NULL; + if( pObj == NULL ) + { + Error( SbERR_NO_OBJECT ); + return; + } + + bool bError_ = false; + BasicCollection* pCollection; + SbxDimArray* pArray; + SbUnoObject* pUnoObj; + if( (pArray = PTR_CAST(SbxDimArray,pObj)) != NULL ) + { + p->eForType = FOR_EACH_ARRAY; + p->refEnd = (SbxVariable*)pArray; + + short nDims = pArray->GetDims(); + p->pArrayLowerBounds = new sal_Int32[nDims]; + p->pArrayUpperBounds = new sal_Int32[nDims]; + p->pArrayCurIndices = new sal_Int32[nDims]; + sal_Int32 lBound, uBound; + for( short i = 0 ; i < nDims ; i++ ) + { + pArray->GetDim32( i+1, lBound, uBound ); + p->pArrayCurIndices[i] = p->pArrayLowerBounds[i] = lBound; + p->pArrayUpperBounds[i] = uBound; + } + } + else if( (pCollection = PTR_CAST(BasicCollection,pObj)) != NULL ) + { + p->eForType = FOR_EACH_COLLECTION; + p->refEnd = pCollection; + p->nCurCollectionIndex = 0; + } + else if( (pUnoObj = PTR_CAST(SbUnoObject,pObj)) != NULL ) + { + // XEnumerationAccess? + Any aAny = pUnoObj->getUnoAny(); + Reference< XEnumerationAccess > xEnumerationAccess; + if( (aAny >>= xEnumerationAccess) ) + { + p->xEnumeration = xEnumerationAccess->createEnumeration(); + p->eForType = FOR_EACH_XENUMERATION; + } + else if ( isVBAEnabled() && pUnoObj->isNativeCOMObject() ) + { + uno::Reference< script::XInvocation > xInvocation; + if ( ( aAny >>= xInvocation ) && xInvocation.is() ) + { + try + { + p->xEnumeration = new ComEnumerationWrapper( xInvocation ); + p->eForType = FOR_EACH_XENUMERATION; + } + catch( uno::Exception& ) + {} + } + + if ( !p->xEnumeration.is() ) + bError_ = true; + } + else + { + bError_ = true; + } + } + else + { + bError_ = true; + } + + if( bError_ ) + { + Error( SbERR_CONVERSION ); + return; + } + + // Container variable + p->refVar = PopVar(); + nForLvl++; +} + +// Poppen des FOR-Stacks + +void SbiRuntime::PopFor() +{ + if( pForStk ) + { + SbiForStack* p = pForStk; + pForStk = p->pNext; + delete p; + nForLvl--; + } +} + +// Entleeren des FOR-Stacks + +void SbiRuntime::ClearForStack() +{ + while( pForStk ) + PopFor(); +} + +////////////////////////////////////////////////////////////////////////// +// +// DLL-Aufrufe +// +////////////////////////////////////////////////////////////////////////// + +void SbiRuntime::DllCall + ( const String& aFuncName, // Funktionsname + const String& aDLLName, // Name der DLL + SbxArray* pArgs, // Parameter (ab Index 1, kann NULL sein) + SbxDataType eResType, // Returnwert + BOOL bCDecl ) // TRUE: nach C-Konventionen +{ + // No DllCall for "virtual" portal users + if( needSecurityRestrictions() ) + { + StarBASIC::Error(SbERR_NOT_IMPLEMENTED); + return; + } + + // MUSS NOCH IMPLEMENTIERT WERDEN + /* + String aMsg; + aMsg = "FUNC="; + aMsg += pFunc; + aMsg += " DLL="; + aMsg += pDLL; + MessBox( NULL, WB_OK, String( "DLL-CALL" ), aMsg ).Execute(); + Error( SbERR_NOT_IMPLEMENTED ); + */ + + SbxVariable* pRes = new SbxVariable( eResType ); + SbiDllMgr* pDllMgr = pInst->GetDllMgr(); + SbError nErr = pDllMgr->Call( aFuncName, aDLLName, pArgs, *pRes, bCDecl ); + if( nErr ) + Error( nErr ); + PushVar( pRes ); +} +USHORT +SbiRuntime::GetImageFlag( USHORT n ) const +{ + return pImg->GetFlag( n ); +} +USHORT +SbiRuntime::GetBase() +{ + return pImg->GetBase(); +} diff --git a/basic/source/runtime/stdobj.cxx b/basic/source/runtime/stdobj.cxx new file mode 100644 index 000000000000..39f92afdea4a --- /dev/null +++ b/basic/source/runtime/stdobj.cxx @@ -0,0 +1,796 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include "runtime.hxx" +#include "stdobj.hxx" +#include <basic/sbstdobj.hxx> +#include "rtlproto.hxx" +#include "sbintern.hxx" + +// Das nArgs-Feld eines Tabelleneintrags ist wie folgt verschluesselt: +// Zur Zeit wird davon ausgegangen, dass Properties keine Parameter +// benoetigen! + +#define _ARGSMASK 0x007F // Bis zu 127 Argumente +#define _COMPTMASK 0x0080 // Only valid in compatibility mode +#define _RWMASK 0x0F00 // Maske fuer R/W-Bits +#define _TYPEMASK 0xF000 // Maske fuer den Typ des Eintrags + +#define _READ 0x0100 // kann gelesen werden +#define _BWRITE 0x0200 // kann as Lvalue verwendet werden +#define _LVALUE _BWRITE // kann as Lvalue verwendet werden +#define _READWRITE 0x0300 // beides +#define _OPT 0x0400 // Parameter ist optional +#define _CONST 0x0800 // Property ist const +#define _METHOD 0x3000 // Masken-Bits fuer eine Methode +#define _PROPERTY 0x4000 // Masken-Bit fuer eine Property +#define _OBJECT 0x8000 // Masken-Bit fuer ein Objekt + // Kombination von oberen Bits: +#define _FUNCTION 0x1100 // Maske fuer Function +#define _LFUNCTION 0x1300 // Maske fuer Function, die auch als Lvalue geht +#define _SUB 0x2100 // Maske fuer Sub +#define _ROPROP 0x4100 // Maske Read Only-Property +#define _WOPROP 0x4200 // Maske Write Only-Property +#define _RWPROP 0x4300 // Maske Read/Write-Property +#define _CPROP 0x4900 // Maske fuer Konstante + +struct Methods { + const char* pName; // Name des Eintrags + SbxDataType eType; // Datentyp + short nArgs; // Argumente und Flags + RtlCall pFunc; // Function Pointer + USHORT nHash; // Hashcode +}; + +static Methods aMethods[] = { + +{ "AboutStarBasic", SbxNULL, 1 | _FUNCTION, RTLNAME(AboutStarBasic),0 }, + { "Name", SbxSTRING, 0,NULL,0 }, +{ "Abs", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Abs),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "Array", SbxOBJECT, _FUNCTION, RTLNAME(Array),0 }, +{ "Asc", SbxLONG, 1 | _FUNCTION, RTLNAME(Asc),0 }, + { "string", SbxSTRING, 0,NULL,0 }, +{ "AscW", SbxLONG, 1 | _FUNCTION | _COMPTMASK, RTLNAME(Asc),0}, + { "string", SbxSTRING, 0,NULL,0 }, +{ "Atn", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Atn),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "ATTR_ARCHIVE", SbxINTEGER, _CPROP, RTLNAME(ATTR_ARCHIVE),0 }, +{ "ATTR_DIRECTORY", SbxINTEGER, _CPROP, RTLNAME(ATTR_DIRECTORY),0 }, +{ "ATTR_HIDDEN", SbxINTEGER, _CPROP, RTLNAME(ATTR_HIDDEN),0 }, +{ "ATTR_NORMAL", SbxINTEGER, _CPROP, RTLNAME(ATTR_NORMAL),0 }, +{ "ATTR_READONLY", SbxINTEGER, _CPROP, RTLNAME(ATTR_READONLY),0 }, +{ "ATTR_SYSTEM", SbxINTEGER, _CPROP, RTLNAME(ATTR_SYSTEM),0 }, +{ "ATTR_VOLUME", SbxINTEGER, _CPROP, RTLNAME(ATTR_VOLUME),0 }, + +{ "Beep", SbxNULL, _FUNCTION, RTLNAME(Beep),0 }, +{ "Blue", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Blue),0 }, + { "RGB-Value", SbxLONG, 0,NULL,0 }, + +{ "CallByName", SbxVARIANT, 3 | _FUNCTION, RTLNAME(CallByName),0 }, + { "Object", SbxOBJECT, 0,NULL,0 }, + { "ProcedureName",SbxSTRING, 0,NULL,0 }, + { "CallType", SbxINTEGER, 0,NULL,0 }, +{ "CBool", SbxBOOL, 1 | _FUNCTION, RTLNAME(CBool),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CByte", SbxBYTE, 1 | _FUNCTION, RTLNAME(CByte),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CCur", SbxCURRENCY, 1 | _FUNCTION, RTLNAME(CCur),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CDate", SbxDATE, 1 | _FUNCTION, RTLNAME(CDate),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CDateFromIso", SbxDATE, 1 | _FUNCTION, RTLNAME(CDateFromIso),0 }, + { "IsoDate", SbxSTRING, 0,NULL,0 }, +{ "CDateToIso", SbxSTRING, 1 | _FUNCTION, RTLNAME(CDateToIso),0 }, + { "Date", SbxDATE, 0,NULL,0 }, +{ "CDec", SbxDECIMAL, 1 | _FUNCTION, RTLNAME(CDec),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CDbl", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(CDbl),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CF_BITMAP", SbxINTEGER, _CPROP, RTLNAME(CF_BITMAP),0 }, +{ "CF_METAFILEPICT",SbxINTEGER, _CPROP, RTLNAME(CF_METAFILEPICT),0 }, +{ "CF_TEXT", SbxINTEGER, _CPROP, RTLNAME(CF_TEXT),0 }, +{ "ChDir", SbxNULL, 1 | _FUNCTION, RTLNAME(ChDir),0 }, + { "string", SbxSTRING, 0,NULL,0 }, +{ "ChDrive", SbxNULL, 1 | _FUNCTION, RTLNAME(ChDrive),0 }, + { "string", SbxSTRING, 0,NULL,0 }, + +{ "Choose", SbxVARIANT, 2 | _FUNCTION, RTLNAME(Choose),0 }, + { "Index", SbxINTEGER, 0,NULL,0 }, + { "Expression", SbxVARIANT, 0,NULL,0 }, + +{ "Chr", SbxSTRING, 1 | _FUNCTION, RTLNAME(Chr),0 }, + { "string", SbxINTEGER, 0,NULL,0 }, +{ "ChrW", SbxSTRING, 1 | _FUNCTION | _COMPTMASK, RTLNAME(Chr),0}, + { "string", SbxINTEGER, 0,NULL,0 }, + +{ "CInt", SbxINTEGER, 1 | _FUNCTION, RTLNAME(CInt),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CLEAR_ALLTABS", SbxINTEGER, _CPROP, RTLNAME(CLEAR_ALLTABS),0 }, +{ "CLEAR_TAB", SbxINTEGER, _CPROP, RTLNAME(CLEAR_TAB),0 }, +{ "CLng", SbxLONG, 1 | _FUNCTION, RTLNAME(CLng),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CompatibilityMode", SbxBOOL, 1 | _FUNCTION, RTLNAME(CompatibilityMode),0}, + { "bEnable", SbxBOOL, 0,NULL,0 }, +{ "ConvertFromUrl", SbxSTRING, 1 | _FUNCTION, RTLNAME(ConvertFromUrl),0 }, + { "Url", SbxSTRING, 0,NULL,0 }, +{ "ConvertToUrl", SbxSTRING, 1 | _FUNCTION, RTLNAME(ConvertToUrl),0 }, + { "SystemPath", SbxSTRING, 0,NULL,0 }, +{ "Cos", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Cos),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "CreateObject", SbxOBJECT, 1 | _FUNCTION, RTLNAME( CreateObject ),0 }, + { "class", SbxSTRING, 0,NULL,0 }, +{ "CreateUnoListener",SbxOBJECT, 1 | _FUNCTION, RTLNAME( CreateUnoListener ),0 }, + { "prefix", SbxSTRING, 0,NULL,0 }, + { "typename", SbxSTRING, 0,NULL,0 }, +{ "CreateUnoDialog",SbxOBJECT, 2 | _FUNCTION, RTLNAME( CreateUnoDialog ),0 }, + { "dialoglibrary",SbxOBJECT, 0,NULL,0 }, + { "dialogname", SbxSTRING, 0,NULL,0 }, +{ "CreateUnoService",SbxOBJECT, 1 | _FUNCTION, RTLNAME( CreateUnoService ),0 }, + { "servicename", SbxSTRING, 0,NULL,0 }, +{ "CreateUnoServiceWithArguments",SbxOBJECT, 2 | _FUNCTION, RTLNAME( CreateUnoServiceWithArguments ),0 }, + { "servicename", SbxSTRING, 0,NULL,0 }, + { "arguments", SbxARRAY, 0,NULL,0 }, +{ "CreateUnoStruct",SbxOBJECT, 1 | _FUNCTION, RTLNAME( CreateUnoStruct ),0 }, + { "classname", SbxSTRING, 0,NULL,0 }, +{ "CreateUnoValue", SbxOBJECT, 2 | _FUNCTION, RTLNAME( CreateUnoValue ),0 }, + { "type", SbxSTRING, 0,NULL,0 }, + { "value", SbxVARIANT, 0,NULL,0 }, +{ "CreatePropertySet",SbxOBJECT, 1 | _FUNCTION, RTLNAME( CreatePropertySet ),0 }, + { "values", SbxARRAY, 0,NULL,0 }, +{ "CSng", SbxSINGLE, 1 | _FUNCTION, RTLNAME(CSng),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CStr", SbxSTRING, 1 | _FUNCTION, RTLNAME(CStr),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CurDir", SbxSTRING, 1 | _FUNCTION, RTLNAME(CurDir),0 }, + { "string", SbxSTRING, 0,NULL,0 }, +{ "CVar", SbxVARIANT, 1 | _FUNCTION, RTLNAME(CVar),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, +{ "CVErr", SbxVARIANT, 1 | _FUNCTION, RTLNAME(CVErr),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, + +{ "Date", SbxDATE, _LFUNCTION,RTLNAME(Date),0 }, +{ "DateAdd", SbxDATE, 3 | _FUNCTION, RTLNAME(DateAdd),0 }, + { "Interval", SbxSTRING, 0,NULL,0 }, + { "Number", SbxLONG, 0,NULL,0 }, + { "Date", SbxDATE, 0,NULL,0 }, +{ "DateDiff", SbxDOUBLE, 5 | _FUNCTION, RTLNAME(DateDiff),0 }, + { "Interval", SbxSTRING, 0,NULL,0 }, + { "Date1", SbxDATE, 0,NULL,0 }, + { "Date2", SbxDATE, 0,NULL,0 }, + { "Firstdayofweek" , SbxINTEGER, _OPT,NULL,0 }, + { "Firstweekofyear", SbxINTEGER, _OPT,NULL,0 }, +{ "DatePart", SbxLONG, 4 | _FUNCTION, RTLNAME(DatePart),0 }, + { "Interval", SbxSTRING, 0,NULL,0 }, + { "Date", SbxDATE, 0,NULL,0 }, + { "Firstdayofweek" , SbxINTEGER, _OPT, NULL,0 }, + { "Firstweekofyear", SbxINTEGER, _OPT, NULL,0 }, +{ "DateSerial", SbxDATE, 3 | _FUNCTION, RTLNAME(DateSerial),0 }, + { "Year", SbxINTEGER, 0,NULL,0 }, + { "Month", SbxINTEGER, 0,NULL,0 }, + { "Day", SbxINTEGER, 0,NULL,0 }, +{ "DateValue", SbxDATE, 1 | _FUNCTION, RTLNAME(DateValue),0 }, + { "String", SbxSTRING, 0,NULL,0 }, +{ "Day", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Day),0 }, + { "Date", SbxDATE, 0,NULL,0 }, +{ "Ddeexecute", SbxNULL, 2 | _FUNCTION, RTLNAME(DDEExecute),0 }, + { "Channel", SbxLONG, 0,NULL,0 }, + { "Command", SbxSTRING, 0,NULL,0 }, +{ "Ddeinitiate", SbxINTEGER, 2 | _FUNCTION, RTLNAME(DDEInitiate),0 }, + { "Application", SbxSTRING, 0,NULL,0 }, + { "Topic", SbxSTRING, 0,NULL,0 }, +{ "Ddepoke", SbxNULL, 3 | _FUNCTION, RTLNAME(DDEPoke),0 }, + { "Channel", SbxLONG, 0,NULL,0 }, + { "Item", SbxSTRING, 0,NULL,0 }, + { "Data", SbxSTRING, 0,NULL,0 }, +{ "Dderequest", SbxSTRING, 2 | _FUNCTION, RTLNAME(DDERequest),0 }, + { "Channel", SbxLONG, 0,NULL,0 }, + { "Item", SbxSTRING, 0,NULL,0 }, +{ "Ddeterminate", SbxNULL, 1 | _FUNCTION, RTLNAME(DDETerminate),0 }, + { "Channel", SbxLONG, 0,NULL,0 }, +{ "Ddeterminateall", SbxNULL, _FUNCTION, RTLNAME(DDETerminateAll),0 }, +{ "DimArray", SbxOBJECT, _FUNCTION, RTLNAME(DimArray),0 }, +{ "Dir", SbxSTRING, 2 | _FUNCTION, RTLNAME(Dir),0 }, + { "FileSpec", SbxSTRING, _OPT, NULL,0 }, + { "attrmask", SbxINTEGER, _OPT, NULL,0 }, +{ "DoEvents", SbxEMPTY, _FUNCTION, RTLNAME(DoEvents),0 }, +{ "DumpAllObjects", SbxEMPTY, 2 | _SUB, RTLNAME(DumpAllObjects),0 }, + { "FileSpec", SbxSTRING, 0,NULL,0 }, + { "DumpAll", SbxINTEGER, _OPT, NULL,0 }, + +{ "Empty", SbxVARIANT, _CPROP, RTLNAME(Empty),0 }, +{ "EqualUnoObjects",SbxBOOL, 2 | _FUNCTION, RTLNAME(EqualUnoObjects),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "EnableReschedule", SbxNULL, 1 | _FUNCTION, RTLNAME(EnableReschedule),0}, + { "bEnable", SbxBOOL, 0,NULL,0 }, +{ "Environ", SbxSTRING, 1 | _FUNCTION, RTLNAME(Environ),0 }, + { "Environmentstring",SbxSTRING, 0,NULL,0 }, +{ "EOF", SbxBOOL, 1 | _FUNCTION, RTLNAME(EOF),0 }, + { "Channel", SbxINTEGER, 0,NULL,0 }, +{ "Erl", SbxLONG, _ROPROP, RTLNAME( Erl ),0 }, +{ "Err", SbxVARIANT, _RWPROP, RTLNAME( Err ),0 }, +{ "Error", SbxSTRING, 1 | _FUNCTION, RTLNAME( Error ),0 }, + { "code", SbxLONG, 0,NULL,0 }, +{ "Exp", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Exp),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, + +{ "False", SbxBOOL, _CPROP, RTLNAME(False),0 }, +{ "FileAttr", SbxINTEGER, 2 | _FUNCTION, RTLNAME(FileAttr),0 }, + { "Channel", SbxINTEGER, 0,NULL,0 }, + { "Attributes", SbxINTEGER, 0,NULL,0 }, +{ "FileCopy", SbxNULL, 2 | _FUNCTION, RTLNAME(FileCopy),0 }, + { "Source", SbxSTRING, 0,NULL,0 }, + { "Destination", SbxSTRING, 0,NULL,0 }, +{ "FileDateTime", SbxSTRING, 1 | _FUNCTION, RTLNAME(FileDateTime),0 }, + { "filename", SbxSTRING, 0,NULL,0 }, +{ "FileExists", SbxBOOL, 1 | _FUNCTION, RTLNAME(FileExists),0 }, + { "filename", SbxSTRING, 0,NULL,0 }, +{ "FileLen", SbxLONG, 1 | _FUNCTION, RTLNAME(FileLen),0 }, + { "filename", SbxSTRING, 0,NULL,0 }, +{ "FindObject", SbxOBJECT, 1 | _FUNCTION, RTLNAME(FindObject),0 }, + { "Name", SbxSTRING, 0,NULL,0 }, +{ "FindPropertyObject", SbxOBJECT, 2 | _FUNCTION, RTLNAME(FindPropertyObject),0 }, + { "Object", SbxOBJECT, 0,NULL,0 }, + { "Name", SbxSTRING, 0,NULL,0 }, +{ "Fix", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Fix),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "Format", SbxSTRING, 2 | _FUNCTION, RTLNAME(Format),0 }, + { "expression", SbxVARIANT, 0,NULL,0 }, + { "format", SbxSTRING, _OPT, NULL,0 }, +{ "FormatDateTime", SbxSTRING, 2 | _FUNCTION | _COMPTMASK, RTLNAME(FormatDateTime),0 }, + { "Date", SbxDATE, 0,NULL,0 }, + { "NamedFormat", SbxINTEGER, _OPT, NULL,0 }, +{ "FRAMEANCHORCHAR", SbxINTEGER, _CPROP, RTLNAME(FRAMEANCHORCHAR),0 }, +{ "FRAMEANCHORPAGE", SbxINTEGER, _CPROP, RTLNAME(FRAMEANCHORPAGE),0 }, +{ "FRAMEANCHORPARA", SbxINTEGER, _CPROP, RTLNAME(FRAMEANCHORPARA),0 }, +{ "FreeFile", SbxINTEGER, _FUNCTION, RTLNAME(FreeFile),0 }, +{ "FreeLibrary", SbxNULL, 1 | _FUNCTION, RTLNAME(FreeLibrary),0 }, + { "Modulename", SbxSTRING, 0,NULL,0 }, + +{ "Get", SbxNULL, 3 | _FUNCTION, RTLNAME(Get),0 }, + { "filenumber", SbxINTEGER, 0,NULL,0 }, + { "recordnumber", SbxLONG, 0,NULL,0 }, + { "variablename", SbxVARIANT, 0,NULL,0 }, +{ "GetAttr", SbxINTEGER, 1 | _FUNCTION, RTLNAME(GetAttr),0 }, + { "filename", SbxSTRING, 0,NULL,0 }, +{ "GetDefaultContext", SbxOBJECT, 0 | _FUNCTION, RTLNAME(GetDefaultContext),0 }, +{ "GetDialogZoomFactorX", SbxDOUBLE, _FUNCTION,RTLNAME(GetDialogZoomFactorX),0 }, +{ "GetDialogZoomFactorY", SbxDOUBLE, _FUNCTION,RTLNAME(GetDialogZoomFactorY),0 }, +{ "GetGUIType", SbxINTEGER, _FUNCTION,RTLNAME(GetGUIType),0 }, +{ "GetGUIVersion", SbxLONG, _FUNCTION,RTLNAME(GetGUIVersion),0 }, +{ "GetPathSeparator", SbxSTRING, _FUNCTION,RTLNAME(GetPathSeparator),0 }, +{ "GetProcessServiceManager", SbxOBJECT, 0 | _FUNCTION, RTLNAME(GetProcessServiceManager),0 }, +{ "GetSolarVersion", SbxLONG, _FUNCTION,RTLNAME(GetSolarVersion),0 }, +{ "GetSystemTicks", SbxLONG, _FUNCTION,RTLNAME(GetSystemTicks),0 }, +{ "GetSystemType", SbxINTEGER, _FUNCTION,RTLNAME(GetSystemType),0 }, +{ "GlobalScope", SbxOBJECT, _FUNCTION,RTLNAME(GlobalScope),0 }, +{ "Green", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Green),0 }, + { "RGB-Value", SbxLONG, 0,NULL,0 }, + +{ "HasUnoInterfaces", SbxBOOL, 1 | _FUNCTION, RTLNAME(HasUnoInterfaces),0}, + { "InterfaceName",SbxSTRING, 0,NULL,0 }, +{ "Hex", SbxSTRING, 1 | _FUNCTION, RTLNAME(Hex),0 }, + { "number", SbxLONG, 0,NULL,0 }, +{ "Hour", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Hour),0 }, + { "Date", SbxDATE, 0,NULL,0 }, + +{ "IDABORT", SbxINTEGER, _CPROP, RTLNAME(IDABORT),0 }, +{ "IDCANCEL", SbxINTEGER, _CPROP, RTLNAME(IDCANCEL),0 }, +{ "IDNO", SbxINTEGER, _CPROP, RTLNAME(IDNO),0 }, +{ "IDOK", SbxINTEGER, _CPROP, RTLNAME(IDOK),0 }, +{ "IDRETRY", SbxINTEGER, _CPROP, RTLNAME(IDRETRY),0 }, +{ "IDYES", SbxINTEGER, _CPROP, RTLNAME(IDYES),0 }, + +{ "Iif", SbxVARIANT, 3 | _FUNCTION, RTLNAME(Iif),0 }, + { "Bool", SbxBOOL, 0,NULL,0 }, + { "Variant1", SbxVARIANT, 0,NULL,0 }, + { "Variant2", SbxVARIANT, 0,NULL,0 }, + +{ "Input", SbxSTRING, 2 | _FUNCTION | _COMPTMASK, RTLNAME(Input),0}, + { "Number", SbxLONG, 0,NULL,0 }, + { "FileNumber", SbxLONG, 0,NULL,0 }, +{ "InputBox", SbxSTRING, 5 | _FUNCTION, RTLNAME(InputBox),0 }, + { "Prompt", SbxSTRING, 0,NULL,0 }, + { "Title", SbxSTRING, _OPT, NULL,0 }, + { "Default", SbxSTRING, _OPT, NULL,0 }, + { "XPosTwips", SbxLONG, _OPT, NULL,0 }, + { "YPosTwips", SbxLONG, _OPT, NULL,0 }, +{ "InStr", SbxLONG, 4 | _FUNCTION, RTLNAME(InStr),0 }, + { "Start", SbxSTRING, _OPT, NULL,0 }, + { "String1", SbxSTRING, 0,NULL,0 }, + { "String2", SbxSTRING, 0,NULL,0 }, + { "Compare", SbxINTEGER, _OPT, NULL,0 }, +{ "InStrRev", SbxLONG, 4 | _FUNCTION | _COMPTMASK, RTLNAME(InStrRev),0}, + { "String1", SbxSTRING, 0,NULL,0 }, + { "String2", SbxSTRING, 0,NULL,0 }, + { "Start", SbxSTRING, _OPT, NULL,0 }, + { "Compare", SbxINTEGER, _OPT, NULL,0 }, +{ "Int", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Int),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "IsArray", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsArray),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsDate", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsDate),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsEmpty", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsEmpty),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsError", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsError),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsMissing", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsMissing),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsNull", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsNull),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsNumeric", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsNumeric),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsObject", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsObject),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "IsUnoStruct", SbxBOOL, 1 | _FUNCTION, RTLNAME(IsUnoStruct),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "Join", SbxSTRING, 2 | _FUNCTION, RTLNAME(Join),0 }, + { "list", SbxOBJECT, 0,NULL,0 }, + { "delimiter", SbxSTRING, 0,NULL,0 }, +{ "Kill", SbxNULL, 1 | _FUNCTION, RTLNAME(Kill),0 }, + { "filespec", SbxSTRING, 0,NULL,0 }, +{ "LBound", SbxLONG, 1 | _FUNCTION, RTLNAME(LBound),0 }, + { "Variant", SbxVARIANT, 0,NULL,0 }, +{ "LCase", SbxSTRING, 1 | _FUNCTION, RTLNAME(LCase),0 }, + { "string", SbxSTRING, 0,NULL,0 }, +{ "Left", SbxSTRING, 2 | _FUNCTION, RTLNAME(Left),0 }, + { "String", SbxSTRING, 0,NULL,0 }, + { "Count", SbxLONG, 0,NULL,0 }, +{ "Len", SbxLONG, 1 | _FUNCTION, RTLNAME(Len),0 }, + { "StringOrVariant", SbxVARIANT, 0,NULL,0 }, +{ "LenB", SbxLONG, 1 | _FUNCTION, RTLNAME(Len),0 }, + { "StringOrVariant", SbxVARIANT, 0,NULL,0 }, +{ "Load", SbxNULL, 1 | _FUNCTION, RTLNAME(Load),0 }, + { "object", SbxOBJECT, 0,NULL,0 }, +{ "LoadPicture", SbxOBJECT, 1 | _FUNCTION, RTLNAME(LoadPicture),0 }, + { "string", SbxSTRING, 0,NULL,0 }, +{ "Loc", SbxLONG, 1 | _FUNCTION, RTLNAME(Loc),0 }, + { "Channel", SbxINTEGER, 0,NULL,0 }, +{ "Lof", SbxLONG, 1 | _FUNCTION, RTLNAME(Lof),0 }, + { "Channel", SbxINTEGER, 0,NULL,0 }, +{ "Log", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Log),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "LTrim", SbxSTRING, 1 | _FUNCTION, RTLNAME(LTrim),0 }, + { "string", SbxSTRING, 0,NULL,0 }, + +{ "MB_ABORTRETRYIGNORE", SbxINTEGER, _CPROP, RTLNAME(MB_ABORTRETRYIGNORE),0}, +{ "MB_APPLMODAL", SbxINTEGER, _CPROP, RTLNAME(MB_APPLMODAL),0 }, +{ "MB_DEFBUTTON1", SbxINTEGER, _CPROP, RTLNAME(MB_DEFBUTTON1),0 }, +{ "MB_DEFBUTTON2", SbxINTEGER, _CPROP, RTLNAME(MB_DEFBUTTON2),0 }, +{ "MB_DEFBUTTON3", SbxINTEGER, _CPROP, RTLNAME(MB_DEFBUTTON3),0 }, +{ "MB_ICONEXCLAMATION", SbxINTEGER, _CPROP, RTLNAME(MB_ICONEXCLAMATION),0}, +{ "MB_ICONINFORMATION", SbxINTEGER, _CPROP, RTLNAME(MB_ICONINFORMATION),0}, +{ "MB_ICONQUESTION",SbxINTEGER, _CPROP, RTLNAME(MB_ICONQUESTION),0 }, +{ "MB_ICONSTOP", SbxINTEGER, _CPROP, RTLNAME(MB_ICONSTOP),0 }, +{ "MB_OK", SbxINTEGER, _CPROP, RTLNAME(MB_OK),0 }, +{ "MB_OKCANCEL", SbxINTEGER, _CPROP, RTLNAME(MB_OKCANCEL),0 }, +{ "MB_RETRYCANCEL", SbxINTEGER, _CPROP, RTLNAME(MB_RETRYCANCEL),0 }, +{ "MB_SYSTEMMODAL", SbxINTEGER, _CPROP, RTLNAME(MB_SYSTEMMODAL),0 }, +{ "MB_YESNO", SbxINTEGER, _CPROP, RTLNAME(MB_YESNO),0 }, +{ "MB_YESNOCANCEL", SbxINTEGER, _CPROP, RTLNAME(MB_YESNOCANCEL),0 }, + +{ "Me", SbxOBJECT, 0 | _FUNCTION | _COMPTMASK, RTLNAME(Me),0 }, +{ "Mid", SbxSTRING, 3 | _LFUNCTION,RTLNAME(Mid),0 }, + { "String", SbxSTRING, 0,NULL,0 }, + { "StartPos", SbxLONG, 0,NULL,0 }, + { "Length", SbxLONG, _OPT, NULL,0 }, +{ "Minute", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Minute),0 }, + { "Date", SbxDATE, 0,NULL,0 }, +{ "MkDir", SbxNULL, 1 | _FUNCTION, RTLNAME(MkDir),0 }, + { "pathname", SbxSTRING, 0,NULL,0 }, +{ "Month", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Month),0 }, + { "Date", SbxDATE, 0,NULL,0 }, +{ "MonthName", SbxSTRING, 2 | _FUNCTION | _COMPTMASK, RTLNAME(MonthName),0 }, + { "Month", SbxINTEGER, 0,NULL,0 }, + { "Abbreviate", SbxBOOL, _OPT, NULL,0 }, +{ "MsgBox", SbxINTEGER, 5 | _FUNCTION, RTLNAME(MsgBox),0 }, + { "Prompt", SbxSTRING, 0,NULL,0 }, + { "Buttons", SbxINTEGER, _OPT, NULL,0 }, + { "Title", SbxSTRING, _OPT, NULL,0 }, + { "Helpfile", SbxSTRING, _OPT, NULL,0 }, + { "Context", SbxINTEGER, _OPT, NULL,0 }, + +{ "Nothing", SbxOBJECT, _CPROP, RTLNAME(Nothing),0 }, +{ "Now", SbxDATE, _FUNCTION, RTLNAME(Now),0 }, +{ "Null", SbxNULL, _CPROP, RTLNAME(Null),0 }, + +{ "Oct", SbxSTRING, 1 | _FUNCTION, RTLNAME(Oct),0 }, + { "number", SbxLONG, 0,NULL,0 }, + +{ "Partition", SbxSTRING, 4 | _FUNCTION, RTLNAME(Partition),0 }, + { "number", SbxLONG, 0,NULL,0 }, + { "start", SbxLONG, 0,NULL,0 }, + { "stop", SbxLONG, 0,NULL,0 }, + { "interval", SbxLONG, 0,NULL,0 }, +{ "Pi", SbxDOUBLE, _CPROP, RTLNAME(PI),0 }, +{ "Put", SbxNULL, 3 | _FUNCTION, RTLNAME(Put),0 }, + { "filenumber", SbxINTEGER, 0,NULL,0 }, + { "recordnumber", SbxLONG, 0,NULL,0 }, + { "variablename", SbxVARIANT, 0,NULL,0 }, + +{ "QBColor", SbxLONG, 1 | _FUNCTION, RTLNAME(QBColor),0 }, + { "number", SbxINTEGER, 0,NULL,0 }, + +{ "Randomize", SbxNULL, 1 | _FUNCTION, RTLNAME(Randomize),0 }, + { "Number", SbxDOUBLE, _OPT, NULL,0 }, +{ "Red", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Red),0 }, + { "RGB-Value", SbxLONG, 0,NULL,0 }, +{ "Reset", SbxNULL, 0 | _FUNCTION, RTLNAME(Reset),0 }, +{ "ResolvePath", SbxSTRING, 1 | _FUNCTION, RTLNAME(ResolvePath),0 }, + { "Path", SbxSTRING, 0,NULL,0 }, +{ "RGB", SbxLONG, 3 | _FUNCTION, RTLNAME(RGB),0 }, + { "Red", SbxINTEGER, 0,NULL,0 }, + { "Green", SbxINTEGER, 0,NULL,0 }, + { "Blue", SbxINTEGER, 0,NULL,0 }, +{ "Replace", SbxSTRING, 6 | _FUNCTION, RTLNAME(Replace),0 }, + { "Expression", SbxSTRING, 0,NULL,0 }, + { "Find", SbxSTRING, 0,NULL,0 }, + { "Replace", SbxSTRING, 0,NULL,0 }, + { "Start", SbxINTEGER, _OPT, NULL,0 }, + { "Count", SbxINTEGER, _OPT, NULL,0 }, + { "Compare", SbxINTEGER, _OPT, NULL,0 }, +{ "Right", SbxSTRING, 2 | _FUNCTION, RTLNAME(Right),0 }, + { "String", SbxSTRING, 0,NULL,0 }, + { "Count", SbxLONG, 0,NULL,0 }, +{ "RmDir", SbxNULL, 1 | _FUNCTION, RTLNAME(RmDir),0 }, + { "pathname", SbxSTRING, 0,NULL,0 }, +{ "Round", SbxDOUBLE, 2 | _FUNCTION | _COMPTMASK, RTLNAME(Round),0}, + { "Expression", SbxDOUBLE, 0,NULL,0 }, + { "Numdecimalplaces", SbxINTEGER, _OPT, NULL,0 }, +{ "Rnd", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Rnd),0 }, + { "Number", SbxDOUBLE, _OPT, NULL,0 }, +{ "RTL", SbxOBJECT, 0 | _FUNCTION | _COMPTMASK, RTLNAME(RTL),0}, +{ "RTrim", SbxSTRING, 1 | _FUNCTION, RTLNAME(RTrim),0 }, + { "string", SbxSTRING, 0,NULL,0 }, + +{ "SavePicture", SbxNULL, 2 | _FUNCTION, RTLNAME(SavePicture),0 }, + { "object", SbxOBJECT, 0,NULL,0 }, + { "string", SbxSTRING, 0,NULL,0 }, +{ "Second", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Second),0 }, + { "Date", SbxDATE, 0,NULL,0 }, +{ "Seek", SbxLONG, 1 | _FUNCTION, RTLNAME(Seek),0 }, + { "Channel", SbxINTEGER, 0,NULL,0 }, +{ "SendKeys", SbxNULL, 2 | _FUNCTION, RTLNAME(SendKeys),0 }, + { "String", SbxSTRING, 0,NULL,0 }, + { "Wait", SbxBOOL, _OPT, NULL,0 }, +{ "SetAttr", SbxNULL, 2 | _FUNCTION, RTLNAME(SetAttr),0 }, + { "File" , SbxSTRING, 0,NULL,0 }, + { "Attributes", SbxINTEGER, 0,NULL,0 }, +{ "SET_OFF", SbxINTEGER, _CPROP, RTLNAME(SET_OFF),0 }, +{ "SET_ON", SbxINTEGER, _CPROP, RTLNAME(SET_ON),0 }, +{ "SET_TAB", SbxINTEGER, _CPROP, RTLNAME(SET_TAB),0 }, +{ "Sgn", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Sgn),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "Shell", SbxLONG, 2 | _FUNCTION, RTLNAME(Shell),0 }, + { "Commandstring",SbxSTRING, 0,NULL,0 }, + { "WindowStyle", SbxINTEGER, _OPT, NULL,0 }, +{ "Sin", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Sin),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "Space", SbxSTRING, 1 | _FUNCTION, RTLNAME(Space),0 }, + { "string", SbxLONG, 0,NULL,0 }, +{ "Spc", SbxSTRING, 1 | _FUNCTION, RTLNAME(Spc),0 }, + { "Count", SbxLONG, 0,NULL,0 }, +{ "Split", SbxOBJECT, 3 | _FUNCTION, RTLNAME(Split),0 }, + { "expression", SbxSTRING, 0,NULL,0 }, + { "delimiter", SbxSTRING, 0,NULL,0 }, + { "count", SbxLONG, 0,NULL,0 }, +{ "Sqr", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Sqr),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "Str", SbxSTRING, 1 | _FUNCTION, RTLNAME(Str),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "StrComp", SbxINTEGER, 3 | _FUNCTION, RTLNAME(StrComp),0 }, + { "String1", SbxSTRING, 0,NULL,0 }, + { "String2", SbxSTRING, 0,NULL,0 }, + { "Compare", SbxINTEGER, _OPT, NULL,0 }, +{ "StrConv", SbxOBJECT, 3 | _FUNCTION, RTLNAME(StrConv),0 }, + { "String", SbxSTRING, 0,NULL,0 }, + { "Conversion", SbxSTRING, 0,NULL,0 }, + { "LCID", SbxINTEGER, _OPT,NULL,0 }, +{ "String", SbxSTRING, 2 | _FUNCTION, RTLNAME(String),0 }, + { "Count", SbxLONG, 0,NULL,0 }, + { "Filler", SbxVARIANT, 0,NULL,0 }, +{ "StrReverse", SbxSTRING, 1 | _FUNCTION | _COMPTMASK, RTLNAME(StrReverse),0 }, + { "String1", SbxSTRING, 0,NULL,0 }, +{ "Switch", SbxVARIANT, 2 | _FUNCTION, RTLNAME(Switch),0 }, + { "Expression", SbxVARIANT, 0,NULL,0 }, + { "Value", SbxVARIANT, 0,NULL,0 }, + +{ "Tan", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Tan),0 }, + { "number", SbxDOUBLE, 0,NULL,0 }, +{ "Time", SbxVARIANT, _LFUNCTION,RTLNAME(Time),0 }, +{ "Timer", SbxDATE, _FUNCTION, RTLNAME(Timer),0 }, +{ "TimeSerial", SbxDATE, 3 | _FUNCTION, RTLNAME(TimeSerial),0 }, + { "Hour", SbxLONG, 0,NULL,0 }, + { "Minute", SbxLONG, 0,NULL,0 }, + { "Second", SbxLONG, 0,NULL,0 }, +{ "TimeValue", SbxDATE, 1 | _FUNCTION, RTLNAME(TimeValue),0 }, + { "String", SbxSTRING, 0,NULL,0 }, +{ "TOGGLE", SbxINTEGER, _CPROP, RTLNAME(TOGGLE),0 }, +#ifdef DBG_TRACE_BASIC +{ "TraceCommand", SbxNULL, 1 | _FUNCTION, RTLNAME(TraceCommand),0 }, + { "Command", SbxSTRING, 0,NULL,0 }, +#endif +{ "Trim", SbxSTRING, 1 | _FUNCTION, RTLNAME(Trim),0 }, + { "String", SbxSTRING, 0,NULL,0 }, +{ "True", SbxBOOL, _CPROP, RTLNAME(True),0 }, +{ "TwipsPerPixelX", SbxLONG, _FUNCTION, RTLNAME(TwipsPerPixelX),0 }, +{ "TwipsPerPixelY", SbxLONG, _FUNCTION, RTLNAME(TwipsPerPixelY),0 }, + +{ "TYP_AUTHORFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_AUTHORFLD),0 }, +{ "TYP_CHAPTERFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_CHAPTERFLD),0 }, +{ "TYP_CONDTXTFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_CONDTXTFLD),0 }, +{ "TYP_DATEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DATEFLD),0 }, +{ "TYP_DBFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DBFLD),0 }, +{ "TYP_DBNAMEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DBNAMEFLD),0 }, +{ "TYP_DBNEXTSETFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DBNEXTSETFLD),0 }, +{ "TYP_DBNUMSETFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DBNUMSETFLD),0 }, +{ "TYP_DBSETNUMBERFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DBSETNUMBERFLD),0 }, +{ "TYP_DDEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DDEFLD),0 }, +{ "TYP_DOCINFOFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DOCINFOFLD),0 }, +{ "TYP_DOCSTATFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_DOCSTATFLD),0 }, +{ "TYP_EXTUSERFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_EXTUSERFLD),0 }, +{ "TYP_FILENAMEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_FILENAMEFLD),0 }, +{ "TYP_FIXDATEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_FIXDATEFLD),0 }, +{ "TYP_FIXTIMEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_FIXTIMEFLD),0 }, +{ "TYP_FORMELFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_FORMELFLD),0 }, +{ "TYP_GETFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_GETFLD),0 }, +{ "TYP_GETREFFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_GETREFFLD),0 }, +{ "TYP_GETREFPAGEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_GETREFPAGEFLD),0 }, +{ "TYP_HIDDENPARAFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_HIDDENPARAFLD),0 }, +{ "TYP_HIDDENTXTFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_HIDDENTXTFLD),0 }, +{ "TYP_INPUTFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_INPUTFLD),0 }, +{ "TYP_INTERNETFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_INTERNETFLD),0 }, +{ "TYP_JUMPEDITFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_JUMPEDITFLD),0 }, +{ "TYP_MACROFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_MACROFLD),0 }, +{ "TYP_NEXTPAGEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_NEXTPAGEFLD),0 }, +{ "TYP_PAGENUMBERFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_PAGENUMBERFLD),0 }, +{ "TYP_POSTITFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_POSTITFLD),0 }, +{ "TYP_PREVPAGEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_PREVPAGEFLD),0 }, +{ "TYP_SEQFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_SEQFLD),0 }, +{ "TYP_SETFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_SETFLD),0 }, +{ "TYP_SETINPFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_SETINPFLD),0 }, +{ "TYP_SETREFFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_SETREFFLD),0 }, +{ "TYP_SETREFPAGEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_SETREFPAGEFLD),0 }, +{ "TYP_TEMPLNAMEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_TEMPLNAMEFLD),0}, +{ "TYP_TIMEFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_TIMEFLD),0 }, +{ "TYP_USERFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_USERFLD),0 }, +{ "TYP_USRINPFLD", SbxINTEGER, _CPROP, RTLNAME(TYP_USRINPFLD),0 }, + +{ "TypeLen", SbxINTEGER, 1 | _FUNCTION, RTLNAME(TypeLen),0 }, + { "Var", SbxVARIANT, 0,NULL,0 }, +{ "TypeName", SbxSTRING, 1 | _FUNCTION, RTLNAME(TypeName),0 }, + { "Var", SbxVARIANT, 0,NULL,0 }, + +{ "UBound", SbxLONG, 1 | _FUNCTION, RTLNAME(UBound),0 }, + { "Var", SbxVARIANT, 0,NULL,0 }, +{ "UCase", SbxSTRING, 1 | _FUNCTION, RTLNAME(UCase),0 }, + { "String", SbxSTRING, 0,NULL,0 }, +{ "Unload", SbxNULL, 1 | _FUNCTION, RTLNAME(Unload),0 }, + { "Dialog", SbxOBJECT, 0,NULL,0 }, + +{ "Val", SbxDOUBLE, 1 | _FUNCTION, RTLNAME(Val),0 }, + { "String", SbxSTRING, 0,NULL,0 }, +{ "VarType", SbxINTEGER, 1 | _FUNCTION, RTLNAME(VarType),0 }, + { "Var", SbxVARIANT, 0,NULL,0 }, +{ "V_EMPTY", SbxINTEGER, _CPROP, RTLNAME(V_EMPTY),0 }, +{ "V_NULL", SbxINTEGER, _CPROP, RTLNAME(V_NULL),0 }, +{ "V_INTEGER", SbxINTEGER, _CPROP, RTLNAME(V_INTEGER),0 }, +{ "V_LONG", SbxINTEGER, _CPROP, RTLNAME(V_LONG),0 }, +{ "V_SINGLE", SbxINTEGER, _CPROP, RTLNAME(V_SINGLE),0 }, +{ "V_DOUBLE", SbxINTEGER, _CPROP, RTLNAME(V_DOUBLE),0 }, +{ "V_CURRENCY", SbxINTEGER, _CPROP, RTLNAME(V_CURRENCY),0 }, +{ "V_DATE", SbxINTEGER, _CPROP, RTLNAME(V_DATE),0 }, +{ "V_STRING", SbxINTEGER, _CPROP, RTLNAME(V_STRING),0 }, + +{ "Wait", SbxNULL, 1 | _FUNCTION, RTLNAME(Wait),0 }, + { "Milliseconds", SbxLONG, 0,NULL,0 }, +//#i64882# +{ "WaitUntil", SbxNULL, 1 | _FUNCTION, RTLNAME(WaitUntil),0 }, + { "Date", SbxDOUBLE, 0,NULL,0 }, +{ "Weekday", SbxINTEGER, 2 | _FUNCTION, RTLNAME(Weekday),0 }, + { "Date", SbxDATE, 0,NULL,0 }, + { "Firstdayofweek", SbxINTEGER, _OPT, NULL,0 }, +{ "WeekdayName", SbxSTRING, 3 | _FUNCTION | _COMPTMASK, RTLNAME(WeekdayName),0 }, + { "Weekday", SbxINTEGER, 0,NULL,0 }, + { "Abbreviate", SbxBOOL, _OPT, NULL,0 }, + { "Firstdayofweek", SbxINTEGER, _OPT, NULL,0 }, +{ "Year", SbxINTEGER, 1 | _FUNCTION, RTLNAME(Year),0 }, + { "Date", SbxDATE, 0,NULL,0 }, + +{ NULL, SbxNULL, -1,NULL,0 }}; // Tabellenende + +SbiStdObject::SbiStdObject( const String& r, StarBASIC* pb ) : SbxObject( r ) +{ + // Muessen wir die Hashcodes initialisieren? + Methods* p = aMethods; + if( !p->nHash ) + while( p->nArgs != -1 ) + { + String aName_ = String::CreateFromAscii( p->pName ); + p->nHash = SbxVariable::MakeHashCode( aName_ ); + p += ( p->nArgs & _ARGSMASK ) + 1; + } + + // #i92642: Remove default properties + Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_DONTCARE ); + Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Parent") ), SbxCLASS_DONTCARE ); + + SetParent( pb ); + + pStdFactory = new SbStdFactory; + SbxBase::AddFactory( pStdFactory ); + + Insert( new SbStdClipboard ); +} + +SbiStdObject::~SbiStdObject() +{ + SbxBase::RemoveFactory( pStdFactory ); + delete pStdFactory; +} + +// Suche nach einem Element: +// Hier wird linear durch die Methodentabelle gegangen, bis eine +// passende Methode gefunden wurde. Auf Grund der Bits im nArgs-Feld +// wird dann die passende Instanz eines SbxObjElement generiert. +// Wenn die Methode/Property nicht gefunden wurde, nur NULL ohne +// Fehlercode zurueckliefern, da so auch eine ganze Chain von +// Objekten nach der Methode/Property befragt werden kann. + +SbxVariable* SbiStdObject::Find( const String& rName, SbxClassType t ) +{ + // Bereits eingetragen? + SbxVariable* pVar = SbxObject::Find( rName, t ); + if( !pVar ) + { + // sonst suchen + USHORT nHash_ = SbxVariable::MakeHashCode( rName ); + Methods* p = aMethods; + BOOL bFound = FALSE; + short nIndex = 0; + USHORT nSrchMask = _TYPEMASK; + switch( t ) + { + case SbxCLASS_METHOD: nSrchMask = _METHOD; break; + case SbxCLASS_PROPERTY: nSrchMask = _PROPERTY; break; + case SbxCLASS_OBJECT: nSrchMask = _OBJECT; break; + default: break; + } + while( p->nArgs != -1 ) + { + if( ( p->nArgs & nSrchMask ) + && ( p->nHash == nHash_ ) + && ( rName.EqualsIgnoreCaseAscii( p->pName ) ) ) + { + bFound = TRUE; + if( p->nArgs & _COMPTMASK ) + { + SbiInstance* pInst = pINST; + if( !pInst || !pInst->IsCompatibility() ) + bFound = FALSE; + } + break; + } + nIndex += ( p->nArgs & _ARGSMASK ) + 1; + p = aMethods + nIndex; + } + + if( bFound ) + { + // Args-Felder isolieren: + short nAccess = ( p->nArgs & _RWMASK ) >> 8; + short nType = ( p->nArgs & _TYPEMASK ); + if( p->nArgs & _CONST ) + nAccess |= SBX_CONST; + String aName_ = String::CreateFromAscii( p->pName ); + SbxClassType eCT = SbxCLASS_OBJECT; + if( nType & _PROPERTY ) + eCT = SbxCLASS_PROPERTY; + else if( nType & _METHOD ) + eCT = SbxCLASS_METHOD; + pVar = Make( aName_, eCT, p->eType ); + pVar->SetUserData( nIndex + 1 ); + pVar->SetFlags( nAccess ); + } + } + return pVar; +} + +// SetModified muß bei der RTL abgklemmt werden +void SbiStdObject::SetModified( BOOL ) +{ +} + +// Aufruf einer Property oder Methode. + +void SbiStdObject::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, + const SfxHint& rHint, const TypeId& rHintType ) + +{ + const SbxHint* pHint = PTR_CAST(SbxHint,&rHint); + if( pHint ) + { + SbxVariable* pVar = pHint->GetVar(); + SbxArray* pPar_ = pVar->GetParameters(); + ULONG t = pHint->GetId(); + USHORT nCallId = (USHORT) pVar->GetUserData(); + if( nCallId ) + { + if( t == SBX_HINT_INFOWANTED ) + pVar->SetInfo( GetInfo( (short) pVar->GetUserData() ) ); + else + { + BOOL bWrite = FALSE; + if( t == SBX_HINT_DATACHANGED ) + bWrite = TRUE; + if( t == SBX_HINT_DATAWANTED || bWrite ) + { + RtlCall p = (RtlCall) aMethods[ nCallId-1 ].pFunc; + SbxArrayRef rPar( pPar_ ); + if( !pPar_ ) + { + rPar = pPar_ = new SbxArray; + pPar_->Put( pVar, 0 ); + } + p( (StarBASIC*) GetParent(), *pPar_, bWrite ); + return; + } + } + } + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + } +} + +// Zusammenbau der Infostruktur fuer einzelne Elemente +// Falls nIdx = 0, nix erzeugen (sind Std-Props!) + +SbxInfo* SbiStdObject::GetInfo( short nIdx ) +{ + if( !nIdx ) + return NULL; + Methods* p = &aMethods[ --nIdx ]; + // Wenn mal eine Hilfedatei zur Verfuegung steht: + // SbxInfo* pInfo_ = new SbxInfo( Hilfedateiname, p->nHelpId ); + SbxInfo* pInfo_ = new SbxInfo; + short nPar = p->nArgs & _ARGSMASK; + for( short i = 0; i < nPar; i++ ) + { + p++; + String aName_ = String::CreateFromAscii( p->pName ); + USHORT nFlags_ = ( p->nArgs >> 8 ) & 0x03; + if( p->nArgs & _OPT ) + nFlags_ |= SBX_OPTIONAL; + pInfo_->AddParam( aName_, p->eType, nFlags_ ); + } + return pInfo_; +} + diff --git a/basic/source/runtime/stdobj1.cxx b/basic/source/runtime/stdobj1.cxx new file mode 100644 index 000000000000..94b7973c7e77 --- /dev/null +++ b/basic/source/runtime/stdobj1.cxx @@ -0,0 +1,551 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <vcl/wrkwin.hxx> +#include <vcl/svapp.hxx> +#include <svtools/transfer.hxx> +#include "runtime.hxx" +#include <basic/sbstdobj.hxx> + +#define ATTR_IMP_TYPE 1 +#define ATTR_IMP_WIDTH 2 +#define ATTR_IMP_HEIGHT 3 +#define ATTR_IMP_BOLD 4 +#define ATTR_IMP_ITALIC 5 +#define ATTR_IMP_STRIKETHROUGH 6 +#define ATTR_IMP_UNDERLINE 7 +#define ATTR_IMP_WEIGHT 8 +#define ATTR_IMP_SIZE 9 +#define ATTR_IMP_NAME 10 + +#define METH_CLEAR 20 +#define METH_GETDATA 21 +#define METH_GETFORMAT 22 +#define METH_GETTEXT 23 +#define METH_SETDATA 24 +#define METH_SETTEXT 25 + +//------------------------------------------------------------------------------ +SbStdFactory::SbStdFactory() +{ +} + +SbxObject* SbStdFactory::CreateObject( const String& rClassName ) +{ + if( rClassName.EqualsIgnoreCaseAscii( String( RTL_CONSTASCII_USTRINGPARAM("Picture") ) ) ) + return new SbStdPicture; + else + if( rClassName.EqualsIgnoreCaseAscii( String( RTL_CONSTASCII_USTRINGPARAM("Font") ) ) ) + return new SbStdFont; + else + return NULL; +} + +//------------------------------------------------------------------------------ + + + +void SbStdPicture::PropType( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + { + StarBASIC::Error( SbERR_PROP_READONLY ); + return; + } + + GraphicType eType = aGraphic.GetType(); + INT16 nType = 0; + + if( eType == GRAPHIC_BITMAP ) + nType = 1; + else + if( eType != GRAPHIC_NONE ) + nType = 2; + + pVar->PutInteger( nType ); +} + + +void SbStdPicture::PropWidth( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + { + StarBASIC::Error( SbERR_PROP_READONLY ); + return; + } + + Size aSize = aGraphic.GetPrefSize(); + aSize = GetpApp()->GetAppWindow()->LogicToPixel( aSize, aGraphic.GetPrefMapMode() ); + aSize = GetpApp()->GetAppWindow()->PixelToLogic( aSize, MapMode( MAP_TWIP ) ); + + pVar->PutInteger( (INT16)aSize.Width() ); +} + +void SbStdPicture::PropHeight( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + { + StarBASIC::Error( SbERR_PROP_READONLY ); + return; + } + + Size aSize = aGraphic.GetPrefSize(); + aSize = GetpApp()->GetAppWindow()->LogicToPixel( aSize, aGraphic.GetPrefMapMode() ); + aSize = GetpApp()->GetAppWindow()->PixelToLogic( aSize, MapMode( MAP_TWIP ) ); + + pVar->PutInteger( (INT16)aSize.Height() ); +} + + +TYPEINIT1( SbStdPicture, SbxObject ); + +SbStdPicture::SbStdPicture() : + SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("Picture") ) ) +{ + // Properties + SbxVariable* p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Type") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READ | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_TYPE ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Width") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READ | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_WIDTH ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Height") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READ | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_HEIGHT ); +} + +SbStdPicture::~SbStdPicture() +{ +} + + +SbxVariable* SbStdPicture::Find( const String& rName, SbxClassType t ) +{ + // Bereits eingetragen? + return SbxObject::Find( rName, t ); +} + + + +void SbStdPicture::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, + const SfxHint& rHint, const TypeId& rHintType ) + +{ + const SbxHint* pHint = PTR_CAST( SbxHint, &rHint ); + + if( pHint ) + { + if( pHint->GetId() == SBX_HINT_INFOWANTED ) + { + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + return; + } + + SbxVariable* pVar = pHint->GetVar(); + SbxArray* pPar_ = pVar->GetParameters(); + USHORT nWhich = (USHORT)pVar->GetUserData(); + BOOL bWrite = pHint->GetId() == SBX_HINT_DATACHANGED; + + // Propteries + switch( nWhich ) + { + case ATTR_IMP_TYPE: PropType( pVar, pPar_, bWrite ); return; + case ATTR_IMP_WIDTH: PropWidth( pVar, pPar_, bWrite ); return; + case ATTR_IMP_HEIGHT: PropHeight( pVar, pPar_, bWrite ); return; + } + + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + } +} + +//----------------------------------------------------------------------------- + +void SbStdFont::PropBold( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + SetBold( pVar->GetBool() ); + else + pVar->PutBool( IsBold() ); +} + +void SbStdFont::PropItalic( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + SetItalic( pVar->GetBool() ); + else + pVar->PutBool( IsItalic() ); +} + +void SbStdFont::PropStrikeThrough( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + SetStrikeThrough( pVar->GetBool() ); + else + pVar->PutBool( IsStrikeThrough() ); +} + +void SbStdFont::PropUnderline( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + SetUnderline( pVar->GetBool() ); + else + pVar->PutBool( IsUnderline() ); +} + +void SbStdFont::PropSize( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + SetSize( (USHORT)pVar->GetInteger() ); + else + pVar->PutInteger( (INT16)GetSize() ); +} + +void SbStdFont::PropName( SbxVariable* pVar, SbxArray*, BOOL bWrite ) +{ + if( bWrite ) + SetFontName( pVar->GetString() ); + else + pVar->PutString( GetFontName() ); +} + + +TYPEINIT1( SbStdFont, SbxObject ); + +SbStdFont::SbStdFont() : + SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("Font") ) ) +{ + // Properties + SbxVariable* p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Bold") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READWRITE | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_BOLD ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Italic") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READWRITE | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_ITALIC ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("StrikeThrough") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READWRITE | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_STRIKETHROUGH ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Underline") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READWRITE | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_UNDERLINE ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Size") ), SbxCLASS_PROPERTY, SbxVARIANT ); + p->SetFlags( SBX_READWRITE | SBX_DONTSTORE ); + p->SetUserData( ATTR_IMP_SIZE ); + + // Name Property selbst verarbeiten + p = Find( String( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_PROPERTY ); + DBG_ASSERT( p, "Keine Name Property" ); + p->SetUserData( ATTR_IMP_NAME ); +} + +SbStdFont::~SbStdFont() +{ +} + + +SbxVariable* SbStdFont::Find( const String& rName, SbxClassType t ) +{ + // Bereits eingetragen? + return SbxObject::Find( rName, t ); +} + + + +void SbStdFont::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, + const SfxHint& rHint, const TypeId& rHintType ) +{ + const SbxHint* pHint = PTR_CAST( SbxHint, &rHint ); + + if( pHint ) + { + if( pHint->GetId() == SBX_HINT_INFOWANTED ) + { + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + return; + } + + SbxVariable* pVar = pHint->GetVar(); + SbxArray* pPar_ = pVar->GetParameters(); + USHORT nWhich = (USHORT)pVar->GetUserData(); + BOOL bWrite = pHint->GetId() == SBX_HINT_DATACHANGED; + + // Propteries + switch( nWhich ) + { + case ATTR_IMP_BOLD: PropBold( pVar, pPar_, bWrite ); return; + case ATTR_IMP_ITALIC: PropItalic( pVar, pPar_, bWrite ); return; + case ATTR_IMP_STRIKETHROUGH:PropStrikeThrough( pVar, pPar_, bWrite ); return; + case ATTR_IMP_UNDERLINE: PropUnderline( pVar, pPar_, bWrite ); return; + case ATTR_IMP_SIZE: PropSize( pVar, pPar_, bWrite ); return; + case ATTR_IMP_NAME: PropName( pVar, pPar_, bWrite ); return; + } + + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + } +} + + +//----------------------------------------------------------------------------- + +/* +class TransferableHelperImpl : public TransferableHelper +{ + SotFormatStringId mFormat; + String mString; + Graphic mGraphic; + + virtual void AddSupportedFormats(); + virtual sal_Bool GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor ); + +public: + TransferableHelperImpl( void ) { mFormat = 0; } + TransferableHelperImpl( const String& rStr ) + mFormat( FORMAT_STRING ), mString( rStr ) {} + TransferableHelperImpl( const Graphic& rGraphic ); + mFormat( FORMAT_BITMAP ), mGraphic( rGraphic ) {} + +}; + +void TransferableHelperImpl::AddSupportedFormats() +{ +} + +sal_Bool TransferableHelperImpl::GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor ) +{ + sal_uInt32 nFormat = SotExchange::GetFormat( rFlavor ); + if( nFormat == FORMAT_STRING ) + { + } + else if( nFormat == FORMAT_BITMAP || + nFormat == FORMAT_GDIMETAFILE ) + { + } +} +*/ + +void SbStdClipboard::MethClear( SbxVariable*, SbxArray* pPar_, BOOL ) +{ + if( pPar_ && (pPar_->Count() > 1) ) + { + StarBASIC::Error( SbERR_BAD_NUMBER_OF_ARGS ); + return; + } + + //Clipboard::Clear(); +} + +void SbStdClipboard::MethGetData( SbxVariable* pVar, SbxArray* pPar_, BOOL ) +{ + (void)pVar; + + if( !pPar_ || (pPar_->Count() != 2) ) + { + StarBASIC::Error( SbERR_BAD_NUMBER_OF_ARGS ); + return; + } + + USHORT nFormat = pPar_->Get(1)->GetInteger(); + if( !nFormat || nFormat > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + /* + if( nFormat == FORMAT_STRING ) + pVar->PutString( Clipboard::PasteString() ); + else + if( (nFormat == FORMAT_BITMAP) || + (nFormat == FORMAT_GDIMETAFILE ) ) + { + SbxObjectRef xPic = new SbStdPicture; + Graphic aGraph; + aGraph.Paste(); + ((SbStdPicture*)(SbxObject*)xPic)->SetGraphic( aGraph ); + pVar->PutObject( xPic ); + } + */ +} + +void SbStdClipboard::MethGetFormat( SbxVariable* pVar, SbxArray* pPar_, BOOL ) +{ + if( !pPar_ || (pPar_->Count() != 2) ) + { + StarBASIC::Error( SbERR_BAD_NUMBER_OF_ARGS ); + return; + } + + USHORT nFormat = pPar_->Get(1)->GetInteger(); + if( !nFormat || nFormat > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + pVar->PutBool( FALSE ); + //pVar->PutBool( Clipboard::HasFormat( nFormat ) ); +} + +void SbStdClipboard::MethGetText( SbxVariable* pVar, SbxArray* pPar_, BOOL ) +{ + if( pPar_ && (pPar_->Count() > 1) ) + { + StarBASIC::Error( SbERR_BAD_NUMBER_OF_ARGS ); + return; + } + + pVar->PutString( String() ); + //pVar->PutString( Clipboard::PasteString() ); +} + +void SbStdClipboard::MethSetData( SbxVariable* pVar, SbxArray* pPar_, BOOL ) +{ + (void)pVar; + + if( !pPar_ || (pPar_->Count() != 3) ) + { + StarBASIC::Error( SbERR_BAD_NUMBER_OF_ARGS ); + return; + } + + USHORT nFormat = pPar_->Get(2)->GetInteger(); + if( !nFormat || nFormat > 3 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return; + } + + /* + if( nFormat == FORMAT_STRING ) + { + Clipboard::CopyString( pPar_->Get(1)->GetString() ); + } + else + if( (nFormat == FORMAT_BITMAP) || + (nFormat == FORMAT_GDIMETAFILE) ) + { + SbxObject* pObj = (SbxObject*)pPar_->Get(1)->GetObject(); + + if( pObj && pObj->IsA( TYPE( SbStdPicture ) ) ) + ((SbStdPicture*)(SbxObject*)pObj)->GetGraphic().Copy(); + } + */ +} + +void SbStdClipboard::MethSetText( SbxVariable* pVar, SbxArray* pPar_, BOOL ) +{ + (void)pVar; + + if( !pPar_ || (pPar_->Count() != 2) ) + { + StarBASIC::Error( SbERR_BAD_NUMBER_OF_ARGS ); + return; + } + + // Clipboard::CopyString( pPar_->Get(1)->GetString() ); +} + + +TYPEINIT1( SbStdClipboard, SbxObject ); + +SbStdClipboard::SbStdClipboard() : + SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("Clipboard") ) ) +{ + // Name Property selbst verarbeiten + SbxVariable* p = Find( String( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_PROPERTY ); + DBG_ASSERT( p, "Keine Name Property" ); + p->SetUserData( ATTR_IMP_NAME ); + + //Methoden registrieren + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("Clear") ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p->SetUserData( METH_CLEAR ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("GetData") ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p->SetUserData( METH_GETDATA ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("GetFormat") ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p->SetUserData( METH_GETFORMAT ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("GetText") ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p->SetUserData( METH_GETTEXT ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("SetData") ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p->SetUserData( METH_SETDATA ); + p = Make( String( RTL_CONSTASCII_USTRINGPARAM("SetText") ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p->SetUserData( METH_SETTEXT ); +} + +SbStdClipboard::~SbStdClipboard() +{ +} + + +SbxVariable* SbStdClipboard::Find( const String& rName, SbxClassType t ) +{ + // Bereits eingetragen? + return SbxObject::Find( rName, t ); +} + + + +void SbStdClipboard::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, + const SfxHint& rHint, const TypeId& rHintType ) +{ + const SbxHint* pHint = PTR_CAST( SbxHint, &rHint ); + + if( pHint ) + { + if( pHint->GetId() == SBX_HINT_INFOWANTED ) + { + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + return; + } + + SbxVariable* pVar = pHint->GetVar(); + SbxArray* pPar_ = pVar->GetParameters(); + USHORT nWhich = (USHORT)pVar->GetUserData(); + BOOL bWrite = pHint->GetId() == SBX_HINT_DATACHANGED; + + // Methods + switch( nWhich ) + { + case METH_CLEAR: MethClear( pVar, pPar_, bWrite ); return; + case METH_GETDATA: MethGetData( pVar, pPar_, bWrite ); return; + case METH_GETFORMAT: MethGetFormat( pVar, pPar_, bWrite ); return; + case METH_GETTEXT: MethGetText( pVar, pPar_, bWrite ); return; + case METH_SETDATA: MethSetData( pVar, pPar_, bWrite ); return; + case METH_SETTEXT: MethSetText( pVar, pPar_, bWrite ); return; + } + + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + } +} + + diff --git a/basic/source/runtime/step0.cxx b/basic/source/runtime/step0.cxx new file mode 100644 index 000000000000..c686b0ed80ed --- /dev/null +++ b/basic/source/runtime/step0.cxx @@ -0,0 +1,1438 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <vcl/msgbox.hxx> +#include <tools/fsys.hxx> + +#include "errobject.hxx" +#include "runtime.hxx" +#include "sbintern.hxx" +#include "iosys.hxx" +#include <sb.hrc> +#include <basrid.hxx> +#include "sbunoobj.hxx" +#include "image.hxx" +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/util/SearchOptions.hdl> +#include <vcl/svapp.hxx> +#include <unotools/textsearch.hxx> + +Reference< XInterface > createComListener( const Any& aControlAny, const ::rtl::OUString& aVBAType, + const ::rtl::OUString& aPrefix, SbxObjectRef xScopeObj ); + +#include <algorithm> +#include <hash_map> + +SbxVariable* getDefaultProp( SbxVariable* pRef ); + +void SbiRuntime::StepNOP() +{} + +void SbiRuntime::StepArith( SbxOperator eOp ) +{ + SbxVariableRef p1 = PopVar(); + TOSMakeTemp(); + SbxVariable* p2 = GetTOS(); + + + // This could & should be moved to the MakeTempTOS() method in runtime.cxx + // In the code which this is cut'npaste from there is a check for a ref + // count != 1 based on which the copy of the SbxVariable is done. + // see orig code in MakeTempTOS ( and I'm not sure what the significance, + // of that is ) + // here we alway seem to have a refcount of 1. Also it seems that + // MakeTempTOS is called for other operation, so I hold off for now + // until I have a better idea + if ( bVBAEnabled + && ( p2->GetType() == SbxOBJECT || p2->GetType() == SbxVARIANT ) + ) + { + SbxVariable* pDflt = getDefaultProp( p2 ); + if ( pDflt ) + { + pDflt->Broadcast( SBX_HINT_DATAWANTED ); + // replacing new p2 on stack causes object pointed by + // pDft->pParent to be deleted, when p2->Compute() is + // called below pParent is accessed ( but its deleted ) + // so set it to NULL now + pDflt->SetParent( NULL ); + p2 = new SbxVariable( *pDflt ); + p2->SetFlag( SBX_READWRITE ); + refExprStk->Put( p2, nExprLvl - 1 ); + } + } + + p2->ResetFlag( SBX_FIXED ); + p2->Compute( eOp, *p1 ); + + checkArithmeticOverflow( p2 ); +} + +void SbiRuntime::StepUnary( SbxOperator eOp ) +{ + TOSMakeTemp(); + SbxVariable* p = GetTOS(); + p->Compute( eOp, *p ); +} + +void SbiRuntime::StepCompare( SbxOperator eOp ) +{ + SbxVariableRef p1 = PopVar(); + SbxVariableRef p2 = PopVar(); + + // Make sure objects with default params have + // values ( and type ) set as appropriate + SbxDataType p1Type = p1->GetType(); + SbxDataType p2Type = p2->GetType(); + if ( p1Type == p2Type ) + { + if ( p1Type == SbxEMPTY ) + { + p1->Broadcast( SBX_HINT_DATAWANTED ); + p2->Broadcast( SBX_HINT_DATAWANTED ); + } + // if both sides are an object and have default props + // then we need to use the default props + // we don't need to worry if only one side ( lhs, rhs ) is an + // object ( object side will get coerced to correct type in + // Compare ) + else if ( p1Type == SbxOBJECT ) + { + SbxVariable* pDflt = getDefaultProp( p1 ); + if ( pDflt ) + { + p1 = pDflt; + p1->Broadcast( SBX_HINT_DATAWANTED ); + } + pDflt = getDefaultProp( p2 ); + if ( pDflt ) + { + p2 = pDflt; + p2->Broadcast( SBX_HINT_DATAWANTED ); + } + } + + } + static SbxVariable* pTRUE = NULL; + static SbxVariable* pFALSE = NULL; + + if( p2->Compare( eOp, *p1 ) ) + { + if( !pTRUE ) + { + pTRUE = new SbxVariable; + pTRUE->PutBool( TRUE ); + pTRUE->AddRef(); + } + PushVar( pTRUE ); + } + else + { + if( !pFALSE ) + { + pFALSE = new SbxVariable; + pFALSE->PutBool( FALSE ); + pFALSE->AddRef(); + } + PushVar( pFALSE ); + } +} + +void SbiRuntime::StepEXP() { StepArith( SbxEXP ); } +void SbiRuntime::StepMUL() { StepArith( SbxMUL ); } +void SbiRuntime::StepDIV() { StepArith( SbxDIV ); } +void SbiRuntime::StepIDIV() { StepArith( SbxIDIV ); } +void SbiRuntime::StepMOD() { StepArith( SbxMOD ); } +void SbiRuntime::StepPLUS() { StepArith( SbxPLUS ); } +void SbiRuntime::StepMINUS() { StepArith( SbxMINUS ); } +void SbiRuntime::StepCAT() { StepArith( SbxCAT ); } +void SbiRuntime::StepAND() { StepArith( SbxAND ); } +void SbiRuntime::StepOR() { StepArith( SbxOR ); } +void SbiRuntime::StepXOR() { StepArith( SbxXOR ); } +void SbiRuntime::StepEQV() { StepArith( SbxEQV ); } +void SbiRuntime::StepIMP() { StepArith( SbxIMP ); } + +void SbiRuntime::StepNEG() { StepUnary( SbxNEG ); } +void SbiRuntime::StepNOT() { StepUnary( SbxNOT ); } + +void SbiRuntime::StepEQ() { StepCompare( SbxEQ ); } +void SbiRuntime::StepNE() { StepCompare( SbxNE ); } +void SbiRuntime::StepLT() { StepCompare( SbxLT ); } +void SbiRuntime::StepGT() { StepCompare( SbxGT ); } +void SbiRuntime::StepLE() { StepCompare( SbxLE ); } +void SbiRuntime::StepGE() { StepCompare( SbxGE ); } + +namespace +{ + bool NeedEsc(sal_Unicode cCode) + { + String sEsc(RTL_CONSTASCII_USTRINGPARAM(".^$+\\|{}()")); + return (STRING_NOTFOUND != sEsc.Search(cCode)); + } + + String VBALikeToRegexp(const String &rIn) + { + String sResult; + const sal_Unicode *start = rIn.GetBuffer(); + const sal_Unicode *end = start + rIn.Len(); + + int seenright = 0; + + sResult.Append('^'); + + while (start < end) + { + switch (*start) + { + case '?': + sResult.Append('.'); + start++; + break; + case '*': + sResult.Append(String(RTL_CONSTASCII_USTRINGPARAM(".*"))); + start++; + break; + case '#': + sResult.Append(String(RTL_CONSTASCII_USTRINGPARAM("[0-9]"))); + start++; + break; + case ']': + sResult.Append('\\'); + sResult.Append(*start++); + break; + case '[': + sResult.Append(*start++); + seenright = 0; + while (start < end && !seenright) + { + switch (*start) + { + case '[': + case '?': + case '*': + sResult.Append('\\'); + sResult.Append(*start); + break; + case ']': + sResult.Append(*start); + seenright = 1; + break; + case '!': + sResult.Append('^'); + break; + default: + if (NeedEsc(*start)) + sResult.Append('\\'); + sResult.Append(*start); + break; + } + start++; + } + break; + default: + if (NeedEsc(*start)) + sResult.Append('\\'); + sResult.Append(*start++); + } + } + + sResult.Append('$'); + + return sResult; + } +} + +void SbiRuntime::StepLIKE() +{ + SbxVariableRef refVar1 = PopVar(); + SbxVariableRef refVar2 = PopVar(); + + String pattern = VBALikeToRegexp(refVar1->GetString()); + String value = refVar2->GetString(); + + com::sun::star::util::SearchOptions aSearchOpt; + + aSearchOpt.algorithmType = com::sun::star::util::SearchAlgorithms_REGEXP; + + aSearchOpt.Locale = Application::GetSettings().GetLocale(); + aSearchOpt.searchString = pattern; + + int bTextMode(1); + bool bCompatibility = ( pINST && pINST->IsCompatibility() ); + if( bCompatibility ) + bTextMode = GetImageFlag( SBIMG_COMPARETEXT ); + + if( bTextMode ) + aSearchOpt.transliterateFlags |= com::sun::star::i18n::TransliterationModules_IGNORE_CASE; + + SbxVariable* pRes = new SbxVariable; + utl::TextSearch aSearch(aSearchOpt); + xub_StrLen nStart=0, nEnd=value.Len(); + int bRes = aSearch.SearchFrwrd(value, &nStart, &nEnd); + pRes->PutBool( bRes != 0 ); + + PushVar( pRes ); +} + +// TOS und TOS-1 sind beides Objektvariable und enthalten den selben Pointer + +void SbiRuntime::StepIS() +{ + SbxVariableRef refVar1 = PopVar(); + SbxVariableRef refVar2 = PopVar(); + + SbxDataType eType1 = refVar1->GetType(); + SbxDataType eType2 = refVar2->GetType(); + if ( eType1 == SbxEMPTY ) + { + refVar1->Broadcast( SBX_HINT_DATAWANTED ); + eType1 = refVar1->GetType(); + } + if ( eType2 == SbxEMPTY ) + { + refVar2->Broadcast( SBX_HINT_DATAWANTED ); + eType2 = refVar2->GetType(); + } + + BOOL bRes = BOOL( eType1 == SbxOBJECT && eType2 == SbxOBJECT ); + if ( bVBAEnabled && !bRes ) + Error( SbERR_INVALID_USAGE_OBJECT ); + bRes = ( bRes && refVar1->GetObject() == refVar2->GetObject() ); + SbxVariable* pRes = new SbxVariable; + pRes->PutBool( bRes ); + PushVar( pRes ); +} + +// Aktualisieren des Wertes von TOS + +void SbiRuntime::StepGET() +{ + SbxVariable* p = GetTOS(); + p->Broadcast( SBX_HINT_DATAWANTED ); +} + +// #67607 Uno-Structs kopieren +inline void checkUnoStructCopy( SbxVariableRef& refVal, SbxVariableRef& refVar ) +{ + SbxDataType eVarType = refVar->GetType(); + if( eVarType != SbxOBJECT ) + return; + + SbxObjectRef xValObj = (SbxObject*)refVal->GetObject(); + if( !xValObj.Is() || xValObj->ISA(SbUnoAnyObject) ) + return; + + // #115826: Exclude ProcedureProperties to avoid call to Property Get procedure + if( refVar->ISA(SbProcedureProperty) ) + return; + + SbxObjectRef xVarObj = (SbxObject*)refVar->GetObject(); + SbxDataType eValType = refVal->GetType(); + if( eValType == SbxOBJECT && xVarObj == xValObj ) + { + SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxObject*)xVarObj); + if( pUnoObj ) + { + Any aAny = pUnoObj->getUnoAny(); + if( aAny.getValueType().getTypeClass() == TypeClass_STRUCT ) + { + SbUnoObject* pNewUnoObj = new SbUnoObject( pUnoObj->GetName(), aAny ); + // #70324: ClassName uebernehmen + pNewUnoObj->SetClassName( pUnoObj->GetClassName() ); + refVar->PutObject( pNewUnoObj ); + } + } + } +} + + +// Ablage von TOS in TOS-1 + +void SbiRuntime::StepPUT() +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + // Store auf die eigene Methode (innerhalb einer Function)? + BOOL bFlagsChanged = FALSE; + USHORT n = 0; + if( (SbxVariable*) refVar == (SbxVariable*) pMeth ) + { + bFlagsChanged = TRUE; + n = refVar->GetFlags(); + refVar->SetFlag( SBX_WRITE ); + } + + // if left side arg is an object or variant and right handside isn't + // either an object or a variant then try and see if a default + // property exists. + // to use e.g. Range{"A1") = 34 + // could equate to Range("A1").Value = 34 + if ( bVBAEnabled ) + { + if ( refVar->GetType() == SbxOBJECT ) + { + SbxVariable* pDflt = getDefaultProp( refVar ); + if ( pDflt ) + refVar = pDflt; + } + if ( refVal->GetType() == SbxOBJECT ) + { + SbxVariable* pDflt = getDefaultProp( refVal ); + if ( pDflt ) + refVal = pDflt; + } + } + + *refVar = *refVal; + // lhs is a property who's value is currently null + if ( !bVBAEnabled || ( bVBAEnabled && refVar->GetType() != SbxEMPTY ) ) + // #67607 Uno-Structs kopieren + checkUnoStructCopy( refVal, refVar ); + if( bFlagsChanged ) + refVar->SetFlags( n ); +} + + +// VBA Dim As New behavior handling, save init object information +struct DimAsNewRecoverItem +{ + String m_aObjClass; + String m_aObjName; + SbxObject* m_pObjParent; + SbModule* m_pClassModule; + + DimAsNewRecoverItem( void ) + : m_pObjParent( NULL ) + , m_pClassModule( NULL ) + {} + + DimAsNewRecoverItem( const String& rObjClass, const String& rObjName, + SbxObject* pObjParent, SbModule* pClassModule ) + : m_aObjClass( rObjClass ) + , m_aObjName( rObjName ) + , m_pObjParent( pObjParent ) + , m_pClassModule( pClassModule ) + {} + +}; + + +struct SbxVariablePtrHash +{ + size_t operator()( SbxVariable* pVar ) const + { return (size_t)pVar; } +}; + +typedef std::hash_map< SbxVariable*, DimAsNewRecoverItem, SbxVariablePtrHash > DimAsNewRecoverHash; + +static DimAsNewRecoverHash GaDimAsNewRecoverHash; + +void removeDimAsNewRecoverItem( SbxVariable* pVar ) +{ + DimAsNewRecoverHash::iterator it = GaDimAsNewRecoverHash.find( pVar ); + if( it != GaDimAsNewRecoverHash.end() ) + GaDimAsNewRecoverHash.erase( it ); +} + + +// Speichern Objektvariable +// Nicht-Objekt-Variable fuehren zu Fehlern + +static const char pCollectionStr[] = "Collection"; + +void SbiRuntime::StepSET_Impl( SbxVariableRef& refVal, SbxVariableRef& refVar, bool bHandleDefaultProp ) +{ + // #67733 Typen mit Array-Flag sind auch ok + + // Check var, !object is no error for sure if, only if type is fixed + SbxDataType eVarType = refVar->GetType(); + if( !bHandleDefaultProp && eVarType != SbxOBJECT && !(eVarType & SbxARRAY) && refVar->IsFixed() ) + { + Error( SbERR_INVALID_USAGE_OBJECT ); + return; + } + + // Check value, !object is no error for sure if, only if type is fixed + SbxDataType eValType = refVal->GetType(); +// bool bGetValObject = false; + if( !bHandleDefaultProp && eValType != SbxOBJECT && !(eValType & SbxARRAY) && refVal->IsFixed() ) + { + Error( SbERR_INVALID_USAGE_OBJECT ); + return; + } + + // Getting in here causes problems with objects with default properties + // if they are SbxEMPTY I guess + if ( !bHandleDefaultProp || ( bHandleDefaultProp && eValType == SbxOBJECT ) ) + { + // Auf refVal GetObject fuer Collections ausloesen + SbxBase* pObjVarObj = refVal->GetObject(); + if( pObjVarObj ) + { + SbxVariableRef refObjVal = PTR_CAST(SbxObject,pObjVarObj); + + // #67733 Typen mit Array-Flag sind auch ok + if( refObjVal ) + refVal = refObjVal; + else if( !(eValType & SbxARRAY) ) + refVal = NULL; + } + } + + // #52896 Wenn Uno-Sequences bzw. allgemein Arrays einer als + // Object deklarierten Variable zugewiesen werden, kann hier + // refVal ungueltig sein! + if( !refVal ) + { + Error( SbERR_INVALID_USAGE_OBJECT ); + } + else + { + // Store auf die eigene Methode (innerhalb einer Function)? + BOOL bFlagsChanged = FALSE; + USHORT n = 0; + if( (SbxVariable*) refVar == (SbxVariable*) pMeth ) + { + bFlagsChanged = TRUE; + n = refVar->GetFlags(); + refVar->SetFlag( SBX_WRITE ); + } + SbProcedureProperty* pProcProperty = PTR_CAST(SbProcedureProperty,(SbxVariable*)refVar); + if( pProcProperty ) + pProcProperty->setSet( true ); + + if ( bHandleDefaultProp ) + { + // get default properties for lhs & rhs where necessary + // SbxVariable* defaultProp = NULL; unused variable + bool bLHSHasDefaultProp = false; + // LHS try determine if a default prop exists + if ( refVar->GetType() == SbxOBJECT ) + { + SbxVariable* pDflt = getDefaultProp( refVar ); + if ( pDflt ) + { + refVar = pDflt; + bLHSHasDefaultProp = true; + } + } + // RHS only get a default prop is the rhs has one + if ( refVal->GetType() == SbxOBJECT ) + { + // check if lhs is a null object + // if it is then use the object not the default property + SbxObject* pObj = NULL; + + + pObj = PTR_CAST(SbxObject,(SbxVariable*)refVar); + + // calling GetObject on a SbxEMPTY variable raises + // object not set errors, make sure its an Object + if ( !pObj && refVar->GetType() == SbxOBJECT ) + { + SbxBase* pObjVarObj = refVar->GetObject(); + pObj = PTR_CAST(SbxObject,pObjVarObj); + } + SbxVariable* pDflt = NULL; + if ( pObj || bLHSHasDefaultProp ) + // lhs is either a valid object || or has a defaultProp + pDflt = getDefaultProp( refVal ); + if ( pDflt ) + refVal = pDflt; + } + } + + // Handle Dim As New + BOOL bDimAsNew = bVBAEnabled && refVar->IsSet( SBX_DIM_AS_NEW ); + SbxBaseRef xPrevVarObj; + if( bDimAsNew ) + xPrevVarObj = refVar->GetObject(); + + // Handle withevents + BOOL bWithEvents = refVar->IsSet( SBX_WITH_EVENTS ); + if ( bWithEvents ) + { + Reference< XInterface > xComListener; + + SbxBase* pObj = refVal->GetObject(); + SbUnoObject* pUnoObj = (pObj != NULL) ? PTR_CAST(SbUnoObject,pObj) : NULL; + if( pUnoObj != NULL ) + { + Any aControlAny = pUnoObj->getUnoAny(); + String aDeclareClassName = refVar->GetDeclareClassName(); + ::rtl::OUString aVBAType = aDeclareClassName; + ::rtl::OUString aPrefix = refVar->GetName(); + SbxObjectRef xScopeObj = refVar->GetParent(); + xComListener = createComListener( aControlAny, aVBAType, aPrefix, xScopeObj ); + + refVal->SetDeclareClassName( aDeclareClassName ); + refVal->SetComListener( xComListener, &rBasic ); // Hold reference + } + + *refVar = *refVal; + } + else + { + *refVar = *refVal; + } + + if ( bDimAsNew ) + { + if( !refVar->ISA(SbxObject) ) + { + SbxBase* pValObjBase = refVal->GetObject(); + if( pValObjBase == NULL ) + { + if( xPrevVarObj.Is() ) + { + // Object is overwritten with NULL, instantiate init object + DimAsNewRecoverHash::iterator it = GaDimAsNewRecoverHash.find( refVar ); + if( it != GaDimAsNewRecoverHash.end() ) + { + const DimAsNewRecoverItem& rItem = it->second; + if( rItem.m_pClassModule != NULL ) + { + SbClassModuleObject* pNewObj = new SbClassModuleObject( rItem.m_pClassModule ); + pNewObj->SetName( rItem.m_aObjName ); + pNewObj->SetParent( rItem.m_pObjParent ); + refVar->PutObject( pNewObj ); + } + else if( rItem.m_aObjClass.EqualsIgnoreCaseAscii( pCollectionStr ) ) + { + BasicCollection* pNewCollection = new BasicCollection( String( RTL_CONSTASCII_USTRINGPARAM(pCollectionStr) ) ); + pNewCollection->SetName( rItem.m_aObjName ); + pNewCollection->SetParent( rItem.m_pObjParent ); + refVar->PutObject( pNewCollection ); + } + } + } + } + else + { + // Does old value exist? + bool bFirstInit = !xPrevVarObj.Is(); + if( bFirstInit ) + { + // Store information to instantiate object later + SbxObject* pValObj = PTR_CAST(SbxObject,pValObjBase); + if( pValObj != NULL ) + { + String aObjClass = pValObj->GetClassName(); + + SbClassModuleObject* pClassModuleObj = PTR_CAST(SbClassModuleObject,pValObjBase); + if( pClassModuleObj != NULL ) + { + SbModule* pClassModule = pClassModuleObj->getClassModule(); + GaDimAsNewRecoverHash[refVar] = + DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), pClassModule ); + } + else if( aObjClass.EqualsIgnoreCaseAscii( "Collection" ) ) + { + GaDimAsNewRecoverHash[refVar] = + DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), NULL ); + } + } + } + } + } + } + + + // lhs is a property who's value is currently (Empty e.g. no broadcast yet) + // in this case if there is a default prop involved the value of the + // default property may infact be void so the type will also be SbxEMPTY + // in this case we do not want to call checkUnoStructCopy 'cause that will + // cause an error also + if ( !bHandleDefaultProp || ( bHandleDefaultProp && ( refVar->GetType() != SbxEMPTY ) ) ) + // #67607 Uno-Structs kopieren + checkUnoStructCopy( refVal, refVar ); + if( bFlagsChanged ) + refVar->SetFlags( n ); + } +} + +void SbiRuntime::StepSET() +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + StepSET_Impl( refVal, refVar, bVBAEnabled ); // this is really assigment +} + +void SbiRuntime::StepVBASET() +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + // don't handle default property + StepSET_Impl( refVal, refVar, false ); // set obj = something +} + + +// JSM 07.10.95 +void SbiRuntime::StepLSET() +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + if( refVar->GetType() != SbxSTRING + || refVal->GetType() != SbxSTRING ) + Error( SbERR_INVALID_USAGE_OBJECT ); + else + { + // Store auf die eigene Methode (innerhalb einer Function)? + USHORT n = refVar->GetFlags(); + if( (SbxVariable*) refVar == (SbxVariable*) pMeth ) + refVar->SetFlag( SBX_WRITE ); + String aRefVarString = refVar->GetString(); + String aRefValString = refVal->GetString(); + + USHORT nVarStrLen = aRefVarString.Len(); + USHORT nValStrLen = aRefValString.Len(); + String aNewStr; + if( nVarStrLen > nValStrLen ) + { + aRefVarString.Fill(nVarStrLen,' '); + aNewStr = aRefValString.Copy( 0, nValStrLen ); + aNewStr += aRefVarString.Copy( nValStrLen, nVarStrLen - nValStrLen ); + } + else + { + aNewStr = aRefValString.Copy( 0, nVarStrLen ); + } + + refVar->PutString( aNewStr ); + refVar->SetFlags( n ); + } +} + +// JSM 07.10.95 +void SbiRuntime::StepRSET() +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + if( refVar->GetType() != SbxSTRING + || refVal->GetType() != SbxSTRING ) + Error( SbERR_INVALID_USAGE_OBJECT ); + else + { + // Store auf die eigene Methode (innerhalb einer Function)? + USHORT n = refVar->GetFlags(); + if( (SbxVariable*) refVar == (SbxVariable*) pMeth ) + refVar->SetFlag( SBX_WRITE ); + String aRefVarString = refVar->GetString(); + String aRefValString = refVal->GetString(); + + USHORT nPos = 0; + USHORT nVarStrLen = aRefVarString.Len(); + if( nVarStrLen > aRefValString.Len() ) + { + aRefVarString.Fill(nVarStrLen,' '); + nPos = nVarStrLen - aRefValString.Len(); + } + aRefVarString = aRefVarString.Copy( 0, nPos ); + aRefVarString += aRefValString.Copy( 0, nVarStrLen - nPos ); + refVar->PutString(aRefVarString); + + refVar->SetFlags( n ); + } +} + +// Ablage von TOS in TOS-1, dann ReadOnly-Bit setzen + +void SbiRuntime::StepPUTC() +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + refVar->SetFlag( SBX_WRITE ); + *refVar = *refVal; + refVar->ResetFlag( SBX_WRITE ); + refVar->SetFlag( SBX_CONST ); +} + +// DIM +// TOS = Variable fuer das Array mit Dimensionsangaben als Parameter + +void SbiRuntime::StepDIM() +{ + SbxVariableRef refVar = PopVar(); + DimImpl( refVar ); +} + +// #56204 DIM-Funktionalitaet in Hilfsmethode auslagern (step0.cxx) +void SbiRuntime::DimImpl( SbxVariableRef refVar ) +{ + SbxArray* pDims = refVar->GetParameters(); + // Muss eine gerade Anzahl Argumente haben + // Man denke daran, dass Arg[0] nicht zaehlt! + if( pDims && !( pDims->Count() & 1 ) ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + { + SbxDataType eType = refVar->IsFixed() ? refVar->GetType() : SbxVARIANT; + SbxDimArray* pArray = new SbxDimArray( eType ); + // AB 2.4.1996, auch Arrays ohne Dimensionsangaben zulassen (VB-komp.) + if( pDims ) + { + for( USHORT i = 1; i < pDims->Count(); ) + { + INT32 lb = pDims->Get( i++ )->GetLong(); + INT32 ub = pDims->Get( i++ )->GetLong(); + if( ub < lb ) + Error( SbERR_OUT_OF_RANGE ), ub = lb; + pArray->AddDim32( lb, ub ); + if ( lb != ub ) + pArray->setHasFixedSize( true ); + } + } + else + { + // #62867 Beim Anlegen eines Arrays der Laenge 0 wie bei + // Uno-Sequences der Laenge 0 eine Dimension anlegen + pArray->unoAddDim( 0, -1 ); + } + USHORT nSavFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->PutObject( pArray ); + refVar->SetFlags( nSavFlags ); + refVar->SetParameters( NULL ); + } +} + +// REDIM +// TOS = Variable fuer das Array +// argv = Dimensionsangaben + +void SbiRuntime::StepREDIM() +{ + // Im Moment ist es nichts anderes als Dim, da doppeltes Dim + // bereits vom Compiler erkannt wird. + StepDIM(); +} + + +// Helper function for StepREDIMP +void implCopyDimArray( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex, + short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds ) +{ + sal_Int32& ri = pActualIndices[nActualDim]; + for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ ) + { + if( nActualDim < nMaxDimIndex ) + { + implCopyDimArray( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1, + pActualIndices, pLowerBounds, pUpperBounds ); + } + else + { + SbxVariable* pSource = pOldArray->Get32( pActualIndices ); + SbxVariable* pDest = pNewArray->Get32( pActualIndices ); + if( pSource && pDest ) + *pDest = *pSource; + } + } +} + +// REDIM PRESERVE +// TOS = Variable fuer das Array +// argv = Dimensionsangaben + +void SbiRuntime::StepREDIMP() +{ + SbxVariableRef refVar = PopVar(); + DimImpl( refVar ); + + // Now check, if we can copy from the old array + if( refRedimpArray.Is() ) + { + SbxBase* pElemObj = refVar->GetObject(); + SbxDimArray* pNewArray = PTR_CAST(SbxDimArray,pElemObj); + SbxDimArray* pOldArray = (SbxDimArray*)(SbxArray*)refRedimpArray; + if( pNewArray ) + { + short nDimsNew = pNewArray->GetDims(); + short nDimsOld = pOldArray->GetDims(); + short nDims = nDimsNew; + BOOL bRangeError = FALSE; + + // Store dims to use them for copying later + sal_Int32* pLowerBounds = new sal_Int32[nDims]; + sal_Int32* pUpperBounds = new sal_Int32[nDims]; + sal_Int32* pActualIndices = new sal_Int32[nDims]; + + if( nDimsOld != nDimsNew ) + { + bRangeError = TRUE; + } + else + { + // Compare bounds + for( short i = 1 ; i <= nDims ; i++ ) + { + sal_Int32 lBoundNew, uBoundNew; + sal_Int32 lBoundOld, uBoundOld; + pNewArray->GetDim32( i, lBoundNew, uBoundNew ); + pOldArray->GetDim32( i, lBoundOld, uBoundOld ); + + /* #69094 Allow all dimensions to be changed + although Visual Basic is not able to do so. + // All bounds but the last have to be the same + if( i < nDims && ( lBoundNew != lBoundOld || uBoundNew != uBoundOld ) ) + { + bRangeError = TRUE; + break; + } + else + */ + { + // #69094: if( i == nDims ) + { + lBoundNew = std::max( lBoundNew, lBoundOld ); + uBoundNew = std::min( uBoundNew, uBoundOld ); + } + short j = i - 1; + pActualIndices[j] = pLowerBounds[j] = lBoundNew; + pUpperBounds[j] = uBoundNew; + } + } + } + + if( bRangeError ) + { + StarBASIC::Error( SbERR_OUT_OF_RANGE ); + } + else + { + // Copy data from old array by going recursively through all dimensions + // (It would be faster to work on the flat internal data array of an + // SbyArray but this solution is clearer and easier) + implCopyDimArray( pNewArray, pOldArray, nDims - 1, + 0, pActualIndices, pLowerBounds, pUpperBounds ); + } + + delete[] pUpperBounds; + delete[] pLowerBounds; + delete[] pActualIndices; + refRedimpArray = NULL; + } + } + + //StarBASIC::FatalError( SbERR_NOT_IMPLEMENTED ); +} + +// REDIM_COPY +// TOS = Array-Variable, Reference to array is copied +// Variable is cleared as in ERASE + +void SbiRuntime::StepREDIMP_ERASE() +{ + SbxVariableRef refVar = PopVar(); + SbxDataType eType = refVar->GetType(); + if( eType & SbxARRAY ) + { + SbxBase* pElemObj = refVar->GetObject(); + SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj); + if( pDimArray ) + { + refRedimpArray = pDimArray; + } + + // As in ERASE + USHORT nSavFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->SetType( SbxDataType(eType & 0x0FFF) ); + refVar->SetFlags( nSavFlags ); + refVar->Clear(); + } + else + if( refVar->IsFixed() ) + refVar->Clear(); + else + refVar->SetType( SbxEMPTY ); +} + +void lcl_clearImpl( SbxVariableRef& refVar, SbxDataType& eType ) +{ + USHORT nSavFlags = refVar->GetFlags(); + refVar->ResetFlag( SBX_FIXED ); + refVar->SetType( SbxDataType(eType & 0x0FFF) ); + refVar->SetFlags( nSavFlags ); + refVar->Clear(); +} + +void lcl_eraseImpl( SbxVariableRef& refVar, bool bVBAEnabled ) +{ + SbxDataType eType = refVar->GetType(); + if( eType & SbxARRAY ) + { + if ( bVBAEnabled ) + { + SbxBase* pElemObj = refVar->GetObject(); + SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj); + bool bClearValues = true; + if( pDimArray ) + { + if ( pDimArray->hasFixedSize() ) + { + // Clear all Value(s) + pDimArray->SbxArray::Clear(); + bClearValues = false; + } + else + pDimArray->Clear(); // clear Dims + } + if ( bClearValues ) + { + SbxArray* pArray = PTR_CAST(SbxArray,pElemObj); + if ( pArray ) + pArray->Clear(); + } + } + else + // AB 2.4.1996 + // Arrays haben bei Erase nach VB ein recht komplexes Verhalten. Hier + // werden zunaechst nur die Typ-Probleme bei REDIM (#26295) beseitigt: + // Typ hart auf den Array-Typ setzen, da eine Variable mit Array + // SbxOBJECT ist. Bei REDIM entsteht dann ein SbxOBJECT-Array und + // der ursruengliche Typ geht verloren -> Laufzeitfehler + lcl_clearImpl( refVar, eType ); + } + else + if( refVar->IsFixed() ) + refVar->Clear(); + else + refVar->SetType( SbxEMPTY ); +} + +// Variable loeschen +// TOS = Variable + +void SbiRuntime::StepERASE() +{ + SbxVariableRef refVar = PopVar(); + lcl_eraseImpl( refVar, bVBAEnabled ); +} + +void SbiRuntime::StepERASE_CLEAR() +{ + SbxVariableRef refVar = PopVar(); + lcl_eraseImpl( refVar, bVBAEnabled ); + SbxDataType eType = refVar->GetType(); + lcl_clearImpl( refVar, eType ); +} + +void SbiRuntime::StepARRAYACCESS() +{ + if( !refArgv ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + SbxVariableRef refVar = PopVar(); + refVar->SetParameters( refArgv ); + PopArgv(); + PushVar( CheckArray( refVar ) ); +} + +void SbiRuntime::StepBYVAL() +{ + // Copy variable on stack to break call by reference + SbxVariableRef pVar = PopVar(); + SbxDataType t = pVar->GetType(); + + SbxVariable* pCopyVar = new SbxVariable( t ); + pCopyVar->SetFlag( SBX_READWRITE ); + *pCopyVar = *pVar; + + PushVar( pCopyVar ); +} + +// Einrichten eines Argvs +// nOp1 bleibt so -> 1. Element ist Returnwert + +void SbiRuntime::StepARGC() +{ + PushArgv(); + refArgv = new SbxArray; + nArgc = 1; +} + +// Speichern eines Arguments in Argv + +void SbiRuntime::StepARGV() +{ + if( !refArgv ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + { + SbxVariableRef pVal = PopVar(); + + // Before fix of #94916: + // if( pVal->ISA(SbxMethod) || pVal->ISA(SbxProperty) ) + if( pVal->ISA(SbxMethod) || pVal->ISA(SbUnoProperty) || pVal->ISA(SbProcedureProperty) ) + { + // Methoden und Properties evaluieren! + SbxVariable* pRes = new SbxVariable( *pVal ); + pVal = pRes; + } + refArgv->Put( pVal, nArgc++ ); + } +} + +// Input to Variable. Die Variable ist auf TOS und wird +// anschliessend entfernt. + +void SbiRuntime::StepINPUT() +{ + String s; + char ch = 0; + SbError err; + // Skip whitespace + while( ( err = pIosys->GetError() ) == 0 ) + { + ch = pIosys->Read(); + if( ch != ' ' && ch != '\t' && ch != '\n' ) + break; + } + if( !err ) + { + // Scan until comma or whitespace + char sep = ( ch == '"' ) ? ch : 0; + if( sep ) ch = pIosys->Read(); + while( ( err = pIosys->GetError() ) == 0 ) + { + if( ch == sep ) + { + ch = pIosys->Read(); + if( ch != sep ) + break; + } + else if( !sep && (ch == ',' || ch == '\n') ) + break; + s += ch; + ch = pIosys->Read(); + } + // skip whitespace + if( ch == ' ' || ch == '\t' ) + while( ( err = pIosys->GetError() ) == 0 ) + { + if( ch != ' ' && ch != '\t' && ch != '\n' ) + break; + ch = pIosys->Read(); + } + } + if( !err ) + { + SbxVariableRef pVar = GetTOS(); + // Zuerst versuchen, die Variable mit einem numerischen Wert + // zu fuellen, dann mit einem Stringwert + if( !pVar->IsFixed() || pVar->IsNumeric() ) + { + USHORT nLen = 0; + if( !pVar->Scan( s, &nLen ) ) + { + err = SbxBase::GetError(); + SbxBase::ResetError(); + } + // Der Wert muss komplett eingescant werden + else if( nLen != s.Len() && !pVar->PutString( s ) ) + { + err = SbxBase::GetError(); + SbxBase::ResetError(); + } + else if( nLen != s.Len() && pVar->IsNumeric() ) + { + err = SbxBase::GetError(); + SbxBase::ResetError(); + if( !err ) + err = SbERR_CONVERSION; + } + } + else + { + pVar->PutString( s ); + err = SbxBase::GetError(); + SbxBase::ResetError(); + } + } + if( err == SbERR_USER_ABORT ) + Error( err ); + else if( err ) + { + if( pRestart && !pIosys->GetChannel() ) + { + BasResId aId( IDS_SBERR_START + 4 ); + String aMsg( aId ); + + //****** DONT CHECK IN, TEST ONLY ******* + //****** DONT CHECK IN, TEST ONLY ******* + // ErrorBox( NULL, WB_OK, aMsg ).Execute(); + //****** DONT CHECK IN, TEST ONLY ******* + //****** DONT CHECK IN, TEST ONLY ******* + + pCode = pRestart; + } + else + Error( err ); + } + else + { + // pIosys->ResetChannel(); + PopVar(); + } +} + +// Line Input to Variable. Die Variable ist auf TOS und wird +// anschliessend entfernt. + +void SbiRuntime::StepLINPUT() +{ + ByteString aInput; + pIosys->Read( aInput ); + Error( pIosys->GetError() ); + SbxVariableRef p = PopVar(); + p->PutString( String( aInput, gsl_getSystemTextEncoding() ) ); + // pIosys->ResetChannel(); +} + +// Programmende + +void SbiRuntime::StepSTOP() +{ + pInst->Stop(); +} + +// FOR-Variable initialisieren + +void SbiRuntime::StepINITFOR() +{ + PushFor(); +} + +void SbiRuntime::StepINITFOREACH() +{ + PushForEach(); +} + +// FOR-Variable inkrementieren + +void SbiRuntime::StepNEXT() +{ + if( !pForStk ) + { + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + return; + } + if( pForStk->eForType == FOR_TO ) + pForStk->refVar->Compute( SbxPLUS, *pForStk->refInc ); +} + +// Anfang CASE: TOS in CASE-Stack + +void SbiRuntime::StepCASE() +{ + if( !refCaseStk.Is() ) + refCaseStk = new SbxArray; + SbxVariableRef xVar = PopVar(); + refCaseStk->Put( xVar, refCaseStk->Count() ); +} + +// Ende CASE: Variable freigeben + +void SbiRuntime::StepENDCASE() +{ + if( !refCaseStk || !refCaseStk->Count() ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + refCaseStk->Remove( refCaseStk->Count() - 1 ); +} + +// Standard-Fehlerbehandlung + +void SbiRuntime::StepSTDERROR() +{ + pError = NULL; bError = TRUE; + pInst->aErrorMsg = String(); + pInst->nErr = 0L; + pInst->nErl = 0; + nError = 0L; + SbxErrObject::getUnoErrObject()->Clear(); +} + +void SbiRuntime::StepNOERROR() +{ + pInst->aErrorMsg = String(); + pInst->nErr = 0L; + pInst->nErl = 0; + nError = 0L; + SbxErrObject::getUnoErrObject()->Clear(); + bError = FALSE; +} + +// UP verlassen + +void SbiRuntime::StepLEAVE() +{ + bRun = FALSE; + // If VBA and we are leaving an ErrorHandler then clear the error ( it's been processed ) + if ( bInError && pError ) + SbxErrObject::getUnoErrObject()->Clear(); +} + +void SbiRuntime::StepCHANNEL() // TOS = Kanalnummer +{ + SbxVariableRef pChan = PopVar(); + short nChan = pChan->GetInteger(); + pIosys->SetChannel( nChan ); + Error( pIosys->GetError() ); +} + +void SbiRuntime::StepCHANNEL0() +{ + pIosys->ResetChannel(); +} + +void SbiRuntime::StepPRINT() // print TOS +{ + SbxVariableRef p = PopVar(); + String s1 = p->GetString(); + String s; + if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE ) + s = ' '; // ein Blank davor + s += s1; + ByteString aByteStr( s, gsl_getSystemTextEncoding() ); + pIosys->Write( aByteStr ); + Error( pIosys->GetError() ); +} + +void SbiRuntime::StepPRINTF() // print TOS in field +{ + SbxVariableRef p = PopVar(); + String s1 = p->GetString(); + String s; + if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE ) + s = ' '; // ein Blank davor + s += s1; + s.Expand( 14, ' ' ); + ByteString aByteStr( s, gsl_getSystemTextEncoding() ); + pIosys->Write( aByteStr ); + Error( pIosys->GetError() ); +} + +void SbiRuntime::StepWRITE() // write TOS +{ + SbxVariableRef p = PopVar(); + // Muss der String gekapselt werden? + char ch = 0; + switch (p->GetType() ) + { + case SbxSTRING: ch = '"'; break; + case SbxCURRENCY: + case SbxBOOL: + case SbxDATE: ch = '#'; break; + default: break; + } + String s; + if( ch ) + s += ch; + s += p->GetString(); + if( ch ) + s += ch; + ByteString aByteStr( s, gsl_getSystemTextEncoding() ); + pIosys->Write( aByteStr ); + Error( pIosys->GetError() ); +} + +void SbiRuntime::StepRENAME() // Rename Tos+1 to Tos +{ + SbxVariableRef pTos1 = PopVar(); + SbxVariableRef pTos = PopVar(); + String aDest = pTos1->GetString(); + String aSource = pTos->GetString(); + + // <-- UCB + if( hasUno() ) + { + implStepRenameUCB( aSource, aDest ); + } + else + // --> UCB + { +#ifdef _OLD_FILE_IMPL + DirEntry aSourceDirEntry( aSource ); + if( aSourceDirEntry.Exists() ) + { + if( aSourceDirEntry.MoveTo( DirEntry(aDest) ) != FSYS_ERR_OK ) + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); + } + else + StarBASIC::Error( SbERR_PATH_NOT_FOUND ); +#else + implStepRenameOSL( aSource, aDest ); +#endif + } +} + +// TOS = Prompt + +void SbiRuntime::StepPROMPT() +{ + SbxVariableRef p = PopVar(); + ByteString aStr( p->GetString(), gsl_getSystemTextEncoding() ); + pIosys->SetPrompt( aStr ); +} + +// Set Restart point + +void SbiRuntime::StepRESTART() +{ + pRestart = pCode; +} + +// Leerer Ausdruck auf Stack fuer fehlenden Parameter + +void SbiRuntime::StepEMPTY() +{ + // #57915 Die Semantik von StepEMPTY() ist die Repraesentation eines fehlenden + // Arguments. Dies wird in VB durch ein durch den Wert 448 (SbERR_NAMED_NOT_FOUND) + // vom Typ Error repraesentiert. StepEmpty jetzt muesste besser StepMISSING() + // heissen, aber der Name wird der Einfachkeit halber beibehalten. + SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); + xVar->PutErr( 448 ); + PushVar( xVar ); + // ALT: PushVar( new SbxVariable( SbxEMPTY ) ); +} + +// TOS = Fehlercode + +void SbiRuntime::StepERROR() +{ + SbxVariableRef refCode = PopVar(); + USHORT n = refCode->GetUShort(); + SbError error = StarBASIC::GetSfxFromVBError( n ); + if ( bVBAEnabled ) + pInst->Error( error ); + else + Error( error ); +} + diff --git a/basic/source/runtime/step1.cxx b/basic/source/runtime/step1.cxx new file mode 100644 index 000000000000..e23ef864218e --- /dev/null +++ b/basic/source/runtime/step1.cxx @@ -0,0 +1,574 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include <stdlib.h> +#include <rtl/math.hxx> +#include <basic/sbuno.hxx> +#include "runtime.hxx" +#include "sbintern.hxx" +#include "iosys.hxx" +#include "image.hxx" +#include "sbunoobj.hxx" +#include "errobject.hxx" + +bool checkUnoObjectType( SbUnoObject* refVal, + const String& aClass ); + +// Laden einer numerischen Konstanten (+ID) + +void SbiRuntime::StepLOADNC( UINT32 nOp1 ) +{ + SbxVariable* p = new SbxVariable( SbxDOUBLE ); + + // #57844 Lokalisierte Funktion benutzen + String aStr = pImg->GetString( static_cast<short>( nOp1 ) ); + // Auch , zulassen !!! + USHORT iComma = aStr.Search( ',' ); + if( iComma != STRING_NOTFOUND ) + { + String aStr1 = aStr.Copy( 0, iComma ); + String aStr2 = aStr.Copy( iComma + 1 ); + aStr = aStr1; + aStr += '.'; + aStr += aStr2; + } + double n = ::rtl::math::stringToDouble( aStr, '.', ',', NULL, NULL ); + + p->PutDouble( n ); + PushVar( p ); +} + +// Laden einer Stringkonstanten (+ID) + +void SbiRuntime::StepLOADSC( UINT32 nOp1 ) +{ + SbxVariable* p = new SbxVariable; + p->PutString( pImg->GetString( static_cast<short>( nOp1 ) ) ); + PushVar( p ); +} + +// Immediate Load (+Wert) + +void SbiRuntime::StepLOADI( UINT32 nOp1 ) +{ + SbxVariable* p = new SbxVariable; + p->PutInteger( static_cast<INT16>( nOp1 ) ); + PushVar( p ); +} + +// Speichern eines named Arguments in Argv (+Arg-Nr ab 1!) + +void SbiRuntime::StepARGN( UINT32 nOp1 ) +{ + if( !refArgv ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + { + String aAlias( pImg->GetString( static_cast<short>( nOp1 ) ) ); + SbxVariableRef pVal = PopVar(); + refArgv->Put( pVal, nArgc ); + refArgv->PutAlias( aAlias, nArgc++ ); + } +} + +// Konvertierung des Typs eines Arguments in Argv fuer DECLARE-Fkt. (+Typ) + +void SbiRuntime::StepARGTYP( UINT32 nOp1 ) +{ + if( !refArgv ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + { + BOOL bByVal = (nOp1 & 0x8000) != 0; // Ist BYVAL verlangt? + SbxDataType t = (SbxDataType) (nOp1 & 0x7FFF); + SbxVariable* pVar = refArgv->Get( refArgv->Count() - 1 ); // letztes Arg + + // BYVAL prüfen + if( pVar->GetRefCount() > 2 ) // 2 ist normal für BYVAL + { + // Parameter ist eine Referenz + if( bByVal ) + { + // Call by Value ist verlangt -> Kopie anlegen + pVar = new SbxVariable( *pVar ); + pVar->SetFlag( SBX_READWRITE ); + refExprStk->Put( pVar, refArgv->Count() - 1 ); + } + else + pVar->SetFlag( SBX_REFERENCE ); // Ref-Flag für DllMgr + } + else + { + // Parameter ist KEINE Referenz + if( bByVal ) + pVar->ResetFlag( SBX_REFERENCE ); // Keine Referenz -> OK + else + Error( SbERR_BAD_PARAMETERS ); // Referenz verlangt + } + + if( pVar->GetType() != t ) + { + // Variant, damit richtige Konvertierung + // Ausserdem Fehler, wenn SbxBYREF + pVar->Convert( SbxVARIANT ); + pVar->Convert( t ); + } + } +} + +// String auf feste Laenge bringen (+Laenge) + +void SbiRuntime::StepPAD( UINT32 nOp1 ) +{ + SbxVariable* p = GetTOS(); + String& s = (String&)(const String&) *p; + if( s.Len() > nOp1 ) + s.Erase( static_cast<xub_StrLen>( nOp1 ) ); + else + s.Expand( static_cast<xub_StrLen>( nOp1 ), ' ' ); +} + +// Sprung (+Target) + +void SbiRuntime::StepJUMP( UINT32 nOp1 ) +{ +#ifdef DBG_UTIL + // #QUESTION shouln't this be + // if( (BYTE*)( nOp1+pImagGetCode() ) >= pImg->GetCodeSize() ) + if( nOp1 >= pImg->GetCodeSize() ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); +#endif + pCode = (const BYTE*) pImg->GetCode() + nOp1; +} + +// TOS auswerten, bedingter Sprung (+Target) + +void SbiRuntime::StepJUMPT( UINT32 nOp1 ) +{ + SbxVariableRef p = PopVar(); + if( p->GetBool() ) + StepJUMP( nOp1 ); +} + +// TOS auswerten, bedingter Sprung (+Target) + +void SbiRuntime::StepJUMPF( UINT32 nOp1 ) +{ + SbxVariableRef p = PopVar(); + if( !p->GetBool() ) + StepJUMP( nOp1 ); +} + +// TOS auswerten, Sprung in JUMP-Tabelle (+MaxVal) +// Sieht so aus: +// ONJUMP 2 +// JUMP target1 +// JUMP target2 +// ... +//Falls im Operanden 0x8000 gesetzt ist, Returnadresse pushen (ON..GOSUB) + +void SbiRuntime::StepONJUMP( UINT32 nOp1 ) +{ + SbxVariableRef p = PopVar(); + INT16 n = p->GetInteger(); + if( nOp1 & 0x8000 ) + { + nOp1 &= 0x7FFF; + //PushGosub( pCode + 3 * nOp1 ); + PushGosub( pCode + 5 * nOp1 ); + } + if( n < 1 || static_cast<UINT32>(n) > nOp1 ) + n = static_cast<INT16>( nOp1 + 1 ); + //nOp1 = (UINT32) ( (const char*) pCode - pImg->GetCode() ) + 3 * --n; + nOp1 = (UINT32) ( (const char*) pCode - pImg->GetCode() ) + 5 * --n; + StepJUMP( nOp1 ); +} + +// UP-Aufruf (+Target) + +void SbiRuntime::StepGOSUB( UINT32 nOp1 ) +{ + PushGosub( pCode ); + if( nOp1 >= pImg->GetCodeSize() ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + pCode = (const BYTE*) pImg->GetCode() + nOp1; +} + +// UP-Return (+0 oder Target) + +void SbiRuntime::StepRETURN( UINT32 nOp1 ) +{ + PopGosub(); + if( nOp1 ) + StepJUMP( nOp1 ); +} + +// FOR-Variable testen (+Endlabel) + +void SbiRuntime::StepTESTFOR( UINT32 nOp1 ) +{ + if( !pForStk ) + { + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + return; + } + + bool bEndLoop = false; + switch( pForStk->eForType ) + { + case FOR_TO: + { + SbxOperator eOp = ( pForStk->refInc->GetDouble() < 0 ) ? SbxLT : SbxGT; + if( pForStk->refVar->Compare( eOp, *pForStk->refEnd ) ) + bEndLoop = true; + break; + } + case FOR_EACH_ARRAY: + { + SbiForStack* p = pForStk; + if( p->pArrayCurIndices == NULL ) + { + bEndLoop = true; + } + else + { + SbxDimArray* pArray = (SbxDimArray*)(SbxVariable*)p->refEnd; + short nDims = pArray->GetDims(); + + // Empty array? + if( nDims == 1 && p->pArrayLowerBounds[0] > p->pArrayUpperBounds[0] ) + { + bEndLoop = true; + break; + } + SbxVariable* pVal = pArray->Get32( p->pArrayCurIndices ); + *(p->refVar) = *pVal; + + bool bFoundNext = false; + for( short i = 0 ; i < nDims ; i++ ) + { + if( p->pArrayCurIndices[i] < p->pArrayUpperBounds[i] ) + { + bFoundNext = true; + p->pArrayCurIndices[i]++; + for( short j = i - 1 ; j >= 0 ; j-- ) + p->pArrayCurIndices[j] = p->pArrayLowerBounds[j]; + break; + } + } + if( !bFoundNext ) + { + delete[] p->pArrayCurIndices; + p->pArrayCurIndices = NULL; + } + } + break; + } + case FOR_EACH_COLLECTION: + { + BasicCollection* pCollection = (BasicCollection*)(SbxVariable*)pForStk->refEnd; + SbxArrayRef xItemArray = pCollection->xItemArray; + INT32 nCount = xItemArray->Count32(); + if( pForStk->nCurCollectionIndex < nCount ) + { + SbxVariable* pRes = xItemArray->Get32( pForStk->nCurCollectionIndex ); + pForStk->nCurCollectionIndex++; + (*pForStk->refVar) = *pRes; + } + else + { + bEndLoop = true; + } + break; + } + case FOR_EACH_XENUMERATION: + { + SbiForStack* p = pForStk; + if( p->xEnumeration->hasMoreElements() ) + { + Any aElem = p->xEnumeration->nextElement(); + SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); + unoToSbxValue( (SbxVariable*)xVar, aElem ); + (*pForStk->refVar) = *xVar; + } + else + { + bEndLoop = true; + } + break; + } + } + if( bEndLoop ) + { + PopFor(); + StepJUMP( nOp1 ); + } +} + +// Tos+1 <= Tos+2 <= Tos, 2xremove (+Target) + +void SbiRuntime::StepCASETO( UINT32 nOp1 ) +{ + if( !refCaseStk || !refCaseStk->Count() ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + { + SbxVariableRef xTo = PopVar(); + SbxVariableRef xFrom = PopVar(); + SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 ); + if( *xCase >= *xFrom && *xCase <= *xTo ) + StepJUMP( nOp1 ); + } +} + +// Fehler-Handler + +void SbiRuntime::StepERRHDL( UINT32 nOp1 ) +{ + const BYTE* p = pCode; + StepJUMP( nOp1 ); + pError = pCode; + pCode = p; + pInst->aErrorMsg = String(); + pInst->nErr = 0; + pInst->nErl = 0; + nError = 0; + SbxErrObject::getUnoErrObject()->Clear(); +} + +// Resume nach Fehlern (+0=statement, 1=next or Label) + +void SbiRuntime::StepRESUME( UINT32 nOp1 ) +{ + // AB #32714 Resume ohne Error? -> Fehler + if( !bInError ) + { + Error( SbERR_BAD_RESUME ); + return; + } + if( nOp1 ) + { + // Code-Zeiger auf naechstes Statement setzen + USHORT n1, n2; + pCode = pMod->FindNextStmnt( pErrCode, n1, n2, TRUE, pImg ); + } + else + pCode = pErrStmnt; + if ( pError ) // current in error handler ( and got a Resume Next statment ) + SbxErrObject::getUnoErrObject()->Clear(); + + if( nOp1 > 1 ) + StepJUMP( nOp1 ); + pInst->aErrorMsg = String(); + pInst->nErr = 0; + pInst->nErl = 0; + nError = 0; + bInError = FALSE; + + // Error-Stack loeschen + SbErrorStack*& rErrStack = GetSbData()->pErrStack; + delete rErrStack; + rErrStack = NULL; +} + +// Kanal schliessen (+Kanal, 0=Alle) +void SbiRuntime::StepCLOSE( UINT32 nOp1 ) +{ + SbError err; + if( !nOp1 ) + pIosys->Shutdown(); + else + { + err = pIosys->GetError(); + if( !err ) + { + pIosys->Close(); + } + } + err = pIosys->GetError(); + Error( err ); +} + +// Zeichen ausgeben (+char) + +void SbiRuntime::StepPRCHAR( UINT32 nOp1 ) +{ + ByteString s( (char) nOp1 ); + pIosys->Write( s ); + Error( pIosys->GetError() ); +} + +// Check, ob TOS eine bestimmte Objektklasse ist (+StringID) + +bool SbiRuntime::implIsClass( SbxObject* pObj, const String& aClass ) +{ + bool bRet = true; + + if( aClass.Len() != 0 ) + { + bRet = pObj->IsClass( aClass ); + if( !bRet ) + bRet = aClass.EqualsIgnoreCaseAscii( String( RTL_CONSTASCII_USTRINGPARAM("object") ) ); + if( !bRet ) + { + String aObjClass = pObj->GetClassName(); + SbModule* pClassMod = pCLASSFAC->FindClass( aObjClass ); + SbClassData* pClassData; + if( pClassMod && (pClassData=pClassMod->pClassData) != NULL ) + { + SbxVariable* pClassVar = + pClassData->mxIfaces->Find( aClass, SbxCLASS_DONTCARE ); + bRet = (pClassVar != NULL); + } + } + } + return bRet; +} + +bool SbiRuntime::checkClass_Impl( const SbxVariableRef& refVal, + const String& aClass, bool bRaiseErrors, bool bDefault ) +{ + bool bOk = bDefault; + + SbxDataType t = refVal->GetType(); + if( t == SbxOBJECT ) + { + SbxObject* pObj; + SbxVariable* pVal = (SbxVariable*)refVal; + if( pVal->IsA( TYPE(SbxObject) ) ) + pObj = (SbxObject*) pVal; + else + { + pObj = (SbxObject*) refVal->GetObject(); + if( pObj && !pObj->IsA( TYPE(SbxObject) ) ) + pObj = NULL; + } + if( pObj ) + { + if( !implIsClass( pObj, aClass ) ) + { + if ( bVBAEnabled && pObj->IsA( TYPE(SbUnoObject) ) ) + { + SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pObj); + bOk = checkUnoObjectType( pUnoObj, aClass ); + } + else + bOk = false; + if ( !bOk ) + { + if( bRaiseErrors ) + Error( SbERR_INVALID_USAGE_OBJECT ); + } + } + else + { + bOk = true; + + SbClassModuleObject* pClassModuleObject = PTR_CAST(SbClassModuleObject,pObj); + if( pClassModuleObject != NULL ) + pClassModuleObject->triggerInitializeEvent(); + } + } + } + else + { + if ( !bVBAEnabled ) + { + if( bRaiseErrors ) + Error( SbERR_NEEDS_OBJECT ); + bOk = false; + } + } + return bOk; +} + +void SbiRuntime::StepSETCLASS_impl( UINT32 nOp1, bool bHandleDflt ) +{ + SbxVariableRef refVal = PopVar(); + SbxVariableRef refVar = PopVar(); + String aClass( pImg->GetString( static_cast<short>( nOp1 ) ) ); + + bool bOk = checkClass_Impl( refVal, aClass, true ); + if( bOk ) + StepSET_Impl( refVal, refVar, bHandleDflt ); // don't do handle dflt prop for a "proper" set +} + +void SbiRuntime::StepVBASETCLASS( UINT32 nOp1 ) +{ + StepSETCLASS_impl( nOp1, false ); +} + +void SbiRuntime::StepSETCLASS( UINT32 nOp1 ) +{ + StepSETCLASS_impl( nOp1, true ); +} + +void SbiRuntime::StepTESTCLASS( UINT32 nOp1 ) +{ + SbxVariableRef xObjVal = PopVar(); + String aClass( pImg->GetString( static_cast<short>( nOp1 ) ) ); + bool bDefault = !bVBAEnabled; + bool bOk = checkClass_Impl( xObjVal, aClass, false, bDefault ); + + SbxVariable* pRet = new SbxVariable; + pRet->PutBool( bOk ); + PushVar( pRet ); +} + +// Library fuer anschliessenden Declare-Call definieren + +void SbiRuntime::StepLIB( UINT32 nOp1 ) +{ + aLibName = pImg->GetString( static_cast<short>( nOp1 ) ); +} + +// TOS wird um BASE erhoeht, BASE davor gepusht (+BASE) +// Dieser Opcode wird vor DIM/REDIM-Anweisungen gepusht, +// wenn nur ein Index angegeben wurde. + +void SbiRuntime::StepBASED( UINT32 nOp1 ) +{ + SbxVariable* p1 = new SbxVariable; + SbxVariableRef x2 = PopVar(); + + // #109275 Check compatiblity mode + bool bCompatible = ((nOp1 & 0x8000) != 0); + USHORT uBase = static_cast<USHORT>(nOp1 & 1); // Can only be 0 or 1 + p1->PutInteger( uBase ); + if( !bCompatible ) + x2->Compute( SbxPLUS, *p1 ); + PushVar( x2 ); // erst die Expr + PushVar( p1 ); // dann die Base +} + + + + + diff --git a/basic/source/runtime/step2.cxx b/basic/source/runtime/step2.cxx new file mode 100755 index 000000000000..64a9d86ab940 --- /dev/null +++ b/basic/source/runtime/step2.cxx @@ -0,0 +1,1301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include "runtime.hxx" +#ifndef GCC +#endif +#include "iosys.hxx" +#include "image.hxx" +#include "sbintern.hxx" +#include "sbunoobj.hxx" +#include "opcodes.hxx" + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/script/XDefaultMethod.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <comphelper/processfactory.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::container; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::script; + +using com::sun::star::uno::Reference; + +SbxVariable* getVBAConstant( const String& rName ); + +// Suchen eines Elements +// Die Bits im String-ID: +// 0x8000 - Argv ist belegt + +SbxVariable* SbiRuntime::FindElement + ( SbxObject* pObj, UINT32 nOp1, UINT32 nOp2, SbError nNotFound, BOOL bLocal, BOOL bStatic ) +{ + bool bIsVBAInterOp = SbiRuntime::isVBAEnabled(); + if( bIsVBAInterOp ) + { + StarBASIC* pMSOMacroRuntimeLib = GetSbData()->pMSOMacroRuntimLib; + if( pMSOMacroRuntimeLib != NULL ) + pMSOMacroRuntimeLib->ResetFlag( SBX_EXTSEARCH ); + } + + SbxVariable* pElem = NULL; + if( !pObj ) + { + Error( SbERR_NO_OBJECT ); + pElem = new SbxVariable; + } + else + { + BOOL bFatalError = FALSE; + SbxDataType t = (SbxDataType) nOp2; + String aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) ); + // Hacky capture of Evaluate [] syntax + // this should be tackled I feel at the pcode level + if ( bIsVBAInterOp && aName.Search('[') == 0 ) + { + // emulate pcode here + StepARGC(); + // psuedo StepLOADSC + String sArg = aName.Copy( 1, aName.Len() - 2 ); + SbxVariable* p = new SbxVariable; + p->PutString( sArg ); + PushVar( p ); + // + StepARGV(); + nOp1 = nOp1 | 0x8000; // indicate params are present + aName = String::CreateFromAscii("Evaluate"); + } + if( bLocal ) + { + if ( bStatic ) + { + if ( pMeth ) + pElem = pMeth->GetStatics()->Find( aName, SbxCLASS_DONTCARE ); + } + + if ( !pElem ) + pElem = refLocals->Find( aName, SbxCLASS_DONTCARE ); + } + if( !pElem ) + { + // Die RTL brauchen wir nicht mehr zu durchsuchen! + BOOL bSave = rBasic.bNoRtl; + rBasic.bNoRtl = TRUE; + pElem = pObj->Find( aName, SbxCLASS_DONTCARE ); + + // #110004, #112015: Make private really private + if( bLocal && pElem ) // Local as flag for global search + { + if( pElem->IsSet( SBX_PRIVATE ) ) + { + SbiInstance* pInst_ = pINST; + if( pInst_ && pInst_->IsCompatibility() && pObj != pElem->GetParent() ) + pElem = NULL; // Found but in wrong module! + + // Interfaces: Use SBX_EXTFOUND + } + } + rBasic.bNoRtl = bSave; + + // Ist es ein globaler Uno-Bezeichner? + if( bLocal && !pElem ) + { + bool bSetName = true; // preserve normal behaviour + + // i#i68894# if VBAInterOp favour searching vba globals + // over searching for uno classess + if ( bVBAEnabled ) + { + // Try Find in VBA symbols space + pElem = rBasic.VBAFind( aName, SbxCLASS_DONTCARE ); + if ( pElem ) + bSetName = false; // don't overwrite uno name + else + pElem = getVBAConstant( aName ); + } + + if( !pElem ) + { + // #72382 VORSICHT! Liefert jetzt wegen unbekannten + // Modulen IMMER ein Ergebnis! + SbUnoClass* pUnoClass = findUnoClass( aName ); + if( pUnoClass ) + { + pElem = new SbxVariable( t ); + SbxValues aRes( SbxOBJECT ); + aRes.pObj = pUnoClass; + pElem->SbxVariable::Put( aRes ); + } + } + + // #62939 Wenn eine Uno-Klasse gefunden wurde, muss + // das Wrapper-Objekt gehalten werden, da sonst auch + // die Uno-Klasse, z.B. "stardiv" immer wieder neu + // aus der Registry gelesen werden muss + if( pElem ) + { + // #63774 Darf nicht mit gespeichert werden!!! + pElem->SetFlag( SBX_DONTSTORE ); + pElem->SetFlag( SBX_NO_MODIFY); + + // #72382 Lokal speichern, sonst werden alle implizit + // deklarierten Vars automatisch global ! + if ( bSetName ) + pElem->SetName( aName ); + refLocals->Put( pElem, refLocals->Count() ); + } + } + + if( !pElem ) + { + // Nicht da und nicht im Objekt? + // Hat das Ding Parameter, nicht einrichten! + if( nOp1 & 0x8000 ) + bFatalError = TRUE; + // ALT: StarBASIC::FatalError( nNotFound ); + + // Sonst, falls keine Parameter sind, anderen Error Code verwenden + if( !bLocal || pImg->GetFlag( SBIMG_EXPLICIT ) ) + { + // #39108 Bei explizit und als ELEM immer ein Fatal Error + bFatalError = TRUE; + + // Falls keine Parameter sind, anderen Error Code verwenden + if( !( nOp1 & 0x8000 ) && nNotFound == SbERR_PROC_UNDEFINED ) + nNotFound = SbERR_VAR_UNDEFINED; + } + if( bFatalError ) + { + // #39108 Statt FatalError zu setzen, Dummy-Variable liefern + if( !xDummyVar.Is() ) + xDummyVar = new SbxVariable( SbxVARIANT ); + pElem = xDummyVar; + + // Parameter von Hand loeschen + ClearArgvStack(); + + // Normalen Error setzen + Error( nNotFound, aName ); + } + else + { + if ( bStatic ) + pElem = StepSTATIC_Impl( aName, t ); + if ( !pElem ) + { + // Sonst Variable neu anlegen + pElem = new SbxVariable( t ); + if( t != SbxVARIANT ) + pElem->SetFlag( SBX_FIXED ); + pElem->SetName( aName ); + refLocals->Put( pElem, refLocals->Count() ); + } + } + } + } + // #39108 Args koennen schon geloescht sein! + if( !bFatalError ) + SetupArgs( pElem, nOp1 ); + // Ein bestimmter Call-Type wurde gewuenscht, daher muessen + // wir hier den Typ setzen und das Ding anfassen, um den + // korrekten Returnwert zu erhalten! + if( pElem->IsA( TYPE(SbxMethod) ) ) + { + // Soll der Typ konvertiert werden? + SbxDataType t2 = pElem->GetType(); + BOOL bSet = FALSE; + if( !( pElem->GetFlags() & SBX_FIXED ) ) + { + if( t != SbxVARIANT && t != t2 && + t >= SbxINTEGER && t <= SbxSTRING ) + pElem->SetType( t ), bSet = TRUE; + } + // pElem auf eine Ref zuweisen, um ggf. eine Temp-Var zu loeschen + SbxVariableRef refTemp = pElem; + + // Moegliche Reste vom letzten Aufruf der SbxMethod beseitigen + // Vorher Schreiben freigeben, damit kein Error gesetzt wird. + USHORT nSavFlags = pElem->GetFlags(); + pElem->SetFlag( SBX_READWRITE | SBX_NO_BROADCAST ); + pElem->SbxValue::Clear(); + pElem->SetFlags( nSavFlags ); + + // Erst nach dem Setzen anfassen, da z.B. LEFT() + // den Unterschied zwischen Left$() und Left() kennen muss + + // AB 12.8.96: Da in PopVar() die Parameter von Methoden weggehauen + // werden, muessen wir hier explizit eine neue SbxMethod anlegen + SbxVariable* pNew = new SbxMethod( *((SbxMethod*)pElem) ); // das ist der Call! + //ALT: SbxVariable* pNew = new SbxVariable( *pElem ); // das ist der Call! + + pElem->SetParameters(0); // sonst bleibt Ref auf sich selbst + pNew->SetFlag( SBX_READWRITE ); + + // den Datentypen zuruecksetzen? + if( bSet ) + pElem->SetType( t2 ); + pElem = pNew; + } + // Index-Access bei UnoObjekten beruecksichtigen + // definitely we want this for VBA where properties are often + // collections ( which need index access ), but lets only do + // this if we actually have params following + else if( bVBAEnabled && pElem->ISA(SbUnoProperty) && pElem->GetParameters() ) + { + // pElem auf eine Ref zuweisen, um ggf. eine Temp-Var zu loeschen + SbxVariableRef refTemp = pElem; + + // Variable kopieren und dabei den Notify aufloesen + SbxVariable* pNew = new SbxVariable( *((SbxVariable*)pElem) ); // das ist der Call! + pElem->SetParameters( NULL ); // sonst bleibt Ref auf sich selbst + pElem = pNew; + } + } + return CheckArray( pElem ); +} + +// Find-Funktion ueber Name fuer aktuellen Scope (z.B. Abfrage aus BASIC-IDE) +SbxBase* SbiRuntime::FindElementExtern( const String& rName ) +{ + // Hinweis zu #35281#: Es darf nicht davon ausgegangen werden, dass + // pMeth != null, da im RunInit noch keine gesetzt ist. + + SbxVariable* pElem = NULL; + if( !pMod || !rName.Len() ) + return NULL; + + // Lokal suchen + if( refLocals ) + pElem = refLocals->Find( rName, SbxCLASS_DONTCARE ); + + // In Statics suchen + if ( !pElem && pMeth ) + { + // Bei Statics, Name der Methode davor setzen + String aMethName = pMeth->GetName(); + aMethName += ':'; + aMethName += rName; + pElem = pMod->Find(aMethName, SbxCLASS_DONTCARE); + } + + // In Parameter-Liste suchen + if( !pElem && pMeth ) + { + SbxInfo* pInfo = pMeth->GetInfo(); + if( pInfo && refParams ) + { + USHORT nParamCount = refParams->Count(); + USHORT j = 1; + const SbxParamInfo* pParam = pInfo->GetParam( j ); + while( pParam ) + { + if( pParam->aName.EqualsIgnoreCaseAscii( rName ) ) + { + if( j >= nParamCount ) + { + // Parameter is missing + pElem = new SbxVariable( SbxSTRING ); + pElem->PutString( String( RTL_CONSTASCII_USTRINGPARAM("<missing parameter>" ) ) ); + } + else + { + pElem = refParams->Get( j ); + } + break; + } + pParam = pInfo->GetParam( ++j ); + } + } + } + + // Im Modul suchen + if( !pElem ) + { + // RTL nicht durchsuchen! + BOOL bSave = rBasic.bNoRtl; + rBasic.bNoRtl = TRUE; + pElem = pMod->Find( rName, SbxCLASS_DONTCARE ); + rBasic.bNoRtl = bSave; + } + return pElem; +} + + +// Argumente eines Elements setzen +// Dabei auch die Argumente umsetzen, falls benannte Parameter +// verwendet wurden + +void SbiRuntime::SetupArgs( SbxVariable* p, UINT32 nOp1 ) +{ + if( nOp1 & 0x8000 ) + { + if( !refArgv ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + BOOL bHasNamed = FALSE; + USHORT i; + USHORT nArgCount = refArgv->Count(); + for( i = 1 ; i < nArgCount ; i++ ) + { + if( refArgv->GetAlias( i ).Len() ) + { + bHasNamed = TRUE; break; + } + } + if( bHasNamed ) + { + // Wir haben mindestens einen benannten Parameter! + // Wir muessen also umsortieren + // Gibt es Parameter-Infos? + SbxInfo* pInfo = p->GetInfo(); + if( !pInfo ) + { + bool bError_ = true; + + SbUnoMethod* pUnoMethod = PTR_CAST(SbUnoMethod,p); + SbUnoProperty* pUnoProperty = PTR_CAST(SbUnoProperty,p); + if( pUnoMethod || pUnoProperty ) + { + SbUnoObject* pParentUnoObj = PTR_CAST( SbUnoObject,p->GetParent() ); + if( pParentUnoObj ) + { + Any aUnoAny = pParentUnoObj->getUnoAny(); + Reference< XInvocation > xInvocation; + aUnoAny >>= xInvocation; + if( xInvocation.is() ) // TODO: if( xOLEAutomation.is() ) + { + bError_ = false; + + USHORT nCurPar = 1; + AutomationNamedArgsSbxArray* pArg = + new AutomationNamedArgsSbxArray( nArgCount ); + ::rtl::OUString* pNames = pArg->getNames().getArray(); + for( i = 1 ; i < nArgCount ; i++ ) + { + SbxVariable* pVar = refArgv->Get( i ); + const String& rName = refArgv->GetAlias( i ); + if( rName.Len() ) + pNames[i] = rName; + pArg->Put( pVar, nCurPar++ ); + } + refArgv = pArg; + } + } + } + else if( bVBAEnabled && p->GetType() == SbxOBJECT && (!p->ISA(SbxMethod) || !p->IsBroadcaster()) ) + { + // Check for default method with named parameters + SbxBaseRef pObj = (SbxBase*)p->GetObject(); + if( pObj && pObj->ISA(SbUnoObject) ) + { + SbUnoObject* pUnoObj = (SbUnoObject*)(SbxBase*)pObj; + Any aAny = pUnoObj->getUnoAny(); + + if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) + { + Reference< XInterface > x = *(Reference< XInterface >*)aAny.getValue(); + Reference< XDefaultMethod > xDfltMethod( x, UNO_QUERY ); + + rtl::OUString sDefaultMethod; + if ( xDfltMethod.is() ) + sDefaultMethod = xDfltMethod->getDefaultMethodName(); + if ( sDefaultMethod.getLength() ) + { + SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxCLASS_METHOD ); + if( meth != NULL ) + pInfo = meth->GetInfo(); + if( pInfo ) + bError_ = false; + } + } + } + } + if( bError_ ) + Error( SbERR_NO_NAMED_ARGS ); + } + else + { + USHORT nCurPar = 1; + SbxArray* pArg = new SbxArray; + for( i = 1 ; i < nArgCount ; i++ ) + { + SbxVariable* pVar = refArgv->Get( i ); + const String& rName = refArgv->GetAlias( i ); + if( rName.Len() ) + { + // nCurPar wird auf den gefundenen Parameter gesetzt + USHORT j = 1; + const SbxParamInfo* pParam = pInfo->GetParam( j ); + while( pParam ) + { + if( pParam->aName.EqualsIgnoreCaseAscii( rName ) ) + { + nCurPar = j; + break; + } + pParam = pInfo->GetParam( ++j ); + } + if( !pParam ) + { + Error( SbERR_NAMED_NOT_FOUND ); break; + } + } + pArg->Put( pVar, nCurPar++ ); + } + refArgv = pArg; + } + } + // Eigene Var als Parameter 0 + refArgv->Put( p, 0 ); + p->SetParameters( refArgv ); + PopArgv(); + } + else + p->SetParameters( NULL ); +} + +// Holen eines Array-Elements + +SbxVariable* SbiRuntime::CheckArray( SbxVariable* pElem ) +{ + // Falls wir ein Array haben, wollen wir bitte das Array-Element! + SbxArray* pPar; + if( pElem->GetType() & SbxARRAY ) + { + SbxBase* pElemObj = pElem->GetObject(); + SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj); + pPar = pElem->GetParameters(); + if( pDimArray ) + { + // Die Parameter koennen fehlen, wenn ein Array als + // Argument uebergeben wird. + if( pPar ) + pElem = pDimArray->Get( pPar ); + } + else + { + SbxArray* pArray = PTR_CAST(SbxArray,pElemObj); + if( pArray ) + { + if( !pPar ) + { + Error( SbERR_OUT_OF_RANGE ); + pElem = new SbxVariable; + } + else + pElem = pArray->Get( pPar->Get( 1 )->GetInteger() ); + } + } + + // #42940, 0.Parameter zu NULL setzen, damit sich Var nicht selbst haelt + if( pPar ) + pPar->Put( NULL, 0 ); + } + // Index-Access bei UnoObjekten beruecksichtigen + else if( pElem->GetType() == SbxOBJECT && (!pElem->ISA(SbxMethod) || !pElem->IsBroadcaster()) ) + { + pPar = pElem->GetParameters(); + if ( pPar ) + { + // Ist es ein Uno-Objekt? + SbxBaseRef pObj = (SbxBase*)pElem->GetObject(); + if( pObj ) + { + if( pObj->ISA(SbUnoObject) ) + { + SbUnoObject* pUnoObj = (SbUnoObject*)(SbxBase*)pObj; + Any aAny = pUnoObj->getUnoAny(); + + if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) + { + Reference< XInterface > x = *(Reference< XInterface >*)aAny.getValue(); + Reference< XIndexAccess > xIndexAccess( x, UNO_QUERY ); + if ( !bVBAEnabled ) + { + // Haben wir Index-Access? + if( xIndexAccess.is() ) + { + UINT32 nParamCount = (UINT32)pPar->Count() - 1; + if( nParamCount != 1 ) + { + StarBASIC::Error( SbERR_BAD_ARGUMENT ); + return pElem; + } + + // Index holen + INT32 nIndex = pPar->Get( 1 )->GetLong(); + Reference< XInterface > xRet; + try + { + Any aAny2 = xIndexAccess->getByIndex( nIndex ); + TypeClass eType = aAny2.getValueType().getTypeClass(); + if( eType == TypeClass_INTERFACE ) + xRet = *(Reference< XInterface >*)aAny2.getValue(); + } + catch (IndexOutOfBoundsException&) + { + // Bei Exception erstmal immer von Konvertierungs-Problem ausgehen + StarBASIC::Error( SbERR_OUT_OF_RANGE ); + } + + // #57847 Immer neue Variable anlegen, sonst Fehler + // durch PutObject(NULL) bei ReadOnly-Properties. + pElem = new SbxVariable( SbxVARIANT ); + if( xRet.is() ) + { + aAny <<= xRet; + + // #67173 Kein Namen angeben, damit echter Klassen-Namen eintragen wird + String aName; + SbxObjectRef xWrapper = (SbxObject*)new SbUnoObject( aName, aAny ); + pElem->PutObject( xWrapper ); + } + else + { + pElem->PutObject( NULL ); + } + } + } + else + { + rtl::OUString sDefaultMethod; + + Reference< XDefaultMethod > xDfltMethod( x, UNO_QUERY ); + + if ( xDfltMethod.is() ) + sDefaultMethod = xDfltMethod->getDefaultMethodName(); + else if( xIndexAccess.is() ) + sDefaultMethod = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getByIndex" ) ); + + if ( sDefaultMethod.getLength() ) + { + SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxCLASS_METHOD ); + SbxVariableRef refTemp = meth; + if ( refTemp ) + { + meth->SetParameters( pPar ); + SbxVariable* pNew = new SbxMethod( *(SbxMethod*)meth ); + pElem = pNew; + } + } + } + } + + // #42940, 0.Parameter zu NULL setzen, damit sich Var nicht selbst haelt + pPar->Put( NULL, 0 ); + } + else if( pObj->ISA(BasicCollection) ) + { + BasicCollection* pCol = (BasicCollection*)(SbxBase*)pObj; + pElem = new SbxVariable( SbxVARIANT ); + pPar->Put( pElem, 0 ); + pCol->CollItem( pPar ); + } + } + else if( bVBAEnabled ) // !pObj + { + SbxArray* pParam = pElem->GetParameters(); + if( pParam != NULL ) + Error( SbERR_NO_OBJECT ); + } + } + } + + return pElem; +} + +// Laden eines Elements aus der Runtime-Library (+StringID+Typ) + +void SbiRuntime::StepRTL( UINT32 nOp1, UINT32 nOp2 ) +{ + PushVar( FindElement( rBasic.pRtl, nOp1, nOp2, SbERR_PROC_UNDEFINED, FALSE ) ); +} + +void +SbiRuntime::StepFIND_Impl( SbxObject* pObj, UINT32 nOp1, UINT32 nOp2, SbError nNotFound, BOOL bLocal, BOOL bStatic ) +{ + if( !refLocals ) + refLocals = new SbxArray; + PushVar( FindElement( pObj, nOp1, nOp2, nNotFound, bLocal, bStatic ) ); +} +// Laden einer lokalen/globalen Variablen (+StringID+Typ) + +void SbiRuntime::StepFIND( UINT32 nOp1, UINT32 nOp2 ) +{ + StepFIND_Impl( pMod, nOp1, nOp2, SbERR_PROC_UNDEFINED, TRUE ); +} + +// Search inside a class module (CM) to enable global search in time +void SbiRuntime::StepFIND_CM( UINT32 nOp1, UINT32 nOp2 ) +{ + + SbClassModuleObject* pClassModuleObject = PTR_CAST(SbClassModuleObject,pMod); + if( pClassModuleObject ) + pMod->SetFlag( SBX_GBLSEARCH ); + + StepFIND_Impl( pMod, nOp1, nOp2, SbERR_PROC_UNDEFINED, TRUE ); + + if( pClassModuleObject ) + pMod->ResetFlag( SBX_GBLSEARCH ); +} + +void SbiRuntime::StepFIND_STATIC( UINT32 nOp1, UINT32 nOp2 ) +{ + StepFIND_Impl( pMod, nOp1, nOp2, SbERR_PROC_UNDEFINED, TRUE, TRUE ); +} + +// Laden eines Objekt-Elements (+StringID+Typ) +// Das Objekt liegt auf TOS + +void SbiRuntime::StepELEM( UINT32 nOp1, UINT32 nOp2 ) +{ + // Liegt auf dem TOS ein Objekt? + SbxVariableRef pObjVar = PopVar(); + + SbxObject* pObj = PTR_CAST(SbxObject,(SbxVariable*) pObjVar); + if( !pObj ) + { + SbxBase* pObjVarObj = pObjVar->GetObject(); + pObj = PTR_CAST(SbxObject,pObjVarObj); + } + + // #56368 Bei StepElem Referenz sichern, sonst koennen Objekte + // in Qualifizierungsketten wie ActiveComponent.Selection(0).Text + // zu fueh die Referenz verlieren + // #74254 Jetzt per Liste + if( pObj ) + SaveRef( (SbxVariable*)pObj ); + + PushVar( FindElement( pObj, nOp1, nOp2, SbERR_NO_METHOD, FALSE ) ); +} + +// Laden eines Parameters (+Offset+Typ) +// Wenn der Datentyp nicht stimmen sollte, eine Kopie anlegen +// Der Datentyp SbxEMPTY zeigt an, daa kein Parameter angegeben ist. +// Get( 0 ) darf EMPTY sein + +void SbiRuntime::StepPARAM( UINT32 nOp1, UINT32 nOp2 ) +{ + USHORT i = static_cast<USHORT>( nOp1 & 0x7FFF ); + SbxDataType t = (SbxDataType) nOp2; + SbxVariable* p; + + // #57915 Missing sauberer loesen + USHORT nParamCount = refParams->Count(); + if( i >= nParamCount ) + { + INT16 iLoop = i; + while( iLoop >= nParamCount ) + { + p = new SbxVariable(); + + if( SbiRuntime::isVBAEnabled() && + (t == SbxOBJECT || t == SbxSTRING) ) + { + if( t == SbxOBJECT ) + p->PutObject( NULL ); + else + p->PutString( String() ); + } + else + p->PutErr( 448 ); // Wie in VB: Error-Code 448 (SbERR_NAMED_NOT_FOUND) + + refParams->Put( p, iLoop ); + iLoop--; + } + } + p = refParams->Get( i ); + + if( p->GetType() == SbxERROR && ( i ) ) + //if( p->GetType() == SbxEMPTY && ( i ) ) + { + // Wenn ein Parameter fehlt, kann er OPTIONAL sein + BOOL bOpt = FALSE; + if( pMeth ) + { + SbxInfo* pInfo = pMeth->GetInfo(); + if ( pInfo ) + { + const SbxParamInfo* pParam = pInfo->GetParam( i ); + if( pParam && ( (pParam->nFlags & SBX_OPTIONAL) != 0 ) ) + { + // Default value? + USHORT nDefaultId = sal::static_int_cast< USHORT >( + pParam->nUserData & 0xffff ); + if( nDefaultId > 0 ) + { + String aDefaultStr = pImg->GetString( nDefaultId ); + p = new SbxVariable(); + p->PutString( aDefaultStr ); + refParams->Put( p, i ); + } + bOpt = TRUE; + } + } + } + if( bOpt == FALSE ) + Error( SbERR_NOT_OPTIONAL ); + } + else if( t != SbxVARIANT && (SbxDataType)(p->GetType() & 0x0FFF ) != t ) + { + SbxVariable* q = new SbxVariable( t ); + SaveRef( q ); + *q = *p; + p = q; + } + SetupArgs( p, nOp1 ); + PushVar( CheckArray( p ) ); +} + +// Case-Test (+True-Target+Test-Opcode) + +void SbiRuntime::StepCASEIS( UINT32 nOp1, UINT32 nOp2 ) +{ + if( !refCaseStk || !refCaseStk->Count() ) + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + else + { + SbxVariableRef xComp = PopVar(); + SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 ); + if( xCase->Compare( (SbxOperator) nOp2, *xComp ) ) + StepJUMP( nOp1 ); + } +} + +// Aufruf einer DLL-Prozedur (+StringID+Typ) +// Auch hier zeigt das MSB des StringIDs an, dass Argv belegt ist + +void SbiRuntime::StepCALL( UINT32 nOp1, UINT32 nOp2 ) +{ + String aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ); + SbxArray* pArgs = NULL; + if( nOp1 & 0x8000 ) + pArgs = refArgv; + DllCall( aName, aLibName, pArgs, (SbxDataType) nOp2, FALSE ); + aLibName = String(); + if( nOp1 & 0x8000 ) + PopArgv(); +} + +// Aufruf einer DLL-Prozedur nach CDecl (+StringID+Typ) +// Auch hier zeigt das MSB des StringIDs an, dass Argv belegt ist + +void SbiRuntime::StepCALLC( UINT32 nOp1, UINT32 nOp2 ) +{ + String aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ); + SbxArray* pArgs = NULL; + if( nOp1 & 0x8000 ) + pArgs = refArgv; + DllCall( aName, aLibName, pArgs, (SbxDataType) nOp2, TRUE ); + aLibName = String(); + if( nOp1 & 0x8000 ) + PopArgv(); +} + + +// Beginn eines Statements (+Line+Col) + +void SbiRuntime::StepSTMNT( UINT32 nOp1, UINT32 nOp2 ) +{ + // Wenn der Expr-Stack am Anfang einen Statements eine Variable enthaelt, + // hat ein Trottel X als Funktion aufgerufen, obwohl es eine Variable ist! + BOOL bFatalExpr = FALSE; + String sUnknownMethodName; + if( nExprLvl > 1 ) + bFatalExpr = TRUE; + else if( nExprLvl ) + { + SbxVariable* p = refExprStk->Get( 0 ); + if( p->GetRefCount() > 1 + && refLocals.Is() && refLocals->Find( p->GetName(), p->GetClass() ) ) + { + sUnknownMethodName = p->GetName(); + bFatalExpr = TRUE; + } + } + // Der Expr-Stack ist nun nicht mehr notwendig + ClearExprStack(); + + // #56368 Kuenstliche Referenz fuer StepElem wieder freigeben, + // damit sie nicht ueber ein Statement hinaus erhalten bleibt + //refSaveObj = NULL; + // #74254 Jetzt per Liste + ClearRefs(); + + // Wir muessen hier hart abbrechen, da sonst Zeile und Spalte nicht mehr + // stimmen! + if( bFatalExpr) + { + StarBASIC::FatalError( SbERR_NO_METHOD, sUnknownMethodName ); + return; + } + pStmnt = pCode - 9; + USHORT nOld = nLine; + nLine = static_cast<short>( nOp1 ); + + // #29955 & 0xFF, um for-Schleifen-Ebene wegzufiltern + nCol1 = static_cast<short>( nOp2 & 0xFF ); + + // Suchen des naechsten STMNT-Befehls, + // um die End-Spalte dieses Statements zu setzen + // Searches of the next STMNT instruction, + // around the final column of this statement to set + + nCol2 = 0xffff; + USHORT n1, n2; + const BYTE* p = pMod->FindNextStmnt( pCode, n1, n2 ); + if( p ) + { + if( n1 == nOp1 ) + { + // #29955 & 0xFF, um for-Schleifen-Ebene wegzufiltern + nCol2 = (n2 & 0xFF) - 1; + } + } + + // #29955 for-Schleifen-Ebene korrigieren, #67452 NICHT im Error-Handler sonst Chaos + if( !bInError ) + { + // (Bei Sprüngen aus Schleifen tritt hier eine Differenz auf) + USHORT nExspectedForLevel = static_cast<USHORT>( nOp2 / 0x100 ); + if( pGosubStk ) + nExspectedForLevel = nExspectedForLevel + pGosubStk->nStartForLvl; + + // Wenn der tatsaechliche For-Level zu klein ist, wurde aus + // einer Schleife heraus gesprungen -> korrigieren + while( nForLvl > nExspectedForLevel ) + PopFor(); + } + + // 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out + // Erklärung siehe bei _ImplGetBreakCallLevel. + if( pInst->nCallLvl <= pInst->nBreakCallLvl ) + //if( nFlags & SbDEBUG_STEPINTO ) + { + StarBASIC* pStepBasic = GetCurrentBasic( &rBasic ); + USHORT nNewFlags = pStepBasic->StepPoint( nLine, nCol1, nCol2 ); + + // Neuen BreakCallLevel ermitteln + pInst->CalcBreakCallLevel( nNewFlags ); + } + + // Breakpoints nur bei STMNT-Befehlen in neuer Zeile! + else if( ( nOp1 != nOld ) + && ( nFlags & SbDEBUG_BREAK ) + && pMod->IsBP( static_cast<USHORT>( nOp1 ) ) ) + { + StarBASIC* pBreakBasic = GetCurrentBasic( &rBasic ); + USHORT nNewFlags = pBreakBasic->BreakPoint( nLine, nCol1, nCol2 ); + + // Neuen BreakCallLevel ermitteln + pInst->CalcBreakCallLevel( nNewFlags ); + //16.10.96, ALT: + //if( nNewFlags != SbDEBUG_CONTINUE ) + // nFlags = nNewFlags; + } +} + +// (+SvStreamFlags+Flags) +// Stack: Blocklaenge +// Kanalnummer +// Dateiname + +void SbiRuntime::StepOPEN( UINT32 nOp1, UINT32 nOp2 ) +{ + SbxVariableRef pName = PopVar(); + SbxVariableRef pChan = PopVar(); + SbxVariableRef pLen = PopVar(); + short nBlkLen = pLen->GetInteger(); + short nChan = pChan->GetInteger(); + ByteString aName( pName->GetString(), gsl_getSystemTextEncoding() ); + pIosys->Open( nChan, aName, static_cast<short>( nOp1 ), + static_cast<short>( nOp2 ), nBlkLen ); + Error( pIosys->GetError() ); +} + +// Objekt kreieren (+StringID+StringID) + +void SbiRuntime::StepCREATE( UINT32 nOp1, UINT32 nOp2 ) +{ + String aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); + SbxObject *pObj = SbxBase::CreateObject( aClass ); + if( !pObj ) + Error( SbERR_INVALID_OBJECT ); + else + { + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + pObj->SetName( aName ); + // Das Objekt muss BASIC rufen koennen + pObj->SetParent( &rBasic ); + SbxVariable* pNew = new SbxVariable; + pNew->PutObject( pObj ); + PushVar( pNew ); + } +} + +void SbiRuntime::StepDCREATE( UINT32 nOp1, UINT32 nOp2 ) +{ + StepDCREATE_IMPL( nOp1, nOp2 ); +} + +void SbiRuntime::StepDCREATE_REDIMP( UINT32 nOp1, UINT32 nOp2 ) +{ + StepDCREATE_IMPL( nOp1, nOp2 ); +} + + +// Helper function for StepDCREATE_IMPL / bRedimp = true +void implCopyDimArray_DCREATE( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex, + short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds ) +{ + sal_Int32& ri = pActualIndices[nActualDim]; + for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ ) + { + if( nActualDim < nMaxDimIndex ) + { + implCopyDimArray_DCREATE( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1, + pActualIndices, pLowerBounds, pUpperBounds ); + } + else + { + SbxVariable* pSource = pOldArray->Get32( pActualIndices ); + pNewArray->Put32( pSource, pActualIndices ); + } + } +} + +// #56204 Objekt-Array kreieren (+StringID+StringID), DCREATE == Dim-Create +void SbiRuntime::StepDCREATE_IMPL( UINT32 nOp1, UINT32 nOp2 ) +{ + SbxVariableRef refVar = PopVar(); + + DimImpl( refVar ); + + // Das Array mit Instanzen der geforderten Klasse fuellen + SbxBaseRef xObj = (SbxBase*)refVar->GetObject(); + if( !xObj ) + { + StarBASIC::Error( SbERR_INVALID_OBJECT ); + return; + } + + SbxDimArray* pArray = 0; + if( xObj->ISA(SbxDimArray) ) + { + SbxBase* pObj = (SbxBase*)xObj; + pArray = (SbxDimArray*)pObj; + + // Dimensionen auswerten + short nDims = pArray->GetDims(); + INT32 nTotalSize = 0; + + // es muss ein eindimensionales Array sein + INT32 nLower, nUpper, nSize; + INT32 i; + for( i = 0 ; i < nDims ; i++ ) + { + pArray->GetDim32( i+1, nLower, nUpper ); + nSize = nUpper - nLower + 1; + if( i == 0 ) + nTotalSize = nSize; + else + nTotalSize *= nSize; + } + + // Objekte anlegen und ins Array eintragen + String aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); + for( i = 0 ; i < nTotalSize ; i++ ) + { + SbxObject *pClassObj = SbxBase::CreateObject( aClass ); + if( !pClassObj ) + { + Error( SbERR_INVALID_OBJECT ); + break; + } + else + { + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + pClassObj->SetName( aName ); + // Das Objekt muss BASIC rufen koennen + pClassObj->SetParent( &rBasic ); + pArray->SbxArray::Put32( pClassObj, i ); + } + } + } + + SbxDimArray* pOldArray = (SbxDimArray*)(SbxArray*)refRedimpArray; + if( pArray && pOldArray ) + { + short nDimsNew = pArray->GetDims(); + short nDimsOld = pOldArray->GetDims(); + short nDims = nDimsNew; + BOOL bRangeError = FALSE; + + // Store dims to use them for copying later + sal_Int32* pLowerBounds = new sal_Int32[nDims]; + sal_Int32* pUpperBounds = new sal_Int32[nDims]; + sal_Int32* pActualIndices = new sal_Int32[nDims]; + if( nDimsOld != nDimsNew ) + { + bRangeError = TRUE; + } + else + { + // Compare bounds + for( short i = 1 ; i <= nDims ; i++ ) + { + sal_Int32 lBoundNew, uBoundNew; + sal_Int32 lBoundOld, uBoundOld; + pArray->GetDim32( i, lBoundNew, uBoundNew ); + pOldArray->GetDim32( i, lBoundOld, uBoundOld ); + + lBoundNew = std::max( lBoundNew, lBoundOld ); + uBoundNew = std::min( uBoundNew, uBoundOld ); + short j = i - 1; + pActualIndices[j] = pLowerBounds[j] = lBoundNew; + pUpperBounds[j] = uBoundNew; + } + } + + if( bRangeError ) + { + StarBASIC::Error( SbERR_OUT_OF_RANGE ); + } + else + { + // Copy data from old array by going recursively through all dimensions + // (It would be faster to work on the flat internal data array of an + // SbyArray but this solution is clearer and easier) + implCopyDimArray_DCREATE( pArray, pOldArray, nDims - 1, + 0, pActualIndices, pLowerBounds, pUpperBounds ); + } + delete [] pUpperBounds; + delete [] pLowerBounds; + delete [] pActualIndices; + refRedimpArray = NULL; + } +} + +// Objekt aus User-Type kreieren (+StringID+StringID) + +SbxObject* createUserTypeImpl( const String& rClassName ); // sb.cxx + +void SbiRuntime::StepTCREATE( UINT32 nOp1, UINT32 nOp2 ) +{ + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + String aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); + + SbxObject* pCopyObj = createUserTypeImpl( aClass ); + if( pCopyObj ) + pCopyObj->SetName( aName ); + SbxVariable* pNew = new SbxVariable; + pNew->PutObject( pCopyObj ); + pNew->SetDeclareClassName( aClass ); + PushVar( pNew ); +} + +void SbiRuntime::implHandleSbxFlags( SbxVariable* pVar, SbxDataType t, UINT32 nOp2 ) +{ + bool bWithEvents = ((t & 0xff) == SbxOBJECT && (nOp2 & SBX_TYPE_WITH_EVENTS_FLAG) != 0); + if( bWithEvents ) + pVar->SetFlag( SBX_WITH_EVENTS ); + + bool bDimAsNew = ((nOp2 & SBX_TYPE_DIM_AS_NEW_FLAG) != 0); + if( bDimAsNew ) + pVar->SetFlag( SBX_DIM_AS_NEW ); + + bool bFixedString = ((t & 0xff) == SbxSTRING && (nOp2 & SBX_FIXED_LEN_STRING_FLAG) != 0); + if( bFixedString ) + { + USHORT nCount = static_cast<USHORT>( nOp2 >> 17 ); // len = all bits above 0x10000 + String aStr; + aStr.Fill( nCount, 0 ); + pVar->PutString( aStr ); + } +} + +// Einrichten einer lokalen Variablen (+StringID+Typ) + +void SbiRuntime::StepLOCAL( UINT32 nOp1, UINT32 nOp2 ) +{ + if( !refLocals.Is() ) + refLocals = new SbxArray; + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + if( refLocals->Find( aName, SbxCLASS_DONTCARE ) == NULL ) + { + SbxDataType t = (SbxDataType)(nOp2 & 0xffff); + SbxVariable* p = new SbxVariable( t ); + p->SetName( aName ); + implHandleSbxFlags( p, t, nOp2 ); + refLocals->Put( p, refLocals->Count() ); + } +} + +// Einrichten einer modulglobalen Variablen (+StringID+Typ) + +void SbiRuntime::StepPUBLIC_Impl( UINT32 nOp1, UINT32 nOp2, bool bUsedForClassModule ) +{ + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + SbxDataType t = (SbxDataType)(SbxDataType)(nOp2 & 0xffff);; + BOOL bFlag = pMod->IsSet( SBX_NO_MODIFY ); + pMod->SetFlag( SBX_NO_MODIFY ); + SbxVariableRef p = pMod->Find( aName, SbxCLASS_PROPERTY ); + if( p.Is() ) + pMod->Remove (p); + SbProperty* pProp = pMod->GetProperty( aName, t ); + if( !bUsedForClassModule ) + pProp->SetFlag( SBX_PRIVATE ); + if( !bFlag ) + pMod->ResetFlag( SBX_NO_MODIFY ); + if( pProp ) + { + pProp->SetFlag( SBX_DONTSTORE ); + // AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden' + pProp->SetFlag( SBX_NO_MODIFY); + + implHandleSbxFlags( pProp, t, nOp2 ); + } +} + +void SbiRuntime::StepPUBLIC( UINT32 nOp1, UINT32 nOp2 ) +{ + StepPUBLIC_Impl( nOp1, nOp2, false ); +} + +void SbiRuntime::StepPUBLIC_P( UINT32 nOp1, UINT32 nOp2 ) +{ + // Creates module variable that isn't reinitialised when + // between invocations ( for VBASupport & document basic only ) + if( pMod->pImage->bFirstInit ) + { + bool bUsedForClassModule = pImg->GetFlag( SBIMG_CLASSMODULE ); + StepPUBLIC_Impl( nOp1, nOp2, bUsedForClassModule ); + } +} + +// Einrichten einer globalen Variablen (+StringID+Typ) + +void SbiRuntime::StepGLOBAL( UINT32 nOp1, UINT32 nOp2 ) +{ + if( pImg->GetFlag( SBIMG_CLASSMODULE ) ) + StepPUBLIC_Impl( nOp1, nOp2, true ); + + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + SbxDataType t = (SbxDataType)(nOp2 & 0xffff); + + // Store module scope variables at module scope + // in non vba mode these are stored at the library level :/ + // not sure if this really should not be enabled for ALL basic + SbxObject* pStorage = &rBasic; + if ( SbiRuntime::isVBAEnabled() ) + { + pStorage = pMod; + pMod->AddVarName( aName ); + } + + BOOL bFlag = pStorage->IsSet( SBX_NO_MODIFY ); + rBasic.SetFlag( SBX_NO_MODIFY ); + SbxVariableRef p = pStorage->Find( aName, SbxCLASS_PROPERTY ); + if( p.Is() ) + pStorage->Remove (p); + p = pStorage->Make( aName, SbxCLASS_PROPERTY, t ); + if( !bFlag ) + pStorage->ResetFlag( SBX_NO_MODIFY ); + if( p ) + { + p->SetFlag( SBX_DONTSTORE ); + // AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden' + p->SetFlag( SBX_NO_MODIFY); + } +} + + +// Creates global variable that isn't reinitialised when +// basic is restarted, P=PERSIST (+StringID+Typ) + +void SbiRuntime::StepGLOBAL_P( UINT32 nOp1, UINT32 nOp2 ) +{ + if( pMod->pImage->bFirstInit ) + { + StepGLOBAL( nOp1, nOp2 ); + } +} + + +// Searches for global variable, behavior depends on the fact +// if the variable is initialised for the first time + +void SbiRuntime::StepFIND_G( UINT32 nOp1, UINT32 nOp2 ) +{ + if( pMod->pImage->bFirstInit ) + { + // Behave like always during first init + StepFIND( nOp1, nOp2 ); + } + else + { + // Return dummy variable + SbxDataType t = (SbxDataType) nOp2; + String aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) ); + + SbxVariable* pDummyVar = new SbxVariable( t ); + pDummyVar->SetName( aName ); + PushVar( pDummyVar ); + } +} + + +SbxVariable* SbiRuntime::StepSTATIC_Impl( String& aName, SbxDataType& t ) +{ + SbxVariable* p = NULL; + if ( pMeth ) + { + SbxArray* pStatics = pMeth->GetStatics(); + if( pStatics && ( pStatics->Find( aName, SbxCLASS_DONTCARE ) == NULL ) ) + { + p = new SbxVariable( t ); + if( t != SbxVARIANT ) + p->SetFlag( SBX_FIXED ); + p->SetName( aName ); + pStatics->Put( p, pStatics->Count() ); + } + } + return p; +} +// Einrichten einer statischen Variablen (+StringID+Typ) +void SbiRuntime::StepSTATIC( UINT32 nOp1, UINT32 nOp2 ) +{ + String aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); + SbxDataType t = (SbxDataType) nOp2; + StepSTATIC_Impl( aName, t ); +} + diff --git a/basic/source/runtime/wnt-mingw.s b/basic/source/runtime/wnt-mingw.s new file mode 100644 index 000000000000..8c332c1a8ce8 --- /dev/null +++ b/basic/source/runtime/wnt-mingw.s @@ -0,0 +1,53 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#***********************************************************************/ + +.intel_syntax + +.globl _DllMgr_call32 +.globl _DllMgr_callFp + +_DllMgr_call32: +_DllMgr_callFp: + push ebp + mov ebp, esp + push esi + push edi + mov ecx, [ebp+16] + jecxz $1 + sub esp, ecx + mov edi, esp + mov esi, [ebp+12] + shr ecx, 2 + rep movsd +$1: call DWORD PTR [ebp+8] + # for extra safety, do not trust esp after call (in case the Basic Declare + # signature is wrong): + mov edi, [ebp-8] + mov esi, [ebp-4] + mov esp, ebp + pop ebp + ret 12 diff --git a/basic/source/runtime/wnt.asm b/basic/source/runtime/wnt.asm new file mode 100644 index 000000000000..2a8710e34243 --- /dev/null +++ b/basic/source/runtime/wnt.asm @@ -0,0 +1,56 @@ +;************************************************************************* +; +; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +; +; Copyright 2000, 2010 Oracle and/or its affiliates. +; +; OpenOffice.org - a multi-platform office productivity suite +; +; This file is part of OpenOffice.org. +; +; OpenOffice.org is free software: you can redistribute it and/or modify +; it under the terms of the GNU Lesser General Public License version 3 +; only, as published by the Free Software Foundation. +; +; OpenOffice.org is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU Lesser General Public License version 3 for more details +; (a copy is included in the LICENSE file that accompanied this code). +; +; You should have received a copy of the GNU Lesser General Public License +; version 3 along with OpenOffice.org. If not, see +; <http://www.openoffice.org/license.html> +; for a copy of the LGPLv3 License. +; +;***********************************************************************/ + +.386 + +PUBLIC _DllMgr_call32@12 +PUBLIC _DllMgr_callFp@12 + +_TEXT SEGMENT +_DllMgr_call32@12: +_DllMgr_callFp@12: + push ebp + mov ebp, esp + push esi + push edi + mov ecx, [ebp+16] + jecxz $1 + sub esp, ecx + mov edi, esp + mov esi, [ebp+12] + shr ecx, 2 + rep movsd +$1: call DWORD PTR [ebp+8] + ; for extra safety, do not trust esp after call (in case the Basic Declare + ; signature is wrong): + mov edi, [ebp-8] + mov esi, [ebp-4] + mov esp, ebp + pop ebp + ret 12 +_TEXT ENDS +END |