Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/basic/source/classes/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 80 kB image not shown  

Quelle  sbxmod.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */



#include <utility>
#include <vcl/svapp.hxx>
#include <tools/stream.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <svl/SfxBroadcaster.hxx>
#include <basic/codecompletecache.hxx>
#include <basic/sbx.hxx>
#include <basic/sbuno.hxx>
#include <sbjsmeth.hxx>
#include <sbjsmod.hxx>
#include <sbintern.hxx>
#include <sbprop.hxx>
#include <image.hxx>
#include <opcodes.hxx>
#include <runtime.hxx>
#include <token.hxx>
#include <sbunoobj.hxx>

#include <sal/log.hxx>

#include <basic/sberrors.hxx>
#include <sbobjmod.hxx>
#include <basic/vbahelper.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/implbase.hxx>
#include <unotools/eventcfg.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/script/ModuleType.hpp>
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
#include <com/sun/star/script/vba/VBAScriptEventId.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
#include <com/sun/star/document/XDocumentEventListener.hpp>

#ifdef UNX
#include <sys/resource.h>
#endif

#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/asyncquithandler.hxx>
#include <map>
#include <com/sun/star/reflection/ProxyFactory.hpp>
#include <com/sun/star/uno/XAggregation.hpp>
#include <com/sun/star/script/XInvocation.hpp>

#include <com/sun/star/awt/DialogProvider.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/awt/XWindow.hpp>
#include <ooo/vba/VbQueryClose.hpp>
#include <memory>
#include <sbxmod.hxx>
#include <parser.hxx>

#include <limits>

using namespace com::sun::star;
using namespace com::sun::star::lang;
using namespace com::sun::star::reflection;
using namespace com::sun::star::beans;
using namespace com::sun::star::script;
using namespace com::sun::star::uno;

typedef ::cppu::WeakImplHelper< XInvocation > DocObjectWrapper_BASE;
typedef std::map< sal_Int16, Any > OutParamMap;

namespace {

class DocObjectWrapper : public DocObjectWrapper_BASE
{
    Reference< XAggregation >  m_xAggProxy;
    Reference< XInvocation >  m_xAggInv;
    Reference< XTypeProvider > m_xAggregateTypeProv;
    Sequence< Type >           m_Types;
    SbModule*                m_pMod;
    /// @throws css::uno::RuntimeException
    SbMethodRef getMethod( const OUString& aName );
    /// @throws css::uno::RuntimeException
    SbPropertyRef getProperty( const OUString& aName );

public:
    explicit DocObjectWrapper( SbModule* pMod );

    virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override
    {
        return css::uno::Sequence<sal_Int8>();
    }

    virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection(  ) override;

    virtual Any SAL_CALL invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) override;
    virtual void SAL_CALL setValue( const OUString& aPropertyName, const Any& aValue ) override;
    virtual Any SAL_CALL getValue( const OUString& aPropertyName ) override;
    virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override;
    virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override;
    virtual  Any SAL_CALL queryInterface( const Type& aType ) override;

    virtual Sequence< Type > SAL_CALL getTypes() override;
};

}

DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar )
{
    SbObjModule* pMod = dynamic_cast<SbObjModule*>( pVar );
    if ( !pMod )
        return;

    if ( pMod->GetModuleType() != ModuleType::DOCUMENT )
        return;

    // Use proxy factory service to create aggregatable proxy.
    SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pMod->GetObject()  );
    Reference< XInterface > xIf;
    if ( pUnoObj )
    {
           Any aObj = pUnoObj->getUnoAny();
           aObj >>= xIf;
           if ( xIf.is() )
           {
               m_xAggregateTypeProv.set( xIf, UNO_QUERY );
               m_xAggInv.set( xIf, UNO_QUERY );
           }
    }
    if ( xIf.is() )
    {
        try
        {
            Reference< XProxyFactory > xProxyFac = ProxyFactory::create( comphelper::getProcessComponentContext() );
            m_xAggProxy = xProxyFac->createProxy( xIf );
        }
        catch(const Exception& )
        {
            TOOLS_WARN_EXCEPTION( "basic""DocObjectWrapper::DocObjectWrapper" );
        }
    }

    if ( !m_xAggProxy.is() )
        return;

    osl_atomic_increment( &m_refCount );

    /* i35609 - Fix crash on Solaris. The setDelegator call needs
        to be in its own block to ensure that all temporary Reference
        instances that are acquired during the call are released
        before m_refCount is decremented again */

    {
        m_xAggProxy->setDelegator( getXWeak() );
    }

    osl_atomic_decrement( &m_refCount );
}

Sequence< Type > SAL_CALL DocObjectWrapper::getTypes()
{
    if ( !m_Types.hasElements() )
    {
        Sequence< Type > sTypes;
        if ( m_xAggregateTypeProv.is() )
        {
            sTypes = m_xAggregateTypeProv->getTypes();
        }
        m_Types = comphelper::concatSequences(sTypes,
            Sequence { cppu::UnoType<XInvocation>::get() });
    }
    return m_Types;
}

Reference< XIntrospectionAccess > SAL_CALL
DocObjectWrapper::getIntrospection(  )
{
    return nullptr;
}

Any SAL_CALL
DocObjectWrapper::invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
{
    if ( m_xAggInv.is() &&  m_xAggInv->hasMethod( aFunctionName ) )
            return m_xAggInv->invoke( aFunctionName, aParams, aOutParamIndex, aOutParam );
    SbMethodRef pMethod = getMethod( aFunctionName );
    if ( !pMethod.is() )
        throw RuntimeException(u"DocObjectWrapper::invoke - Could not get the method reference!"_ustr);
    // check number of parameters
    sal_Int32 nParamsCount = aParams.getLength();
    SbxInfo* pInfo = pMethod->GetInfo();
    if ( pInfo )
    {
        sal_Int32 nSbxOptional = 0;
        sal_uInt16 n = 1;
        for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
        {
            if ( pParamInfo->nFlags & SbxFlagBits::Optional )
                ++nSbxOptional;
            else
                nSbxOptional = 0;
        }
        sal_Int32 nSbxCount = n - 1;
        if ( nParamsCount < nSbxCount - nSbxOptional )
        {
            throw RuntimeException( u"wrong number of parameters!"_ustr );
        }
    }
    // set parameters
    SbxArrayRef xSbxParams;
    if ( nParamsCount > 0 )
    {
        xSbxParams = new SbxArray;
        const Any* pParams = aParams.getConstArray();
        for ( sal_Int32 i = 0; i < nParamsCount; ++i )
        {
            SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
            unoToSbxValue( xSbxVar.get(), pParams[i] );
            xSbxParams->Put(xSbxVar.get(), static_cast<sal_uInt32>(i) + 1);

            // Enable passing by ref
            if ( xSbxVar->GetType() != SbxVARIANT )
                xSbxVar->SetFlag( SbxFlagBits::Fixed );
        }
    }
    if ( xSbxParams.is() )
        pMethod->SetParameters( xSbxParams.get() );

    // call method
    SbxVariableRef xReturn = new SbxVariable;

    pMethod->Call( xReturn.get() );
    Any aReturn;
    // get output parameters
    if ( xSbxParams.is() )
    {
        SbxInfo* pInfo_ = pMethod->GetInfo();
        if ( pInfo_ )
        {
            OutParamMap aOutParamMap;
            for (sal_uInt32 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n)
            {
                assert(n <= std::numeric_limits<sal_uInt16>::max());
                const SbxParamInfo* pParamInfo = pInfo_->GetParam( sal::static_int_cast<sal_uInt16>(n) );
                if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
                {
                    SbxVariable* pVar = xSbxParams->Get(n);
                    if ( pVar )
                    {
                        SbxVariableRef xVar = pVar;
                        aOutParamMap.emplace( n - 1, sbxToUnoValue( xVar.get() ) );
                    }
                }
            }
            sal_Int32 nOutParamCount = aOutParamMap.size();
            aOutParamIndex.realloc( nOutParamCount );
            aOutParam.realloc( nOutParamCount );
            sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
            Any* pOutParam = aOutParam.getArray();
            for (auto const& outParam : aOutParamMap)
            {
                *pOutParamIndex = outParam.first;
                *pOutParam = outParam.second;
                ++pOutParamIndex;
                ++pOutParam;
            }
        }
    }

    // get return value
    aReturn = sbxToUnoValue( xReturn.get() );

    pMethod->SetParameters( nullptr );

    return aReturn;
}

void SAL_CALL
DocObjectWrapper::setValue( const OUString& aPropertyName, const Any& aValue )
{
    if ( m_xAggInv.is() &&  m_xAggInv->hasProperty( aPropertyName ) )
            return m_xAggInv->setValue( aPropertyName, aValue );

    SbPropertyRef pProperty = getProperty( aPropertyName );
    if ( !pProperty.is() )
       throw UnknownPropertyException(aPropertyName);
    unoToSbxValue( pProperty.get(), aValue );
}

Any SAL_CALL
DocObjectWrapper::getValue( const OUString& aPropertyName )
{
    if ( m_xAggInv.is() &&  m_xAggInv->hasProperty( aPropertyName ) )
            return m_xAggInv->getValue( aPropertyName );

    SbPropertyRef pProperty = getProperty( aPropertyName );
    if ( !pProperty.is() )
       throw UnknownPropertyException(aPropertyName);

    SbxVariable* pProp = pProperty.get();
    if ( pProp->GetType() == SbxEMPTY )
        pProperty->Broadcast( SfxHintId::BasicDataWanted );

    Any aRet = sbxToUnoValue( pProp );
    return aRet;
}

sal_Bool SAL_CALL
DocObjectWrapper::hasMethod( const OUString& aName )
{
    if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) )
        return true;
    return getMethod( aName ).is();
}

sal_Bool SAL_CALL
DocObjectWrapper::hasProperty( const OUString& aName )
{
    bool bRes = false;
    if ( m_xAggInv.is() && m_xAggInv->hasProperty( aName ) )
        bRes = true;
    else bRes = getProperty( aName ).is();
    return bRes;
}

Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType )
{
    Any aRet = DocObjectWrapper_BASE::queryInterface( aType );
    if ( aRet.hasValue() )
        return aRet;
    else if ( m_xAggProxy.is() )
        aRet = m_xAggProxy->queryAggregation( aType );
    return aRet;
}

SbMethodRef DocObjectWrapper::getMethod( const OUString& aName )
{
    SbMethodRef pMethod;
    if ( m_pMod )
    {
        SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
        // Limit search to this module
        m_pMod->ResetFlag( SbxFlagBits::GlobalSearch );
        pMethod = dynamic_cast<SbMethod*>(m_pMod->SbModule::Find(aName,  SbxClassType::Method));
        m_pMod->SetFlags( nSaveFlgs );
    }

    return pMethod;
}

SbPropertyRef DocObjectWrapper::getProperty( const OUString& aName )
{
    SbPropertyRef pProperty;
    if ( m_pMod )
    {
        SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
        // Limit search to this module.
        m_pMod->ResetFlag( SbxFlagBits::GlobalSearch );
        pProperty = dynamic_cast<SbProperty*>(m_pMod->SbModule::Find(aName,  SbxClassType::Property));
        m_pMod->SetFlag( nSaveFlgs );
    }

    return pProperty;
}


uno::Reference< frame::XModel > getDocumentModel( StarBASIC* pb )
{
    uno::Reference< frame::XModel > xModel;
    if( pb && pb->IsDocBasic() )
    {
        uno::Any aDoc;
        if( pb->GetUNOConstant( u"ThisComponent"_ustr, aDoc ) )
            xModel.set( aDoc, uno::UNO_QUERY );
    }
    return xModel;
}

static uno::Reference< vba::XVBACompatibility > getVBACompatibility( const uno::Reference< frame::XModel >& rxModel )
{
    uno::Reference< vba::XVBACompatibility > xVBACompat;
    try
    {
        uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW );
        xVBACompat.set( xModelProps->getPropertyValue( u"BasicLibraries"_ustr ), uno::UNO_QUERY );
    }
    catch(const uno::Exception& )
    {
    }
    return xVBACompat;
}

static bool getDefaultVBAMode( StarBASIC* pb )
{
    uno::Reference< frame::XModel > xModel( getDocumentModel( pb ) );
    if (!xModel.is())
        return false;
    uno::Reference< vba::XVBACompatibility > xVBACompat = getVBACompatibility( xModel );
    return xVBACompat.is() && xVBACompat->getVBACompatibilityMode();
}

// A Basic module has set EXTSEARCH, so that the elements, that the module contains,
// could be found from other module.

SbModule::SbModule( const OUString& rName, bool bVBASupport )
    : SbxObject( u"StarBASICModule"_ustr )
    , mbVBASupport(bVBASupport), mbCompat(bVBASupport)
{
    SetName( rName );
    SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
    SetModuleType( script::ModuleType::NORMAL );

    // #i92642: Set name property to initial name
    SbxVariable* pNameProp = pProps->Find( u"Name"_ustr, SbxClassType::Property );
    if( pNameProp != nullptr )
    {
        pNameProp->PutString( GetName() );
    }
}

SbModule::~SbModule()
{
    SAL_INFO("basic","Module named " << GetName() << " is destructing");
    pImage.reset();
    pBreaks.reset();
    pClassData.reset();
    mxWrapper = nullptr;
}

uno::Reference< script::XInvocation > const &
SbModule::GetUnoModule()
{
    if ( !mxWrapper.is() )
        mxWrapper = new DocObjectWrapper( this );

    SAL_INFO("basic","Module named " << GetName() << " returning wrapper mxWrapper (0x" << mxWrapper.get() <<")" );
    return mxWrapper;
}

bool SbModule::IsCompiled() const
{
    return pImage != nullptr;
}

const SbxObject* SbModule::FindType( const OUString& aTypeName ) const
{
    return pImage ? pImage->FindType( aTypeName ) : nullptr;
}


// From the code generator: deletion of images and the opposite of validation for entries

void SbModule::StartDefinitions()
{
    pImage.reset();
    if( pClassData )
        pClassData->clear();

    // methods and properties persist, but they are invalid;
    // at least are the information under certain conditions clogged
    sal_uInt32 i;
    for (i = 0; i < pMethods->Count(); i++)
    {
        SbMethod* p = dynamic_cast<SbMethod*>(pMethods->Get(i));
        if( p )
            p->bInvalid = true;
    }
    for (i = 0; i < pProps->Count();)
    {
        SbProperty* p = dynamic_cast<SbProperty*>(pProps->Get(i));
        if( p )
            pProps->Remove( i );
        else
            i++;
    }
}

// request/create method

SbMethod* SbModule::GetMethod( const OUString& rName, SbxDataType t )
{
    SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
    SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
    if( p && !pMeth )
    {
        pMethods->Remove( p );
    }
    if( !pMeth )
    {
        pMeth = new SbMethod( rName, t, this );
        pMeth->SetParent( this );
        pMeth->SetFlags( SbxFlagBits::Read );
        pMethods->Put(pMeth, pMethods->Count());
        StartListening(pMeth->GetBroadcaster(), DuplicateHandling::Prevent);
    }
    // The method is per default valid, because it could be
    // created from the compiler (code generator) as well.
    pMeth->bInvalid = false;
    pMeth->ResetFlag( SbxFlagBits::Fixed );
    pMeth->SetFlag( SbxFlagBits::Write );
    pMeth->SetType( t );
    pMeth->ResetFlag( SbxFlagBits::Write );
    if( t != SbxVARIANT )
    {
        pMeth->SetFlag( SbxFlagBits::Fixed );
    }
    return pMeth;
}

SbMethod* SbModule::FindMethod( const OUString& rName, SbxClassType t )
{
    return dynamic_cast<SbMethod*> (pMethods->Find( rName, t ));
}


// request/create property

SbProperty* SbModule::GetProperty( const OUString& rName, SbxDataType t )
{
    SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
    SbProperty* pProp = dynamic_cast<SbProperty*>( p );
    if( p && !pProp )
    {
        pProps->Remove( p );
    }
    if( !pProp )
    {
        pProp = new SbProperty( rName, t, this );
        pProp->SetFlag( SbxFlagBits::ReadWrite );
        pProp->SetParent( this );
        pProps->Put(pProp, pProps->Count());
        StartListening(pProp->GetBroadcaster(), DuplicateHandling::Prevent);
    }
    return pProp;
}

void SbModule::GetProcedureProperty( const OUString& rName, SbxDataType t )
{
    SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
    SbProcedureProperty* pProp = dynamic_cast<SbProcedureProperty*>( p );
    if( p && !pProp )
    {
        pProps->Remove( p );
    }
    if( !pProp )
    {
        tools::SvRef<SbProcedureProperty> pNewProp = new SbProcedureProperty( rName, t );
        pNewProp->SetFlag( SbxFlagBits::ReadWrite );
        pNewProp->SetParent( this );
        pProps->Put(pNewProp.get(), pProps->Count());
        StartListening(pNewProp->GetBroadcaster(), DuplicateHandling::Prevent);
    }
}

void SbModule::GetIfaceMapperMethod( const OUString& rName, SbMethod* pImplMeth )
{
    SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
    SbIfaceMapperMethod* pMapperMethod = dynamic_cast<SbIfaceMapperMethod*>( p );
    if( p && !pMapperMethod )
    {
        pMethods->Remove( p );
    }
    if( !pMapperMethod )
    {
        pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth );
        pMapperMethod->SetParent( this );
        pMapperMethod->SetFlags( SbxFlagBits::Read );
        pMethods->Put(pMapperMethod, pMethods->Count());
    }
    pMapperMethod->bInvalid = false;
}

SbIfaceMapperMethod::~SbIfaceMapperMethod()
{
}


// From the code generator: remove invalid entries

void SbModule::EndDefinitions( bool bNewState )
{
    for (sal_uInt32 i = 0; i < pMethods->Count();)
    {
        SbMethod* p = dynamic_cast<SbMethod*>(pMethods->Get(i));
        if( p )
        {
            if( p->bInvalid )
            {
                pMethods->Remove( p );
            }
            else
            {
                p->bInvalid = bNewState;
                i++;
            }
        }
        else
            i++;
    }
    SetModified( true );
}

void SbModule::Clear()
{
    pImage.reset();
    if( pClassData )
        pClassData->clear();
    SbxObject::Clear();
}


SbxVariable* SbModule::Find( const OUString& rName, SbxClassType t )
{
    // make sure a search in an uninstantiated class module will fail
    if (isClassModule() && !GetSbData()->bRunInit)
    {
        return nullptr;
    }
    SbxVariable* pRes = SbxObject::Find( rName, t );
    if( !pRes && pImage )
    {
        SbiInstance* pInst = GetSbData()->pInst;
        if( pInst && pInst->IsCompatibility() )
        {
            // Put enum types as objects into module,
            // allows MyEnum.First notation
            SbxArrayRef xArray = pImage->GetEnums();
            if( xArray.is() )
            {
                SbxVariable* pEnumVar = xArray->Find( rName, SbxClassType::DontCare );
                SbxObject* pEnumObject = dynamic_cast<SbxObject*>( pEnumVar  );
                if( pEnumObject )
                {
                    bool bPrivate = pEnumObject->IsSet( SbxFlagBits::Private );
                    OUString aEnumName = pEnumObject->GetName();

                    pRes = new SbxVariable( SbxOBJECT );
                    pRes->SetName( aEnumName );
                    pRes->SetParent( this );
                    pRes->SetFlag( SbxFlagBits::Read );
                    if( bPrivate )
                    {
                        pRes->SetFlag( SbxFlagBits::Private );
                    }
                    pRes->PutObject( pEnumObject );
                }
            }
        }
    }
    return pRes;
}

// Parent and BASIC are one!

void SbModule::SetParent( SbxObject* p )
{
    pParent = p;
}

void SbModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
    if( !pHint )
        return;

    SbxVariable* pVar = pHint->GetVar();
    SbProperty* pProp = dynamic_cast<SbProperty*>( pVar );
    SbMethod* pMeth = dynamic_cast<SbMethod*>( pVar );
    SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar  );
    if( pProcProperty )
    {

        if( pHint->GetId() == SfxHintId::BasicDataWanted )
        {
            OUString aProcName = "Property Get "
                               + pProcProperty->GetName();

            SbxVariable* pMethVar = Find( aProcName, SbxClassType::Method );
            if( pMethVar )
            {
                SbxValues aVals;
                aVals.eType = SbxVARIANT;

                SbxArray* pArg = pVar->GetParameters();
                sal_uInt32 nVarParCount = (pArg != nullptr) ? pArg->Count() : 0;
                if( nVarParCount > 1 )
                {
                    auto xMethParameters = tools::make_ref<SbxArray>();
                    xMethParameters->Put(pMethVar, 0); // Method as parameter 0
                    for( sal_uInt32 i = 1 ; i < nVarParCount ; ++i )
                    {
                        SbxVariable* pPar = pArg->Get(i);
                        xMethParameters->Put(pPar, i);
                    }

                    pMethVar->SetParameters( xMethParameters.get() );
                    pMethVar->Get( aVals );
                    pMethVar->SetParameters( nullptr );
                }
                else
                {
                    pMethVar->Get( aVals );
                }

                pVar->Put( aVals );
            }
        }
        else if( pHint->GetId() == SfxHintId::BasicDataChanged )
        {
            SbxVariable* pMethVar = nullptr;

            bool bSet = pProcProperty->isSet();
            if( bSet )
            {
                pProcProperty->setSet( false );

                OUString aProcName = "Property Set "
                                   + pProcProperty->GetName();
                pMethVar = Find( aProcName, SbxClassType::Method );
            }
            if( !pMethVar ) // Let
            {
                OUString aProcName = "Property Let "
                                   + pProcProperty->GetName();
                pMethVar = Find( aProcName, SbxClassType::Method );
            }

            if( pMethVar )
            {
                // Setup parameters
                SbxArrayRef xArray = new SbxArray;
                xArray->Put(pMethVar, 0); // Method as parameter 0
                xArray->Put(pVar, 1);
                pMethVar->SetParameters( xArray.get() );

                SbxValues aVals;
                pMethVar->Get( aVals );
                pMethVar->SetParameters( nullptr );
            }
        }
    }
    if( pProp )
    {
        if( pProp->GetModule() != this )
            SetError( ERRCODE_BASIC_BAD_ACTION );
    }
    else if( pMeth )
    {
        if( pHint->GetId() == SfxHintId::BasicDataWanted )
        {
            if( pMeth->bInvalid && !Compile() )
            {
                // auto compile has not worked!
                StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );
            }
            else
            {
                // Call of a subprogram
                SbModule* pOld = GetSbData()->pMod;
                GetSbData()->pMod = this;
                Run( static_cast<SbMethod*>(pVar) );
                GetSbData()->pMod = pOld;
            }
        }
    }
    else
    {
        // #i92642: Special handling for name property to avoid
        // side effects when using name as variable implicitly
        bool bForwardToSbxObject = true;

        const SfxHintId nId = pHint->GetId();
        if( (nId == SfxHintId::BasicDataWanted || nId == SfxHintId::BasicDataChanged) &&
            pVar->GetName().equalsIgnoreAsciiCase( "name" ) )
        {
                bForwardToSbxObject = false;
        }
        if( bForwardToSbxObject )
        {
            SbxObject::Notify( rBC, rHint );
        }
    }
}

// The setting of the source makes the image invalid
// and scans the method definitions newly in

void SbModule::SetSource32( const OUString& r )
{
    // Default basic mode to library container mode, but... allow Option VBASupport 0/1 override
    SetVBASupport( getDefaultVBAMode( static_cast< StarBASIC*>( GetParent() ) ) );
    aOUSource = r;
    StartDefinitions();
    SbiTokenizer aTok( r );
    aTok.SetCompatible( IsVBASupport() );

    while( !aTok.IsEof() )
    {
        SbiToken eEndTok = NIL;

        // Searching for SUB or FUNCTION
        SbiToken eLastTok = NIL;
        while( !aTok.IsEof() )
        {
            // #32385: not by declare
            SbiToken eCurTok = aTok.Next();
            if( eLastTok != DECLARE )
            {
                if( eCurTok == SUB )
                {
                    eEndTok = ENDSUB; break;
                }
                if( eCurTok == FUNCTION )
                {
                    eEndTok = ENDFUNC; break;
                }
                if( eCurTok == PROPERTY )
                {
                    eEndTok = ENDPROPERTY; break;
                }
                if( eCurTok == OPTION )
                {
                    eCurTok = aTok.Next();
                    if( eCurTok == COMPATIBLE )
                    {
                        mbCompat = true;
                        aTok.SetCompatible( true );
                    }
                    else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) )
                    {
                        bool bIsVBA = ( aTok.GetDbl()== 1 );
                        SetVBASupport( bIsVBA );
                        aTok.SetCompatible( bIsVBA );
                    }
                    else if (eCurTok == CLASSMODULE)
                    {
                        SetModuleType(css::script::ModuleType::CLASS);
                    }
                }
            }
            eLastTok = eCurTok;
        }
        // Definition of the method
        SbMethod* pMeth = nullptr;
        if( eEndTok != NIL )
        {
            sal_uInt16 nLine1 = aTok.GetLine();
            if( aTok.Next() == SYMBOL )
            {
                const OUString& rName_( aTok.GetSym() );
                SbxDataType t = aTok.GetType();
                if( t == SbxVARIANT && eEndTok == ENDSUB )
                {
                    t = SbxVOID;
                }
                pMeth = GetMethod( rName_, t );
                pMeth->nLine1 = pMeth->nLine2 = nLine1;
                // The method is for a start VALID
                pMeth->bInvalid = false;
            }
            else
            {
                eEndTok = NIL;
            }
        }
        // Skip up to END SUB/END FUNCTION
        if( eEndTok != NIL )
        {
            while( !aTok.IsEof() )
            {
                if( aTok.Next() == eEndTok )
                {
                    pMeth->nLine2 = aTok.GetLine();
                    break;
                }
            }
            if( aTok.IsEof() )
            {
                pMeth->nLine2 = aTok.GetLine();
            }
        }
    }
    EndDefinitions( true );
}

// Broadcast of a hint to all Basics

static void SendHint_( SbxObject* pObj, SfxHintId nId, SbMethod* p )
{
    // Self a BASIC?
    ifdynamic_cast<const StarBASIC *>(pObj) != nullptr && pObj->IsBroadcaster() )
        pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) );
    // Then ask for the subobjects
    SbxArray* pObjs = pObj->GetObjects();
    for (sal_uInt32 i = 0; i < pObjs->Count(); i++)
    {
        SbxVariable* pVar = pObjs->Get(i);
        ifdynamic_cast<const SbxObject *>(pVar) != nullptr )
            SendHint_( dynamic_cast<SbxObject*>( pVar), nId, p  );
    }
}

static void SendHint( SbxObject* pObj, SfxHintId nId, SbMethod* p )
{
    while( pObj->GetParent() )
        pObj = pObj->GetParent();
    SendHint_( pObj, nId, p );
}

// #57841 Clear Uno-Objects, which were held in RTL functions,
// at the end of the program, so that nothing is held
static void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic )
{
    // delete the return value of CreateUnoService
    SbxVariable* pVar = pBasic->GetRtl()->Find( u"CreateUnoService"_ustr, SbxClassType::Method );
    if( pVar )
    {
        pVar->SbxValue::Clear();
    }
    // delete the return value of CreateUnoDialog
    pVar = pBasic->GetRtl()->Find( u"CreateUnoDialog"_ustr, SbxClassType::Method );
    if( pVar )
    {
        pVar->SbxValue::Clear();
    }
    // delete the return value of CDec
    pVar = pBasic->GetRtl()->Find( u"CDec"_ustr, SbxClassType::Method );
    if( pVar )
    {
        pVar->SbxValue::Clear();
    }
    // delete return value of CreateObject
    pVar = pBasic->GetRtl()->Find( u"CreateObject"_ustr, SbxClassType::Method );
    if( pVar )
    {
        pVar->SbxValue::Clear();
    }
    // Go over all Sub-Basics
    SbxArray* pObjs = pBasic->GetObjects();
    sal_uInt32 nCount = pObjs->Count();
    for( sal_uInt32 i = 0 ; i < nCount ; i++ )
    {
        SbxVariable* pObjVar = pObjs->Get(i);
        StarBASIC* pSubBasic = dynamic_cast<StarBASIC*>( pObjVar  );
        if( pSubBasic )
        {
            ClearUnoObjectsInRTL_Impl_Rek( pSubBasic );
        }
    }
}

static void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic )
{
    // #67781 Delete return values of the Uno-methods
    clearUnoMethods();

    ClearUnoObjectsInRTL_Impl_Rek( pBasic );

    // Search for the topmost Basic
    SbxObject* p = pBasic;
    while( p->GetParent() )
        p = p->GetParent();
    ifstatic_cast<StarBASIC*>(p) != pBasic )
        ClearUnoObjectsInRTL_Impl_Rek( static_cast<StarBASIC*>(p) );
}


void SbModule::SetVBASupport( bool bSupport )
{
    if( mbVBASupport == bSupport )
        return;

    mbVBASupport = bSupport;
    // initialize VBA document API
    if( mbVBASupport ) try
    {
        mbCompat = true;
        StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
        uno::Reference< lang::XMultiServiceFactory > xFactory( getDocumentModel( pBasic ), uno::UNO_QUERY_THROW );
        xFactory->createInstance( u"ooo.vba.VBAGlobals"_ustr );
    }
    catch( Exception& )
    {
    }
}

namespace
{
    class RunInitGuard
    {
    protected:
        std::unique_ptr<SbiRuntime> m_xRt;
        SbiGlobals* m_pSbData;
        SbModule* m_pOldMod;
    public:
        RunInitGuard(SbModule* pModule, SbMethod* pMethod, sal_uInt32 nArg, SbiGlobals* pSbData)
            : m_xRt(new SbiRuntime(pModule, pMethod, nArg))
            , m_pSbData(pSbData)
            , m_pOldMod(pSbData->pMod)
        {
            m_xRt->pNext = pSbData->pInst->pRun;
            m_pSbData->pMod = pModule;
            m_pSbData->pInst->pRun = m_xRt.get();
        }
        void run()
        {
            while (m_xRt->Step()) {}
        }
        virtual ~RunInitGuard()
        {
            m_pSbData->pInst->pRun = m_xRt->pNext;
            m_pSbData->pMod = m_pOldMod;
            m_xRt.reset();
        }
    };

    class RunGuard : public RunInitGuard
    {
    private:
        bool m_bDelInst;
    public:
        RunGuard(SbModule* pModule, SbMethod* pMethod, sal_uInt32 nArg, SbiGlobals* pSbData, bool bDelInst)
            : RunInitGuard(pModule, pMethod, nArg, pSbData)
            , m_bDelInst(bDelInst)
        {
            if (m_xRt->pNext)
                m_xRt->pNext->block();
        }
        virtual ~RunGuard() override
        {
            if (m_xRt->pNext)
                m_xRt->pNext->unblock();

            // #63710 It can happen by an another thread handling at events,
            // that the show call returns to a dialog (by closing the
            // dialog per UI), before a by an event triggered further call returned,
            // which stands in Basic more top in the stack and that had been run on
            // a  Basic-Breakpoint. Then would the instance below destroyed. And if the Basic,
            // that stand still in the call, further runs, there is a GPF.
            // Thus here had to be wait until the other call comes back.
            if (m_bDelInst)
            {
                // Compare here with 1 instead of 0, because before nCallLvl--
                while (m_pSbData->pInst->nCallLvl != 1 && !Application::IsQuit())
                    Application::Yield();
            }

            m_pSbData->pInst->nCallLvl--;          // Call-Level down again

            // Exist an higher-ranking runtime instance?
            // Then take over BasicDebugFlags::Break, if set
            SbiRuntime* pRtNext = m_xRt->pNext;
            if (pRtNext && (m_xRt->GetDebugFlags() & BasicDebugFlags::Break))
                pRtNext->SetDebugFlags(BasicDebugFlags::Break);
        }
    };
}

// Run a Basic-subprogram
void SbModule::Run( SbMethod* pMeth )
{
    SAL_INFO("basic","About to run " << pMeth->GetName() << ", vba compatmode is " << mbVBASupport );

    static sal_uInt16 nMaxCallLevel = 0;

    SbiGlobals* pSbData = GetSbData();

    bool bDelInst = pSbData->pInst == nullptr;
    bool bQuit = false;
    StarBASICRef xBasic;
    uno::Reference< frame::XModel > xModel;
    uno::Reference< script::vba::XVBACompatibility > xVBACompat;
    if( bDelInst )
    {
        // #32779: Hold Basic during the execution
        xBasic = static_cast<StarBASIC*>( GetParent() );

        pSbData->pInst = new SbiInstance( static_cast<StarBASIC*>(GetParent()) );

        /*  If a VBA script in a document is started, get the VBA compatibility
            interface from the document Basic library container, and notify all
            VBA script listeners about the started script. */

        if( mbVBASupport )
        {
            StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
            if( pBasic && pBasic->IsDocBasic() ) try
            {
                xModel.set( getDocumentModel( pBasic ), uno::UNO_SET_THROW );
                xVBACompat.set( getVBACompatibility( xModel ), uno::UNO_SET_THROW );
                xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STARTED, GetName() );
            }
            catch(const uno::Exception& )
            {
            }
        }

        // Launcher problem
        // i80726 The Find below will generate an error in Testtool so we reset it unless there was one before already
        bool bWasError = SbxBase::GetError() != ERRCODE_NONE;
        SbxVariable* pMSOMacroRuntimeLibVar = Find( u"Launcher"_ustr, SbxClassType::Object );
        if ( !bWasError && (SbxBase::GetError() == ERRCODE_BASIC_PROC_UNDEFINED) )
            SbxBase::ResetError();
        if( pMSOMacroRuntimeLibVar )
        {
            StarBASIC* pMSOMacroRuntimeLib = dynamic_cast<StarBASIC*>( pMSOMacroRuntimeLibVar );
            if( pMSOMacroRuntimeLib )
            {
                SbxFlagBits nGblFlag = pMSOMacroRuntimeLib->GetFlags() & SbxFlagBits::GlobalSearch;
                pMSOMacroRuntimeLib->ResetFlag( SbxFlagBits::GlobalSearch );
                SbxVariable* pAppSymbol = pMSOMacroRuntimeLib->Find( u"Application"_ustr, SbxClassType::Method );
                pMSOMacroRuntimeLib->SetFlag( nGblFlag );
                if( pAppSymbol )
                {
                    pMSOMacroRuntimeLib->SetFlag( SbxFlagBits::ExtSearch );      // Could have been disabled before
                    pSbData->pMSOMacroRuntimLib = pMSOMacroRuntimeLib;
                }
            }
        }

        if( nMaxCallLevel == 0 )
        {
#ifdef UNX
          struct rlimit rl;
          getrlimit ( RLIMIT_STACK, &rl );
#endif
#if defined LINUX
          // Empiric value, 900 = needed bytes/Basic call level
          // for Linux including 10% safety margin
          nMaxCallLevel = rl.rlim_cur / 900;
#elif defined __sun
          // Empiric value, 1650 = needed bytes/Basic call level
          // for Solaris including 10% safety margin
          nMaxCallLevel = rl.rlim_cur / 1650;
#elif defined _WIN32
          nMaxCallLevel = 5800;
#else
          nMaxCallLevel = MAXRECURSION;
#endif
        }
    }

    // Recursion to deep?
    if( ++pSbData->pInst->nCallLvl <= nMaxCallLevel )
    {
        // Define a globale variable in all Mods
        GlobalRunInit( /* bBasicStart = */ bDelInst );

        // Appeared a compiler error? Then we don't launch
        if( !pSbData->bGlobalInitErr )
        {
            if( bDelInst )
            {
                SendHint( GetParent(), SfxHintId::BasicStart, pMeth );

                // 1996-10-16: #31460 New concept for StepInto/Over/Out
                // For an explanation see runtime.cxx at SbiInstance::CalcBreakCallLevel()
                // Identify the BreakCallLevel
                pSbData->pInst->CalcBreakCallLevel( pMeth->GetDebugFlags() );
            }

            {
                RunGuard xRuntimeGuard(this, pMeth, pMeth->nStart, pSbData, bDelInst);

                if (mbVBASupport)
                    pSbData->pInst->EnableCompatibility(true);

                xRuntimeGuard.run();
            }

            if( bDelInst )
            {
                // #57841 Clear Uno-Objects, which were held in RTL functions,
                // at the end of the program, so that nothing is held.
                ClearUnoObjectsInRTL_Impl( xBasic.get() );

                clearNativeObjectWrapperVector();

                SAL_WARN_IF(pSbData->pInst->nCallLvl != 0,"basic","BASIC-Call-Level > 0");
                delete pSbData->pInst;
                pSbData->pInst = nullptr;
                bDelInst = false;

                // #i30690
                SolarMutexGuard aSolarGuard;
                SendHint( GetParent(), SfxHintId::BasicStop, pMeth );

                GlobalRunDeInit();

                if( xVBACompat.is() )
                {
                    // notify all VBA script listeners about the stopped script
                    try
                    {
                        xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STOPPED, GetName() );
                    }
                    catch(const uno::Exception& )
                    {
                    }
                    // VBA always ensures screenupdating is enabled after completing
                    ::basic::vba::lockControllersOfAllDocuments( xModel, false );
                    ::basic::vba::enableContainerWindowsOfAllDocuments( xModel, true );
                }
            }
        }
        else
            pSbData->pInst->nCallLvl--;           // Call-Level down again
    }
    else
    {
        pSbData->pInst->nCallLvl--;          // Call-Level down again
        StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW );
    }

    StarBASIC* pBasic = dynamic_cast<StarBASIC*>( GetParent() );
    if( bDelInst )
    {
        // #57841 Clear Uno-Objects, which were held in RTL functions,
        // the end of the program, so that nothing is held.
        ClearUnoObjectsInRTL_Impl( xBasic.get() );

        delete pSbData->pInst;
        pSbData->pInst = nullptr;
    }
    if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !pSbData->pInst )
            bQuit = true;
    if ( bQuit )
    {
        Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ) );
    }
}

// Execute of the init method of a module after the loading
// or the compilation
void SbModule::RunInit()
{
    if( !(pImage
     && !pImage->bInit
     && pImage->IsFlag( SbiImageFlags::INITCODE )) )
        return;

    SbiGlobals* pSbData = GetSbData();

    // Set flag, so that RunInit get active (Testtool)
    pSbData->bRunInit = true;

    // The init code starts always here
    RunInitGuard(this, nullptr, 0, pSbData).run();

    pImage->bInit = true;
    pImage->bFirstInit = false;

    // RunInit is not active anymore
    pSbData->bRunInit = false;
}

// Delete with private/dim declared variables

void SbModule::AddVarName( const OUString& aName )
{
    // see if the name is added already
    for ( const auto& rModuleVariableName: mModuleVariableNames )
    {
        if ( aName == rModuleVariableName )
            return;
    }
    mModuleVariableNames.push_back( aName );
}

void SbModule::RemoveVars()
{
    for ( const auto& rModuleVariableName: mModuleVariableNames )
    {
        // We don't want a Find being called in a derived class ( e.g.
        // SbUserform because it could trigger say an initialise event
        // which would cause basic to be re-run in the middle of the init ( and remember RemoveVars is called from compile and we don't want code to run as part of the compile )
        SbxVariableRef p = SbModule::Find( rModuleVariableName, SbxClassType::Property );
        if( p.is() )
            Remove( p.get() );
    }
}

void SbModule::ClearPrivateVars()
{
    for (sal_uInt32 i = 0; i < pProps->Count(); i++)
    {
        SbProperty* p = dynamic_cast<SbProperty*>(pProps->Get(i));
        if( p )
        {
            // Delete not the arrays, only their content
            if( p->GetType() & SbxARRAY )
            {
                SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
                if( pArray )
                {
                    for (sal_uInt32 j = 0; j < pArray->Count(); j++)
                    {
                        SbxVariable* pj = pArray->Get(j);
                        pj->SbxValue::Clear();
                    }
                }
            }
            else
            {
                p->SbxValue::Clear();
            }
        }
    }
}

void SbModule::implClearIfVarDependsOnDeletedBasic(SbxVariable& rVar, StarBASIC* pDeletedBasic)
{
    if (rVar.SbxValue::GetType() != SbxOBJECT || dynamic_cast<const SbProcedureProperty*>(&rVar)&nbsp;!= nullptr)
        return;

    SbxObject* pObj = dynamic_cast<SbxObject*>(rVar.GetObject());
    if( pObj == nullptr )
        return;

    SbxObject* p = pObj;

    SbModule* pMod = dynamic_cast<SbModule*>( p  );
    if( pMod != nullptr )
        pMod->ClearVarsDependingOnDeletedBasic( pDeletedBasic );

    while( (p = p->GetParent()) != nullptr )
    {
        StarBASIC* pBasic = dynamic_cast<StarBASIC*>( p  );
        if( pBasic != nullptr && pBasic == pDeletedBasic )
        {
            rVar.SbxValue::Clear();
            break;
        }
    }
}

void SbModule::ClearVarsDependingOnDeletedBasic( StarBASIC* pDeletedBasic )
{
    for (sal_uInt32 i = 0; i < pProps->Count(); i++)
    {
        SbProperty* p = dynamic_cast<SbProperty*>(pProps->Get(i));
        if( p )
        {
            if( p->GetType() & SbxARRAY )
            {
                SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
                if( pArray )
                {
                    for (sal_uInt32 j = 0; j < pArray->Count(); j++)
                    {
                        SbxVariable* pVar = pArray->Get(j);
                        implClearIfVarDependsOnDeletedBasic(*pVar, pDeletedBasic);
                    }
                }
            }
            else
            {
                implClearIfVarDependsOnDeletedBasic(*p, pDeletedBasic);
            }
        }
    }
}

void StarBASIC::ClearAllModuleVars()
{
    // Initialise the own module
    for (const auto& rModule: pModules)
    {
        // Initialise only, if the startcode was already executed
        if( rModule->pImage && rModule->pImage->bInit && !rModule->isClassModule() && dynamic_cast<const SbObjModule*>( rModule.get()) == nullptr )
            rModule->ClearPrivateVars();
    }

}

// Execution of the init-code of all module
void SbModule::GlobalRunInit( bool bBasicStart )
{
    // If no Basic-Start, only initialise, if the module is not initialised
    if( !bBasicStart )
        if( !pImage || pImage->bInit )
            return;

    // Initialise GlobalInitErr-Flag for Compiler-Error
    // With the help of this flags could be located in SbModule::Run() after the call of
    // GlobalRunInit, if at the initialising of the module
    // an error occurred. Then it will not be launched.
    GetSbData()->bGlobalInitErr = false;

    // Parent of the module is a Basic
    StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
    if( !pBasic )
        return;

    pBasic->InitAllModules();

    SbxObject* pParent_ = pBasic->GetParent();
    if( !pParent_ )
        return;

    StarBASIC * pParentBasic = dynamic_cast<StarBASIC*>( pParent_ );
    if( !pParentBasic )
        return;

    pParentBasic->InitAllModules( pBasic );

    // #109018 Parent can also have a parent (library in doc)
    SbxObject* pParentParent = pParentBasic->GetParent();
    if( pParentParent )
    {
        StarBASIC * pParentParentBasic = dynamic_cast<StarBASIC*>( pParentParent );
        if( pParentParentBasic )
            pParentParentBasic->InitAllModules( pParentBasic );
    }
}

void SbModule::GlobalRunDeInit()
{
    StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
    if( pBasic )
    {
        pBasic->DeInitAllModules();

        SbxObject* pParent_ = pBasic->GetParent();
        if( pParent_ )
            pBasic = dynamic_cast<StarBASIC*>( pParent_ );
        if( pBasic )
            pBasic->DeInitAllModules();
    }
}

// Search for the next STMNT-Command in the code. This was used from the STMNT-
// Opcode to set the endcolumn.

const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol ) const
{
    return FindNextStmnt( p, nLine, nCol, false );
}

const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol,
    bool bFollowJumps, const SbiImage* pImg ) const
{
    sal_uInt32 nPC = static_cast<sal_uInt32>( p - pImage->GetCode() );
    while( nPC < pImage->GetCodeSize() )
    {
        SbiOpcode eOp = static_cast<SbiOpcode>( *p++ );
        nPC++;
        if( bFollowJumps && eOp == SbiOpcode::JUMP_ && pImg )
        {
            SAL_WARN_IF( !pImg, "basic""FindNextStmnt: pImg==NULL with FollowJumps option" );
            sal_uInt32 nOp1 = *p++; nOp1 |= *p++ << 8;
            nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
            p = pImg->GetCode() + nOp1;
        }
        else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
        {
            p += 4;
            nPC += 4;
        }
        else if( eOp == SbiOpcode::STMNT_ )
        {
            sal_uInt32 nl, nc;
            nl = *p++; nl |= *p++ << 8;
            nl |= *p++ << 16 ; nl |= *p++ << 24;
            nc = *p++; nc |= *p++ << 8;
            nc |= *p++ << 16 ; nc |= *p++ << 24;
            nLine = static_cast<sal_uInt16>(nl); nCol = static_cast<sal_uInt16>(nc);
            return p;
        }
        else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
        {
            p += 8;
            nPC += 8;
        }
        else if( eOp < SbiOpcode::SbOP0_START || eOp > SbiOpcode::SbOP0_END )
        {
            StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
            break;
        }
    }
    return nullptr;
}

// Test, if a line contains STMNT-Opcodes

bool SbModule::IsBreakable( sal_uInt16 nLine ) const
{
    if( !pImage )
        return false;
    const sal_uInt8* p = pImage->GetCode();
    sal_uInt16 nl, nc;
    while( ( p = FindNextStmnt( p, nl, nc ) ) != nullptr )
        if( nl == nLine )
            return true;
    return false;
}

bool SbModule::IsBP( sal_uInt16 nLine ) const
{
    if( pBreaks )
    {
        for( size_t i = 0; i < pBreaks->size(); i++ )
        {
            sal_uInt16 b = pBreaks->operator[]( i );
            if( b == nLine )
                return true;
            if( b < nLine )
                break;
        }
    }
    return false;
}

bool SbModule::SetBP( sal_uInt16 nLine )
{
    if( !IsBreakable( nLine ) )
        return false;
    if( !pBreaks )
        pBreaks.reset(new SbiBreakpoints);
    auto it = std::find_if(pBreaks->begin(), pBreaks->end(),
        [&nLine](const sal_uInt16 b) { return b <= nLine; });
    if (it != pBreaks->end() && *it == nLine)
        return true;
    pBreaks->insert( it, nLine );

    // #38568: Set during runtime as well here BasicDebugFlags::Break
    if( GetSbData()->pInst && GetSbData()->pInst->pRun )
        GetSbData()->pInst->pRun->SetDebugFlags( BasicDebugFlags::Break );

    return IsBreakable( nLine );
}

bool SbModule::ClearBP( sal_uInt16 nLine )
{
    bool bRes = false;
    if( pBreaks )
    {
        auto it = std::find_if(pBreaks->begin(), pBreaks->end(),
            [&nLine](const sal_uInt16 b) { return b <= nLine; });
        bRes = (it != pBreaks->end()) && (*it == nLine);
        if (bRes)
            pBreaks->erase(it);
        if (pBreaks->empty())
            pBreaks.reset();
    }
    return bRes;
}

void SbModule::ClearAllBP()
{
    pBreaks.reset();
}

void
SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const
{
        if ( !pImg )
            pImg = pImage.get();
        for (sal_uInt32 i = 0; i < pMethods->Count(); i++)
        {
            SbMethod* pMeth = dynamic_cast<SbMethod*>(pMethods->Get(i));
            if( pMeth )
            {
                //fixup method start positions
                if ( bCvtToLegacy )
                    pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart );
                else
                    pMeth->nStart = pImg->CalcNewOffset( static_cast<sal_uInt16>(pMeth->nStart) );
            }
        }

}

bool SbModule::LoadData( SvStream& rStrm, sal_uInt16 nVer )
{
    Clear();
    if( !SbxObject::LoadData( rStrm, 1 ) )
        return false;
    // As a precaution...
    SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
    sal_uInt8 bImage;
    rStrm.ReadUChar( bImage );
    if( !bImage )
        return true;

    std::unique_ptr<SbiImage> p(new SbiImage);
    sal_uInt32 nImgVer = 0;

    if( !p->Load( rStrm, nImgVer ) )
    {
        return false;
    }
    // If the image is in old format, we fix up the method start offsets
    if ( nImgVer < B_IMG_VERSION_12 )
    {
        fixUpMethodStart( false, p.get() );
        p->ReleaseLegacyBuffer();
    }
    aComment = p->aComment;
    SetName( p->aName );
    if( p->GetCodeSize() )
    {
        aOUSource = p->aOUSource;
        // Old version: image away
        if( nVer == 1 )
        {
            SetSource32( p->aOUSource );
        }
        else
            pImage = std::move(p);
    }
    else
    {
        SetSource32( p->aOUSource );
    }
    return true;
}

std::pair<bool, sal_uInt32> SbModule::StoreData( SvStream& rStrm ) const
{
    bool bFixup = ( pImage && !pImage->ExceedsLegacyLimits() );
    if ( bFixup )
        fixUpMethodStart( true );
    const auto [bSuccess, nVersion] = SbxObject::StoreData(rStrm);
    if (!bSuccess)
        return { false, 0 };

    if( pImage )
    {
        pImage->aOUSource = aOUSource;
        pImage->aComment = aComment;
        pImage->aName = GetName();
        rStrm.WriteUChar( 1 );
        // # PCode is saved only for legacy formats only
        // It should be noted that it probably isn't necessary
        // It would be better not to store the image ( more flexible with
        // formats )
        bool bRes = pImage->Save( rStrm, nVersion );
        if ( bFixup )
            fixUpMethodStart( false ); // restore method starts
        return { bRes, nVersion };

    }
    else
    {
        SbiImage aImg;
        aImg.aOUSource = aOUSource;
        aImg.aComment = aComment;
        aImg.aName = GetName();
        rStrm.WriteUChar( 1 );
        return { aImg.Save(rStrm, nVersion), nVersion };
    }
}

bool SbModule::ExceedsImgVersion12ModuleSize()
{
    if ( !IsCompiled() )
        Compile();
    return pImage && pImage->ExceedsImgVersion12Limits();
}

namespace {

class ErrorHdlResetter
{
    Link<StarBASIC*,bool> mErrHandler;
    bool    mbError;
public:
    ErrorHdlResetter()
        : mErrHandler(StarBASIC::GetGlobalErrorHdl()) // save error handler
        , mbError( false )
    {
        // set new error handler
        StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) );
    }
    ~ErrorHdlResetter()
    {
        // restore error handler
        StarBASIC::SetGlobalErrorHdl(mErrHandler);
    }
    DECL_LINK( BasicErrorHdl, StarBASIC *, bool );
    bool HasError() const { return mbError; }
};

}

IMPL_LINK( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/, bool)
{
    mbError = true;
    return false;
}

void SbModule::GetCodeCompleteDataFromParse(CodeCompleteDataCache& aCache)
{
    ErrorHdlResetter aErrHdl;
    SbxBase::ResetError();

    SbiParser aParser(static_cast<StarBASIC*>(GetParent()), this );
    aParser.SetCodeCompleting(true);

    while( aParser.Parse() ) {}
    SbiSymPool* pPool = aParser.pPool;
    aCache.Clear();
    for( sal_uInt16 i = 0; i < pPool->GetSize(); ++i )
    {
        SbiSymDef* pSymDef = pPool->Get(i);
        //std::cerr << "i: " << i << ", type: " << pSymDef->GetType() << "; name:" << pSymDef->GetName() << std::endl;
        if( (pSymDef->GetType() != SbxEMPTY) && (pSymDef->GetType() != SbxNULL) )
            aCache.InsertGlobalVar( pSymDef->GetName(), aParser.aGblStrings.Find(pSymDef->GetTypeId()) );

        SbiSymPool& rChildPool = pSymDef->GetPool();
        for(sal_uInt16 j = 0; j < rChildPool.GetSize(); ++j )
        {
            SbiSymDef* pChildSymDef = rChildPool.Get(j);
            //std::cerr << "j: " << j << ", type: " << pChildSymDef->GetType() << "; name:" << pChildSymDef->GetName() << std::endl;
            if( (pChildSymDef->GetType() != SbxEMPTY) && (pChildSymDef->GetType() != SbxNULL) )
                aCache.InsertLocalVar( pSymDef->GetName(), pChildSymDef->GetName(), aParser.aGblStrings.Find(pChildSymDef->GetTypeId()) );
        }
    }
}


OUString SbModule::GetKeywordCase( std::u16string_view sKeyword )
{
    return SbiParser::GetKeywordCase( sKeyword );
}

bool SbModule::HasExeCode()
{
    // And empty Image always has the Global Chain set up
    static const unsigned char pEmptyImage[] = { 0x45, 0x0 , 0x0, 0x0, 0x0 };
    // let's be stricter for the moment than VBA

    if (!IsCompiled())
    {
        ErrorHdlResetter aGblErrHdl;
        Compile();
        if (aGblErrHdl.HasError()) //assume unsafe on compile error
            return true;
    }

    bool bRes = false;
    if (pImage && (pImage->GetCodeSize() != 5 || (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) != 0 )))
        bRes = true;

    return bRes;
}

// Store only image, no source
void SbModule::StoreBinaryData( SvStream& rStrm )
{
    if (!Compile())
        return;

    const auto [bSuccess, nVersion] = SbxObject::StoreData(rStrm);
    if (!bSuccess)
        return;

    pImage->aOUSource.clear();
    pImage->aComment = aComment;
    pImage->aName = GetName();

    rStrm.WriteUChar(1);
    pImage->Save(rStrm, nVersion);

    pImage->aOUSource = aOUSource;
}

// Called for >= OO 1.0 passwd protected libraries only

void SbModule::LoadBinaryData( SvStream& rStrm )
{
    OUString aKeepSource = aOUSource;
    LoadData( rStrm, 2 );
    LoadCompleted();
    aOUSource = aKeepSource;
}

bool SbModule::LoadCompleted()
{
    SbxArray* p = GetMethods().get();
    sal_uInt32 i;
    for (i = 0; i < p->Count(); i++)
    {
        SbMethod* q = dynamic_cast<SbMethod*>(p->Get(i));
        if( q )
            q->pMod = this;
    }
    p = GetProperties();
    for (i = 0; i < p->Count(); i++)
    {
        SbProperty* q = dynamic_cast<SbProperty*>(p->Get(i));
        if( q )
            q->pMod = this;
    }
    return true;
}

void SbModule::handleProcedureProperties( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    bool bDone = false;

    const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
    if( pHint )
    {
        SbxVariable* pVar = pHint->GetVar();
        SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar  );
        if( pProcProperty )
        {
            bDone = true;

            if( pHint->GetId() == SfxHintId::BasicDataWanted )
            {
                OUString aProcName = "Property Get "
                                   + pProcProperty->GetName();

                SbxVariable* pMeth = Find( aProcName, SbxClassType::Method );
                if( pMeth )
                {
                    SbxValues aVals;
                    aVals.eType = SbxVARIANT;

                    SbxArray* pArg = pVar->GetParameters();
                    sal_uInt32 nVarParCount = (pArg != nullptr) ? pArg->Count() : 0;
                    if( nVarParCount > 1 )
                    {
                        SbxArrayRef xMethParameters = new SbxArray;
                        xMethParameters->Put(pMeth, 0); // Method as parameter 0
                        for( sal_uInt32 i = 1 ; i < nVarParCount ; ++i )
                        {
                            SbxVariable* pPar = pArg->Get(i);
                            xMethParameters->Put(pPar, i);
                        }

                        pMeth->SetParameters( xMethParameters.get() );
                        pMeth->Get( aVals );
                        pMeth->SetParameters( nullptr );
                    }
                    else
                    {
                        pMeth->Get( aVals );
                    }

                    pVar->Put( aVals );
                }
            }
            else if( pHint->GetId() == SfxHintId::BasicDataChanged )
            {
                SbxVariable* pMeth = nullptr;

                bool bSet = pProcProperty->isSet();
                if( bSet )
                {
                    pProcProperty->setSet( false );

                    OUString aProcName = "Property Set "
                                       + pProcProperty->GetName();
                    pMeth = Find( aProcName, SbxClassType::Method );
                }
                if( !pMeth )    // Let
                {
                    OUString aProcName = "Property Let "
                                       + pProcProperty->GetName();
                    pMeth = Find( aProcName, SbxClassType::Method );
                }

                if( pMeth )
                {
                    // Setup parameters
                    SbxArrayRef xArray = new SbxArray;
                    xArray->Put(pMeth, 0); // Method as parameter 0
                    xArray->Put(pVar, 1);
                    pMeth->SetParameters( xArray.get() );

                    SbxValues aVals;
                    pMeth->Get( aVals );
                    pMeth->SetParameters( nullptr );
                }
            }
        }
    }

    if( !bDone )
        SbModule::Notify( rBC, rHint );
}


// Implementation SbJScriptModule (Basic module for JavaScript source code)
SbJScriptModule::SbJScriptModule()
    :SbModule( u""_ustr )
{
}

bool SbJScriptModule::LoadData( SvStream& rStrm, sal_uInt16 )
{
    Clear();
    if( !SbxObject::LoadData( rStrm, 1 ) )
        return false;

    // Get the source string
    aOUSource = rStrm.ReadUniOrByteString( osl_getThreadTextEncoding() );
    return true;
}

std::pair<bool, sal_uInt32> SbJScriptModule::StoreData( SvStream& rStrm ) const
{
    const auto [bSuccess, nVersion] = SbxObject::StoreData(rStrm);
    if( !bSuccess )
        return { false, 0 };

    // Write the source string
    OUString aTmp = aOUSource;
    rStrm.WriteUniOrByteString( aTmp, osl_getThreadTextEncoding() );
    return { true, nVersion };
}


SbMethod::SbMethod( const OUString& r, SbxDataType t, SbModule* p )
        : SbxMethod( r, t ), pMod( p )
{
    bInvalid     = true;
    nStart       = 0;
    nDebugFlags  = BasicDebugFlags::NONE;
    nLine1       = 0;
    nLine2       = 0;
    refStatics   = new SbxArray;
    mCaller      = nullptr;
    // HACK due to 'Reference could not be saved'
    SetFlag( SbxFlagBits::NoModify );
}

SbMethod::SbMethod( const SbMethod& r )
    : SvRefBase( r ), SbxMethod( r )
{
    pMod         = r.pMod;
    bInvalid     = r.bInvalid;
    nStart       = r.nStart;
    nDebugFlags  = r.nDebugFlags;
    nLine1       = r.nLine1;
    nLine2       = r.nLine2;
    refStatics = r.refStatics;
    mCaller          = r.mCaller;
    SetFlag( SbxFlagBits::NoModify );
}

SbMethod::~SbMethod()
{
}

void SbMethod::ClearStatics()
{
    refStatics = new SbxArray;

}
SbxArray* SbMethod::GetStatics()
{
    return refStatics.get();
}

bool SbMethod::LoadData( SvStream& rStrm, sal_uInt16 nVer )
{
    if( !SbxMethod::LoadData( rStrm, 1 ) )
        return false;

    sal_uInt16 nFlag;
    rStrm.ReadUInt16( nFlag );

    sal_Int16 nTempStart = static_cast<sal_Int16>(nStart);

    if( nVer == 2 )
    {
        rStrm.ReadUInt16( nLine1 ).ReadUInt16( nLine2 ).ReadInt16( nTempStart ).ReadCharAsBool( bInvalid );
        //tdf#94617
        if (nFlag & 0x8000)
        {
            sal_uInt16 nMult = nFlag & 0x7FFF;
            sal_Int16 const nMax = std::numeric_limits<sal_Int16>::max();
            nStart = nMult * nMax + nTempStart;
        }
        else
        {
            nStart = nTempStart;
        }
    }
    else
    {
        nStart = nTempStart;
    }

    // HACK due to 'Reference could not be saved'
    SetFlag( SbxFlagBits::NoModify );

    return true;
}

std::pair<bool, sal_uInt32> SbMethod::StoreData( SvStream& rStrm ) const
{
    auto [bSuccess, nVersion] = SbxMethod::StoreData(rStrm);
    if( !bSuccess )
        return { false, 0 };

    //tdf#94617
    const sal_uInt32 nMax = std::numeric_limits<sal_Int16>::max();
    // tdf#142391 - store method using binary format 0x13 only when actually needed, i.e.,
    // when method starts at an offset that would overflow 16 bits
    const sal_Int16 nStartTemp = nStart % nMax;
    sal_uInt16 nDebugFlagsTemp = static_cast<sal_uInt16>(nDebugFlags);
    if (nStart >= nMax)
    {
        assert(nStart <= nMax * 0x7FFF); // Larger addresses can't be stored in version 13
        nDebugFlagsTemp = (nStart / nMax) | 0x8000;
        nVersion = B_IMG_VERSION_13;
    }

    rStrm.WriteUInt16( nDebugFlagsTemp )
         .WriteInt16( nLine1 )
         .WriteInt16( nLine2 )
         .WriteInt16( nStartTemp )
         .WriteBool( bInvalid );

    return { true, nVersion };
}

void SbMethod::GetLineRange( sal_uInt16& l1, sal_uInt16& l2 )
{
    l1 = nLine1; l2 = nLine2;
}

// Could later be deleted

SbxInfo* SbMethod::GetInfo()
{
    return pInfo.get();
}

// Interface to execute a method of the applications
// With special RefCounting, so that the Basic was not fired of by CloseDocument()
// The return value will be delivered as string.
ErrCode SbMethod::Call( SbxValue* pRet, SbxVariable* pCaller )
{
    if ( pCaller )
    {
        SAL_INFO("basic""SbMethod::Call Have been passed a caller 0x" << pCaller );
        mCaller = pCaller;
    }
    // Increment the RefCount of the module
    tools::SvRef<SbModule> pMod_ = static_cast<SbModule*>(GetParent());

    tools::SvRef<StarBASIC> xHolder = static_cast<StarBASIC*>(pMod_->GetParent());

    // Establish the values to get the return value
    SbxValues aVals;
    aVals.eType = SbxVARIANT;

    // #104083: Compile BEFORE get
    if( bInvalid && !pMod_->Compile() )
        StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );

    // tdf#143582 - clear return value of the method before calling it
    Clear();

    Get( aVals );
    if ( pRet )
        pRet->Put( aVals );

    // Was there an error
    ErrCode nErr = SbxBase::GetError();
    SbxBase::ResetError();

    mCaller = nullptr;
    return nErr;
}


// #100883 Own Broadcast for SbMethod
void SbMethod::Broadcast( SfxHintId nHintId )
{
    if( !mpBroadcaster || IsSet( SbxFlagBits::NoBroadcast ) )
        return;

    // Because the method could be called from outside, test here once again
    // the authorisation
    if( nHintId == SfxHintId::BasicDataWanted )
        if( !CanRead() )
            return;
    if( nHintId == SfxHintId::BasicDataChanged )
        if( !CanWrite() )
            return;

    if( pMod && !pMod->IsCompiled() )
        pMod->Compile();

    // Block broadcasts while creating new method
    std::unique_ptr<SfxBroadcaster> pSaveBroadcaster = std::move(mpBroadcaster);
    SbMethodRef xThisCopy = new SbMethod( *this );
    if( mpPar.is() )
    {
        // Enregister this as element 0, but don't reset the parent!
        if( GetType() != SbxVOID ) {
            mpPar->PutDirect( xThisCopy.get(), 0 );
        }
        SetParameters( nullptr );
    }

    mpBroadcaster = std::move(pSaveBroadcaster);
    mpBroadcaster->Broadcast( SbxHint( nHintId, xThisCopy.get() ) );

    SbxFlagBits nSaveFlags = GetFlags();
    SetFlag( SbxFlagBits::ReadWrite );
    pSaveBroadcaster = std::move(mpBroadcaster);
    Put( xThisCopy->GetValues_Impl() );
    mpBroadcaster = std::move(pSaveBroadcaster);
    SetFlags( nSaveFlags );
}


--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=90 H=93 G=91

¤ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.