forked from amazingfate/loongoffice
parsing 1000s of line of code is hard enough without having to fight with weird indentation and irregular formatting. So as the review progress, in order to follow the code, cosmetic changes were made... In order to minimize the task of the reviewers and allow them to concentrate on what matter, an effort is made to collect these cosmetic changes into this separate commit. Change-Id: I3c9b04a0150d0d0a048c2e976fe24de4f2b6b98a
1506 lines
43 KiB
C++
1506 lines
43 KiB
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 <comphelper/string.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.hpp>
|
|
#include <rtl/instance.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <unotools/textsearch.hxx>
|
|
|
|
Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
|
|
const OUString& aPrefix, SbxObjectRef xScopeObj );
|
|
|
|
#include <algorithm>
|
|
#include <boost/unordered_map.hpp>
|
|
|
|
// for a patch forward declaring these methods below makes sense
|
|
// but, #FIXME lets really just move the methods to the top
|
|
static void lcl_clearImpl( SbxVariableRef& refVar, SbxDataType& eType );
|
|
static void lcl_eraseImpl( SbxVariableRef& refVar, bool bVBAEnabled );
|
|
|
|
SbxVariable* getDefaultProp( SbxVariable* pRef );
|
|
|
|
void SbiRuntime::StepNOP()
|
|
{}
|
|
|
|
void SbiRuntime::StepArith( SbxOperator eOp )
|
|
{
|
|
SbxVariableRef p1 = PopVar();
|
|
TOSMakeTemp();
|
|
SbxVariable* p2 = GetTOS();
|
|
|
|
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 == SbxEMPTY )
|
|
{
|
|
p1->Broadcast( SBX_HINT_DATAWANTED );
|
|
p1Type = p1->GetType();
|
|
}
|
|
if ( p2Type == SbxEMPTY )
|
|
{
|
|
p2->Broadcast( SBX_HINT_DATAWANTED );
|
|
p2Type = p2->GetType();
|
|
}
|
|
if ( p1Type == p2Type )
|
|
{
|
|
// 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 )
|
|
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;
|
|
static SbxVariable* pNULL = NULL;
|
|
// why do this on non-windows ?
|
|
// why do this at all ?
|
|
// I dumbly follow the pattern :-/
|
|
if ( bVBAEnabled && ( p1->IsNull() || p2->IsNull() ) )
|
|
{
|
|
if( !pNULL )
|
|
{
|
|
pNULL = new SbxVariable;
|
|
pNULL->PutNull();
|
|
pNULL->AddRef();
|
|
}
|
|
PushVar( pNULL );
|
|
}
|
|
else if( p2->Compare( eOp, *p1 ) )
|
|
{
|
|
if( !pTRUE )
|
|
{
|
|
pTRUE = new SbxVariable;
|
|
pTRUE->PutBool( sal_True );
|
|
pTRUE->AddRef();
|
|
}
|
|
PushVar( pTRUE );
|
|
}
|
|
else
|
|
{
|
|
if( !pFALSE )
|
|
{
|
|
pFALSE = new SbxVariable;
|
|
pFALSE->PutBool( sal_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)
|
|
{
|
|
if((cCode & 0xFF80))
|
|
{
|
|
return false;
|
|
}
|
|
switch((sal_uInt8)(cCode & 0x07F))
|
|
{
|
|
case '.':
|
|
case '^':
|
|
case '$':
|
|
case '+':
|
|
case '\\':
|
|
case '|':
|
|
case '{':
|
|
case '}':
|
|
case '(':
|
|
case ')':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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 = ( GetSbData()->pInst && GetSbData()->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 and TOS-1 are both object variables and contain the same 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();
|
|
}
|
|
|
|
sal_Bool bRes = sal_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 );
|
|
}
|
|
|
|
// update the value of TOS
|
|
|
|
void SbiRuntime::StepGET()
|
|
{
|
|
SbxVariable* p = GetTOS();
|
|
p->Broadcast( SBX_HINT_DATAWANTED );
|
|
}
|
|
|
|
// #67607 copy Uno-Structs
|
|
inline bool checkUnoStructCopy( bool bVBA, SbxVariableRef& refVal, SbxVariableRef& refVar )
|
|
{
|
|
SbxDataType eVarType = refVar->GetType();
|
|
SbxDataType eValType = refVal->GetType();
|
|
|
|
if ( !( !bVBA|| ( bVBA && refVar->GetType() != SbxEMPTY ) ) || !refVar->CanWrite() )
|
|
return false;
|
|
|
|
if ( eValType != SbxOBJECT )
|
|
return false;
|
|
// we seem to be duplicating parts of SbxValue=operator, maybe we should just move this to
|
|
// there :-/ not sure if for every '=' we would want struct handling
|
|
if( eVarType != SbxOBJECT )
|
|
{
|
|
if ( refVar->IsFixed() )
|
|
return false;
|
|
}
|
|
// #115826: Exclude ProcedureProperties to avoid call to Property Get procedure
|
|
else if( refVar->ISA(SbProcedureProperty) )
|
|
return false;
|
|
|
|
SbxObjectRef xValObj = (SbxObject*)refVal->GetObject();
|
|
if( !xValObj.Is() || xValObj->ISA(SbUnoAnyObject) )
|
|
return false;
|
|
|
|
SbUnoObject* pUnoVal = PTR_CAST(SbUnoObject,(SbxObject*)xValObj);
|
|
SbUnoStructRefObject* pUnoStructVal = PTR_CAST(SbUnoStructRefObject,(SbxObject*)xValObj);
|
|
Any aAny;
|
|
// make doubly sure value is either an Uno object or
|
|
// an uno struct
|
|
if ( pUnoVal || pUnoStructVal )
|
|
aAny = pUnoVal ? pUnoVal->getUnoAny() : pUnoStructVal->getUnoAny();
|
|
else
|
|
return false;
|
|
if ( aAny.getValueType().getTypeClass() == TypeClass_STRUCT )
|
|
{
|
|
refVar->SetType( SbxOBJECT );
|
|
SbxObjectRef xVarObj = (SbxObject*)refVar->GetObject();
|
|
SbUnoStructRefObject* pUnoStructObj = PTR_CAST(SbUnoStructRefObject,(SbxObject*)xVarObj);
|
|
|
|
if ( ( !pUnoVal && !pUnoStructVal ) )
|
|
return false;
|
|
|
|
String sClassName = pUnoVal ? pUnoVal->GetClassName() : pUnoStructVal->GetClassName();
|
|
String sName = pUnoVal ? pUnoVal->GetName() : pUnoStructVal->GetName();
|
|
|
|
if ( pUnoStructObj )
|
|
{
|
|
StructRefInfo aInfo = pUnoStructObj->getStructInfo();
|
|
aInfo.setValue( aAny );
|
|
}
|
|
else
|
|
{
|
|
SbUnoObject* pNewUnoObj = new SbUnoObject( sName, aAny );
|
|
// #70324: adopt ClassName
|
|
pNewUnoObj->SetClassName( sClassName );
|
|
refVar->PutObject( pNewUnoObj );
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// laying down TOS in TOS-1
|
|
|
|
void SbiRuntime::StepPUT()
|
|
{
|
|
SbxVariableRef refVal = PopVar();
|
|
SbxVariableRef refVar = PopVar();
|
|
// store on its own method (inside a function)?
|
|
bool bFlagsChanged = false;
|
|
sal_uInt16 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;
|
|
}
|
|
}
|
|
|
|
if ( !checkUnoStructCopy( bVBAEnabled, refVal, refVar ) )
|
|
*refVar = *refVal;
|
|
|
|
if( bFlagsChanged )
|
|
refVar->SetFlags( n );
|
|
}
|
|
|
|
|
|
// VBA Dim As New behavior handling, save init object information
|
|
struct DimAsNewRecoverItem
|
|
{
|
|
OUString m_aObjClass;
|
|
OUString m_aObjName;
|
|
SbxObject* m_pObjParent;
|
|
SbModule* m_pClassModule;
|
|
|
|
DimAsNewRecoverItem( void )
|
|
: m_pObjParent( NULL )
|
|
, m_pClassModule( NULL )
|
|
{}
|
|
|
|
DimAsNewRecoverItem( const OUString& rObjClass, const OUString& 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 boost::unordered_map< SbxVariable*, DimAsNewRecoverItem,
|
|
SbxVariablePtrHash > DimAsNewRecoverHash;
|
|
|
|
class GaDimAsNewRecoverHash : public rtl::Static<DimAsNewRecoverHash, GaDimAsNewRecoverHash> {};
|
|
|
|
void removeDimAsNewRecoverItem( SbxVariable* pVar )
|
|
{
|
|
DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get();
|
|
DimAsNewRecoverHash::iterator it = rDimAsNewRecoverHash.find( pVar );
|
|
if( it != rDimAsNewRecoverHash.end() )
|
|
{
|
|
rDimAsNewRecoverHash.erase( it );
|
|
}
|
|
}
|
|
|
|
|
|
// saving object variable
|
|
// not-object variables will cause errors
|
|
|
|
static const char pCollectionStr[] = "Collection";
|
|
|
|
void SbiRuntime::StepSET_Impl( SbxVariableRef& refVal, SbxVariableRef& refVar, bool bHandleDefaultProp )
|
|
{
|
|
// #67733 types with array-flag are OK too
|
|
|
|
// 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();
|
|
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 ) )
|
|
{
|
|
// activate GetOject for collections on refVal
|
|
SbxBase* pObjVarObj = refVal->GetObject();
|
|
if( pObjVarObj )
|
|
{
|
|
SbxVariableRef refObjVal = PTR_CAST(SbxObject,pObjVarObj);
|
|
|
|
if( refObjVal )
|
|
{
|
|
refVal = refObjVal;
|
|
}
|
|
else if( !(eValType & SbxARRAY) )
|
|
{
|
|
refVal = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// #52896 refVal can be invalid here, if uno-sequences - or more
|
|
// general arrays - are assigned to variables that are declared
|
|
// as an object!
|
|
if( !refVal )
|
|
{
|
|
Error( SbERR_INVALID_USAGE_OBJECT );
|
|
}
|
|
else
|
|
{
|
|
bool bFlagsChanged = false;
|
|
sal_uInt16 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
|
|
sal_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();
|
|
OUString aVBAType = aDeclareClassName;
|
|
OUString aPrefix = refVar->GetName();
|
|
SbxObjectRef xScopeObj = refVar->GetParent();
|
|
xComListener = createComListener( aControlAny, aVBAType, aPrefix, xScopeObj );
|
|
|
|
refVal->SetDeclareClassName( aDeclareClassName );
|
|
refVal->SetComListener( xComListener, &rBasic ); // Hold reference
|
|
}
|
|
|
|
}
|
|
|
|
// 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 ( !checkUnoStructCopy( bHandleDefaultProp, refVal, refVar ) )
|
|
{
|
|
*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 &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get();
|
|
DimAsNewRecoverHash::iterator it = rDimAsNewRecoverHash.find( refVar );
|
|
if( it != rDimAsNewRecoverHash.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.equalsIgnoreAsciiCaseAscii( pCollectionStr ) )
|
|
{
|
|
BasicCollection* pNewCollection = new BasicCollection( OUString(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);
|
|
DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get();
|
|
if( pClassModuleObj != NULL )
|
|
{
|
|
SbModule* pClassModule = pClassModuleObj->getClassModule();
|
|
rDimAsNewRecoverHash[refVar] =
|
|
DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), pClassModule );
|
|
}
|
|
else if( aObjClass.EqualsIgnoreCaseAscii( "Collection" ) )
|
|
{
|
|
rDimAsNewRecoverHash[refVar] =
|
|
DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), NULL );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
|
|
void SbiRuntime::StepLSET()
|
|
{
|
|
SbxVariableRef refVal = PopVar();
|
|
SbxVariableRef refVar = PopVar();
|
|
if( refVar->GetType() != SbxSTRING ||
|
|
refVal->GetType() != SbxSTRING )
|
|
{
|
|
Error( SbERR_INVALID_USAGE_OBJECT );
|
|
}
|
|
else
|
|
{
|
|
sal_uInt16 n = refVar->GetFlags();
|
|
if( (SbxVariable*) refVar == (SbxVariable*) pMeth )
|
|
refVar->SetFlag( SBX_WRITE );
|
|
String aRefVarString = refVar->GetString();
|
|
String aRefValString = refVal->GetString();
|
|
|
|
sal_uInt16 nVarStrLen = aRefVarString.Len();
|
|
sal_uInt16 nValStrLen = aRefValString.Len();
|
|
rtl::OUStringBuffer aNewStr;
|
|
if( nVarStrLen > nValStrLen )
|
|
{
|
|
aNewStr.append(aRefValString);
|
|
comphelper::string::padToLength(aNewStr, nVarStrLen, ' ');
|
|
}
|
|
else
|
|
{
|
|
aNewStr.append(aRefValString.Copy(0, nVarStrLen));
|
|
}
|
|
|
|
refVar->PutString(aNewStr.makeStringAndClear());
|
|
refVar->SetFlags( n );
|
|
}
|
|
}
|
|
|
|
void SbiRuntime::StepRSET()
|
|
{
|
|
SbxVariableRef refVal = PopVar();
|
|
SbxVariableRef refVar = PopVar();
|
|
if( refVar->GetType() != SbxSTRING || refVal->GetType() != SbxSTRING )
|
|
{
|
|
Error( SbERR_INVALID_USAGE_OBJECT );
|
|
}
|
|
else
|
|
{
|
|
sal_uInt16 n = refVar->GetFlags();
|
|
if( (SbxVariable*) refVar == (SbxVariable*) pMeth )
|
|
refVar->SetFlag( SBX_WRITE );
|
|
String aRefVarString = refVar->GetString();
|
|
String aRefValString = refVal->GetString();
|
|
|
|
sal_uInt16 nVarStrLen = aRefVarString.Len();
|
|
sal_uInt16 nValStrLen = aRefValString.Len();
|
|
rtl::OUStringBuffer aNewStr;
|
|
if (nVarStrLen > nValStrLen)
|
|
{
|
|
comphelper::string::padToLength(aNewStr, nVarStrLen - nValStrLen, ' ');
|
|
aNewStr.append(aRefValString);
|
|
}
|
|
else
|
|
{
|
|
aNewStr.append(aRefValString.Copy(0, nVarStrLen));
|
|
}
|
|
refVar->PutString(aNewStr.makeStringAndClear());
|
|
|
|
refVar->SetFlags( n );
|
|
}
|
|
}
|
|
|
|
// laying down TOS in TOS-1, then set ReadOnly-Bit
|
|
|
|
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 for the array with dimension information as parameter
|
|
|
|
void SbiRuntime::StepDIM()
|
|
{
|
|
SbxVariableRef refVar = PopVar();
|
|
DimImpl( refVar );
|
|
}
|
|
|
|
// #56204 swap out DIM-functionality into a help method (step0.cxx)
|
|
void SbiRuntime::DimImpl( SbxVariableRef refVar )
|
|
{
|
|
// If refDim then this DIM statement is terminating a ReDIM and
|
|
// previous StepERASE_CLEAR for an array, the following actions have
|
|
// been delayed from ( StepERASE_CLEAR ) 'till here
|
|
if ( refRedim )
|
|
{
|
|
if ( !refRedimpArray ) // only erase the array not ReDim Preserve
|
|
{
|
|
lcl_eraseImpl( refVar, bVBAEnabled );
|
|
}
|
|
SbxDataType eType = refVar->GetType();
|
|
lcl_clearImpl( refVar, eType );
|
|
refRedim = NULL;
|
|
}
|
|
SbxArray* pDims = refVar->GetParameters();
|
|
// must have an even number of arguments
|
|
// have in mind that Arg[0] does not count!
|
|
if( pDims && !( pDims->Count() & 1 ) )
|
|
{
|
|
StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
|
|
}
|
|
else
|
|
{
|
|
SbxDataType eType = refVar->IsFixed() ? refVar->GetType() : SbxVARIANT;
|
|
SbxDimArray* pArray = new SbxDimArray( eType );
|
|
// allow arrays without dimension information, too (VB-compatible)
|
|
if( pDims )
|
|
{
|
|
refVar->ResetFlag( SBX_VAR_TO_DIM );
|
|
|
|
for( sal_uInt16 i = 1; i < pDims->Count(); )
|
|
{
|
|
sal_Int32 lb = pDims->Get( i++ )->GetLong();
|
|
sal_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 On creating an array of the length 0, create
|
|
// a dimension (like for Uno-Sequences of the length 0)
|
|
pArray->unoAddDim( 0, -1 );
|
|
}
|
|
sal_uInt16 nSavFlags = refVar->GetFlags();
|
|
refVar->ResetFlag( SBX_FIXED );
|
|
refVar->PutObject( pArray );
|
|
refVar->SetFlags( nSavFlags );
|
|
refVar->SetParameters( NULL );
|
|
}
|
|
}
|
|
|
|
// REDIM
|
|
// TOS = variable for the array
|
|
// argv = dimension information
|
|
|
|
void SbiRuntime::StepREDIM()
|
|
{
|
|
// Nothing different than dim at the moment because
|
|
// a double dim is already recognized by the compiler.
|
|
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 for the array
|
|
// argv = dimension information
|
|
|
|
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 );
|
|
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// REDIM_COPY
|
|
// TOS = Array-Variable, Reference to array is copied
|
|
// Variable is cleared as in ERASE
|
|
|
|
void SbiRuntime::StepREDIMP_ERASE()
|
|
{
|
|
SbxVariableRef refVar = PopVar();
|
|
refRedim = refVar;
|
|
SbxDataType eType = refVar->GetType();
|
|
if( eType & SbxARRAY )
|
|
{
|
|
SbxBase* pElemObj = refVar->GetObject();
|
|
SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj);
|
|
if( pDimArray )
|
|
{
|
|
refRedimpArray = pDimArray;
|
|
}
|
|
|
|
}
|
|
else if( refVar->IsFixed() )
|
|
{
|
|
refVar->Clear();
|
|
}
|
|
else
|
|
{
|
|
refVar->SetType( SbxEMPTY );
|
|
}
|
|
}
|
|
|
|
static void lcl_clearImpl( SbxVariableRef& refVar, SbxDataType& eType )
|
|
{
|
|
sal_uInt16 nSavFlags = refVar->GetFlags();
|
|
refVar->ResetFlag( SBX_FIXED );
|
|
refVar->SetType( SbxDataType(eType & 0x0FFF) );
|
|
refVar->SetFlags( nSavFlags );
|
|
refVar->Clear();
|
|
}
|
|
|
|
static 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
|
|
{
|
|
// Arrays have on an erase to VB quite a complex behaviour. Here are
|
|
// only the type problems at REDIM (#26295) removed at first:
|
|
// Set type hard onto the array-type, because a variable with array is
|
|
// SbxOBJECT. At REDIM there's an SbxOBJECT-array generated then and
|
|
// the original type is lost -> runtime error
|
|
lcl_clearImpl( refVar, eType );
|
|
}
|
|
}
|
|
else if( refVar->IsFixed() )
|
|
{
|
|
refVar->Clear();
|
|
}
|
|
else
|
|
{
|
|
refVar->SetType( SbxEMPTY );
|
|
}
|
|
}
|
|
|
|
// delete variable
|
|
// TOS = variable
|
|
|
|
void SbiRuntime::StepERASE()
|
|
{
|
|
SbxVariableRef refVar = PopVar();
|
|
lcl_eraseImpl( refVar, bVBAEnabled );
|
|
}
|
|
|
|
void SbiRuntime::StepERASE_CLEAR()
|
|
{
|
|
refRedim = PopVar();
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
// establishing an argv
|
|
// nOp1 stays as it is -> 1st element is the return value
|
|
|
|
void SbiRuntime::StepARGC()
|
|
{
|
|
PushArgv();
|
|
refArgv = new SbxArray;
|
|
nArgc = 1;
|
|
}
|
|
|
|
// storing an argument 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(SbUnoProperty) || pVal->ISA(SbProcedureProperty) )
|
|
{
|
|
// evaluate methods and properties!
|
|
SbxVariable* pRes = new SbxVariable( *pVal );
|
|
pVal = pRes;
|
|
}
|
|
refArgv->Put( pVal, nArgc++ );
|
|
}
|
|
}
|
|
|
|
// Input to Variable. The variable is on TOS and is
|
|
// is removed afterwards.
|
|
|
|
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();
|
|
// try to fill the variable with a numeric value first,
|
|
// then with a string value
|
|
if( !pVar->IsFixed() || pVar->IsNumeric() )
|
|
{
|
|
sal_uInt16 nLen = 0;
|
|
if( !pVar->Scan( s, &nLen ) )
|
|
{
|
|
err = SbxBase::GetError();
|
|
SbxBase::ResetError();
|
|
}
|
|
// the value has to be scanned in completely
|
|
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() )
|
|
{
|
|
pCode = pRestart;
|
|
}
|
|
else
|
|
{
|
|
Error( err );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PopVar();
|
|
}
|
|
}
|
|
|
|
// Line Input to Variable. The variable is on TOS and is
|
|
// deleted afterwards.
|
|
|
|
void SbiRuntime::StepLINPUT()
|
|
{
|
|
OString aInput;
|
|
pIosys->Read( aInput );
|
|
Error( pIosys->GetError() );
|
|
SbxVariableRef p = PopVar();
|
|
p->PutString(rtl::OStringToOUString(aInput, osl_getThreadTextEncoding()));
|
|
}
|
|
|
|
// end of program
|
|
|
|
void SbiRuntime::StepSTOP()
|
|
{
|
|
pInst->Stop();
|
|
}
|
|
|
|
|
|
void SbiRuntime::StepINITFOR()
|
|
{
|
|
PushFor();
|
|
}
|
|
|
|
void SbiRuntime::StepINITFOREACH()
|
|
{
|
|
PushForEach();
|
|
}
|
|
|
|
// increment FOR-variable
|
|
|
|
void SbiRuntime::StepNEXT()
|
|
{
|
|
if( !pForStk )
|
|
{
|
|
StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
|
|
return;
|
|
}
|
|
if( pForStk->eForType == FOR_TO )
|
|
{
|
|
pForStk->refVar->Compute( SbxPLUS, *pForStk->refInc );
|
|
}
|
|
}
|
|
|
|
// beginning CASE: TOS in CASE-stack
|
|
|
|
void SbiRuntime::StepCASE()
|
|
{
|
|
if( !refCaseStk.Is() )
|
|
{
|
|
refCaseStk = new SbxArray;
|
|
}
|
|
SbxVariableRef xVar = PopVar();
|
|
refCaseStk->Put( xVar, refCaseStk->Count() );
|
|
}
|
|
|
|
// end CASE: free variable
|
|
|
|
void SbiRuntime::StepENDCASE()
|
|
{
|
|
if( !refCaseStk || !refCaseStk->Count() )
|
|
{
|
|
StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
|
|
}
|
|
else
|
|
{
|
|
refCaseStk->Remove( refCaseStk->Count() - 1 );
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
// leave UP
|
|
|
|
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 = channel number
|
|
{
|
|
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 = ' '; // one blank before
|
|
s += s1;
|
|
rtl::OString aByteStr(rtl::OUStringToOString(s, osl_getThreadTextEncoding()));
|
|
pIosys->Write( aByteStr );
|
|
Error( pIosys->GetError() );
|
|
}
|
|
|
|
void SbiRuntime::StepPRINTF() // print TOS in field
|
|
{
|
|
SbxVariableRef p = PopVar();
|
|
OUString s1 = p->GetString();
|
|
OUStringBuffer s;
|
|
if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE )
|
|
{
|
|
s.append(' ');
|
|
}
|
|
s.append(s1);
|
|
comphelper::string::padToLength(s, 14, ' ');
|
|
OString aByteStr(OUStringToOString(s.makeStringAndClear(), osl_getThreadTextEncoding()));
|
|
pIosys->Write( aByteStr );
|
|
Error( pIosys->GetError() );
|
|
}
|
|
|
|
void SbiRuntime::StepWRITE() // write TOS
|
|
{
|
|
SbxVariableRef p = PopVar();
|
|
// Does the string have to be encapsulated?
|
|
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;
|
|
rtl::OString aByteStr(rtl::OUStringToOString(s, osl_getThreadTextEncoding()));
|
|
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();
|
|
|
|
if( hasUno() )
|
|
{
|
|
implStepRenameUCB( aSource, aDest );
|
|
}
|
|
else
|
|
{
|
|
implStepRenameOSL( aSource, aDest );
|
|
}
|
|
}
|
|
|
|
// TOS = Prompt
|
|
|
|
void SbiRuntime::StepPROMPT()
|
|
{
|
|
SbxVariableRef p = PopVar();
|
|
rtl::OString aStr(rtl::OUStringToOString(p->GetString(), osl_getThreadTextEncoding()));
|
|
pIosys->SetPrompt( aStr );
|
|
}
|
|
|
|
// Set Restart point
|
|
|
|
void SbiRuntime::StepRESTART()
|
|
{
|
|
pRestart = pCode;
|
|
}
|
|
|
|
// empty expression on stack for missing parameter
|
|
|
|
void SbiRuntime::StepEMPTY()
|
|
{
|
|
// #57915 The semantics of StepEMPTY() is the representation of a missing argument.
|
|
// This is represented by the value 448 (SbERR_NAMED_NOT_FOUND) of the type error
|
|
// in VB. StepEmpty should now rather be named StepMISSING() but the name is kept
|
|
// to simplify matters.
|
|
SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
|
|
xVar->PutErr( 448 );
|
|
PushVar( xVar );
|
|
}
|
|
|
|
// TOS = error code
|
|
|
|
void SbiRuntime::StepERROR()
|
|
{
|
|
SbxVariableRef refCode = PopVar();
|
|
sal_uInt16 n = refCode->GetUShort();
|
|
SbError error = StarBASIC::GetSfxFromVBError( n );
|
|
if ( bVBAEnabled )
|
|
{
|
|
pInst->Error( error );
|
|
}
|
|
else
|
|
{
|
|
Error( error );
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|