/* -*- 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 .
*/
/* 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;
}
// 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 )
{ returndynamic_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 );
}
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 );
// 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() );
}
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() );
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() );
// 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 ( constauto& rModuleVariableName: mModuleVariableNames )
{ if ( aName == rModuleVariableName ) return;
}
mModuleVariableNames.push_back( aName );
}
void SbModule::RemoveVars()
{ for ( constauto& 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 StarBASIC::ClearAllModuleVars()
{ // Initialise the own module for (constauto& 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;
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 ) returntrue; if( b < nLine ) break;
}
} returnfalse;
}
bool SbModule::SetBP( sal_uInt16 nLine )
{ if( !IsBreakable( nLine ) ) returnfalse; 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) returntrue;
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;
}
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 };
bool SbModule::HasExeCode()
{ // And empty Image always has the Global Chain set up staticconstunsignedchar 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 returntrue;
}
// 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());
// 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;
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.