summaryrefslogtreecommitdiffstats
path: root/basic/source/sbx/sbxexec.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basic/source/sbx/sbxexec.cxx')
-rw-r--r--basic/source/sbx/sbxexec.cxx391
1 files changed, 391 insertions, 0 deletions
diff --git a/basic/source/sbx/sbxexec.cxx b/basic/source/sbx/sbxexec.cxx
new file mode 100644
index 0000000000..af7d12c006
--- /dev/null
+++ b/basic/source/sbx/sbxexec.cxx
@@ -0,0 +1,391 @@
+/* -*- 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 <sal/config.h>
+
+#include <basic/sbx.hxx>
+#include <basic/sberrors.hxx>
+#include <rtl/character.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <basiccharclass.hxx>
+
+static SbxVariableRef Element
+ ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
+ SbxClassType, bool bCompatible );
+
+static const sal_Unicode* SkipWhitespace( const sal_Unicode* p )
+{
+ while( BasicCharClass::isWhitespace(*p) )
+ p++;
+ return p;
+}
+
+// Scanning of a symbol. The symbol were inserted in rSym, the return value
+// is the new scan position. The symbol is at errors empty.
+
+static const sal_Unicode* Symbol( const sal_Unicode* p, OUString& rSym, bool bCompatible )
+{
+ sal_uInt16 nLen = 0;
+ // Did we have a nonstandard symbol?
+ if( *p == '[' )
+ {
+ rSym = ++p;
+ while( *p && *p != ']' )
+ {
+ p++;
+ nLen++;
+ }
+ p++;
+ }
+ else
+ {
+ // A symbol had to begin with an alphabetic character or an underline
+ if( !BasicCharClass::isAlpha( *p, bCompatible ) && *p != '_' )
+ {
+ SbxBase::SetError( ERRCODE_BASIC_SYNTAX );
+ }
+ else
+ {
+ rSym = p;
+ // The it can contain alphabetic characters, numbers or underlines
+ while( *p && (BasicCharClass::isAlphaNumeric( *p, bCompatible ) || *p == '_') )
+ {
+ p++;
+ nLen++;
+ }
+ // Ignore standard BASIC suffixes
+ if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
+ {
+ p++;
+ }
+ }
+ }
+ rSym = rSym.copy( 0, nLen );
+ return p;
+}
+
+// Qualified name. Element.Element...
+
+static SbxVariableRef QualifiedName
+ ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, SbxClassType t, bool bCompatible )
+{
+
+ SbxVariableRef refVar;
+ const sal_Unicode* p = SkipWhitespace( *ppBuf );
+ if( BasicCharClass::isAlpha( *p, bCompatible ) || *p == '_' || *p == '[' )
+ {
+ // Read in the element
+ refVar = Element( pObj, pGbl, &p, t, bCompatible );
+ while( refVar.is() && (*p == '.' || *p == '!') )
+ {
+ // It follows still an objectelement. The current element
+ // had to be a SBX-Object or had to deliver such an object!
+ pObj = dynamic_cast<SbxObject*>( refVar.get() );
+ if( !pObj )
+ // Then it had to deliver an object
+ pObj = dynamic_cast<SbxObject*>( refVar->GetObject() );
+ refVar.clear();
+ if( !pObj )
+ break;
+ p++;
+ // And the next element please
+ refVar = Element( pObj, pGbl, &p, t, bCompatible );
+ }
+ }
+ else
+ SbxBase::SetError( ERRCODE_BASIC_SYNTAX );
+ *ppBuf = p;
+ return refVar;
+}
+
+// Read in of an operand. This could be a number, a string or
+// a function (with optional parameters).
+
+static SbxVariableRef Operand
+ ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bVar, bool bCompatible )
+{
+ SbxVariableRef refVar( new SbxVariable );
+ const sal_Unicode* p = SkipWhitespace( *ppBuf );
+ if( !bVar && ( rtl::isAsciiDigit( *p )
+ || ( *p == '.' && rtl::isAsciiDigit( *( p+1 ) ) )
+ || *p == '-'
+ || *p == '&' ) )
+ {
+ // A number could be scanned in directly!
+ sal_uInt16 nLen;
+ if( !refVar->Scan( OUString( p ), &nLen ) )
+ {
+ refVar.clear();
+ }
+ else
+ {
+ p += nLen;
+ }
+ }
+ else if( !bVar && *p == '"' )
+ {
+ // A string
+ OUStringBuffer aString;
+ p++;
+ for( ;; )
+ {
+ // This is perhaps an error
+ if( !*p )
+ {
+ return nullptr;
+ }
+ // Double quotes are OK
+ if( *p == '"' && (*++p) != '"' )
+ {
+ break;
+ }
+ aString.append(*p++);
+ }
+ refVar->PutString( aString.makeStringAndClear() );
+ }
+ else
+ {
+ refVar = QualifiedName( pObj, pGbl, &p, SbxClassType::DontCare, bCompatible );
+ }
+ *ppBuf = p;
+ return refVar;
+}
+
+// Read in of a simple term. The operands +, -, * and /
+// are supported.
+
+static SbxVariableRef MulDiv( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bCompatible )
+{
+ const sal_Unicode* p = *ppBuf;
+ SbxVariableRef refVar( Operand( pObj, pGbl, &p, false, bCompatible ) );
+ p = SkipWhitespace( p );
+ while( refVar.is() && ( *p == '*' || *p == '/' ) )
+ {
+ sal_Unicode cOp = *p++;
+ SbxVariableRef refVar2( Operand( pObj, pGbl, &p, false, bCompatible ) );
+ if( refVar2.is() )
+ {
+ // temporary variable!
+ SbxVariable* pVar = refVar.get();
+ pVar = new SbxVariable( *pVar );
+ refVar = pVar;
+ if( cOp == '*' )
+ *refVar *= *refVar2;
+ else
+ *refVar /= *refVar2;
+ }
+ else
+ {
+ refVar.clear();
+ break;
+ }
+ }
+ *ppBuf = p;
+ return refVar;
+}
+
+static SbxVariableRef PlusMinus( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bCompatible )
+{
+ const sal_Unicode* p = *ppBuf;
+ SbxVariableRef refVar( MulDiv( pObj, pGbl, &p, bCompatible ) );
+ p = SkipWhitespace( p );
+ while( refVar.is() && ( *p == '+' || *p == '-' ) )
+ {
+ sal_Unicode cOp = *p++;
+ SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p, bCompatible ) );
+ if( refVar2.is() )
+ {
+ // temporary Variable!
+ SbxVariable* pVar = refVar.get();
+ pVar = new SbxVariable( *pVar );
+ refVar = pVar;
+ if( cOp == '+' )
+ *refVar += *refVar2;
+ else
+ *refVar -= *refVar2;
+ }
+ else
+ {
+ refVar.clear();
+ break;
+ }
+ }
+ *ppBuf = p;
+ return refVar;
+}
+
+static SbxVariableRef Assign( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bCompatible )
+{
+ const sal_Unicode* p = *ppBuf;
+ SbxVariableRef refVar( Operand( pObj, pGbl, &p, true, bCompatible ) );
+ p = SkipWhitespace( p );
+ if( refVar.is() )
+ {
+ if( *p == '=' )
+ {
+ // Assign only onto properties!
+ if( refVar->GetClass() != SbxClassType::Property )
+ {
+ SbxBase::SetError( ERRCODE_BASIC_BAD_ACTION );
+ refVar.clear();
+ }
+ else
+ {
+ p++;
+ SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p, bCompatible ) );
+ if( refVar2.is() )
+ {
+ SbxVariable* pVar = refVar.get();
+ SbxVariable* pVar2 = refVar2.get();
+ *pVar = *pVar2;
+ pVar->SetParameters( nullptr );
+ }
+ }
+ }
+ else
+ // Simple call: once activating
+ refVar->Broadcast( SfxHintId::BasicDataWanted );
+ }
+ *ppBuf = p;
+ return refVar;
+}
+
+// Read in of an element. This is a symbol, optional followed
+// by a parameter list. The symbol will be searched in the
+// specified object and the parameter list will be attached if necessary.
+
+static SbxVariableRef Element
+ ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
+ SbxClassType t, bool bCompatible )
+{
+ OUString aSym;
+ const sal_Unicode* p = Symbol( *ppBuf, aSym, bCompatible );
+ SbxVariableRef refVar;
+ if( !aSym.isEmpty() )
+ {
+ SbxFlagBits nOld = pObj->GetFlags();
+ if( pObj == pGbl )
+ {
+ pObj->SetFlag( SbxFlagBits::GlobalSearch );
+ }
+ refVar = pObj->Find( aSym, t );
+ pObj->SetFlags( nOld );
+ if( refVar.is() )
+ {
+ refVar->SetParameters( nullptr );
+ // Follow still parameter?
+ p = SkipWhitespace( p );
+ if( *p == '(' )
+ {
+ p++;
+ auto refPar = tools::make_ref<SbxArray>();
+ sal_uInt32 nArg = 0;
+ // We are once relaxed and accept as well
+ // the line- or command end as delimiter
+ // Search parameter always global!
+ while( *p && *p != ')' && *p != ']' )
+ {
+ SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p, bCompatible );
+ if( !refArg.is() )
+ {
+ // Error during the parsing
+ refVar.clear(); break;
+ }
+ else
+ {
+ // One copies the parameter, so that
+ // one have the current status (triggers also
+ // the call per access)
+ refPar->Put(new SbxVariable(*refArg), ++nArg);
+ }
+ p = SkipWhitespace( p );
+ if( *p == ',' )
+ p++;
+ }
+ if( *p == ')' )
+ p++;
+ if( refVar.is() )
+ refVar->SetParameters( refPar.get() );
+ }
+ }
+ else
+ SbxBase::SetError( ERRCODE_BASIC_NO_METHOD, aSym );
+ }
+ *ppBuf = p;
+ return refVar;
+}
+
+// Mainroutine
+
+SbxVariable* SbxObject::Execute( const OUString& rTxt )
+{
+ SbxVariableRef pVar;
+ const sal_Unicode* p = rTxt.getStr();
+ for( ;; )
+ {
+ p = SkipWhitespace( p );
+ if( !*p )
+ {
+ break;
+ }
+ if( *p++ != '[' )
+ {
+ SetError( ERRCODE_BASIC_SYNTAX ); break;
+ }
+ pVar = Assign( this, this, &p, IsOptionCompatible() );
+ if( !pVar.is() )
+ {
+ break;
+ }
+ p = SkipWhitespace( p );
+ if( *p++ != ']' )
+ {
+ SetError( ERRCODE_BASIC_SYNTAX ); break;
+ }
+ }
+ return pVar.get();
+}
+
+SbxVariable* SbxObject::FindQualified( const OUString& rName, SbxClassType t )
+{
+ SbxVariableRef pVar;
+ const sal_Unicode* p = rName.getStr();
+ p = SkipWhitespace( p );
+ if( !*p )
+ {
+ return nullptr;
+ }
+ pVar = QualifiedName( this, this, &p, t, IsOptionCompatible() );
+ p = SkipWhitespace( p );
+ if( *p )
+ {
+ SetError( ERRCODE_BASIC_SYNTAX );
+ }
+ return pVar.get();
+}
+
+bool SbxObject::IsOptionCompatible() const
+{
+ if (const SbxObject* pObj = GetParent())
+ return pObj->IsOptionCompatible();
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */