Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / sbx / sbxexec.cxx
blobd5f46f06ac46602c844683578e5b9a35bc83b9f1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <basic/sbx.hxx>
21 #include <basic/sberrors.hxx>
22 #include <rtl/character.hxx>
23 #include <rtl/ustrbuf.hxx>
26 static SbxVariableRef Element
27 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
28 SbxClassType );
30 static const sal_Unicode* SkipWhitespace( const sal_Unicode* p )
32 while( *p && ( *p == ' ' || *p == '\t' ) )
33 p++;
34 return p;
37 // Scanning of a symbol. The symbol were inserted in rSym, the return value
38 // is the new scan position. The symbol is at errors empty.
40 static const sal_Unicode* Symbol( const sal_Unicode* p, OUString& rSym )
42 sal_uInt16 nLen = 0;
43 // Did we have a nonstandard symbol?
44 if( *p == '[' )
46 rSym = ++p;
47 while( *p && *p != ']' )
49 p++;
50 nLen++;
52 p++;
54 else
56 // A symbol had to begin with an alphabetic character or an underline
57 if( !rtl::isAsciiAlpha( *p ) && *p != '_' )
59 SbxBase::SetError( ERRCODE_BASIC_SYNTAX );
61 else
63 rSym = p;
64 // The it can contain alphabetic characters, numbers or underlines
65 while( *p && (rtl::isAsciiAlphanumeric( *p ) || *p == '_') )
67 p++;
68 nLen++;
70 // Ignore standard BASIC suffixes
71 if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
73 p++;
77 rSym = rSym.copy( 0, nLen );
78 return p;
81 // Qualified name. Element.Element...
83 static SbxVariableRef QualifiedName
84 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, SbxClassType t )
87 SbxVariableRef refVar;
88 const sal_Unicode* p = SkipWhitespace( *ppBuf );
89 if( rtl::isAsciiAlpha( *p ) || *p == '_' || *p == '[' )
91 // Read in the element
92 refVar = Element( pObj, pGbl, &p, t );
93 while( refVar.is() && (*p == '.' || *p == '!') )
95 // It follows still an objectelement. The current element
96 // had to be a SBX-Object or had to deliver such an object!
97 pObj = dynamic_cast<SbxObject*>( refVar.get() );
98 if( !pObj )
99 // Then it had to deliver an object
100 pObj = dynamic_cast<SbxObject*>( refVar->GetObject() );
101 refVar.clear();
102 if( !pObj )
103 break;
104 p++;
105 // And the next element please
106 refVar = Element( pObj, pGbl, &p, t );
109 else
110 SbxBase::SetError( ERRCODE_BASIC_SYNTAX );
111 *ppBuf = p;
112 return refVar;
115 // Read in of an operand. This could be a number, a string or
116 // a function (with optional parameters).
118 static SbxVariableRef Operand
119 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bVar )
121 SbxVariableRef refVar( new SbxVariable );
122 const sal_Unicode* p = SkipWhitespace( *ppBuf );
123 if( !bVar && ( rtl::isAsciiDigit( *p )
124 || ( *p == '.' && rtl::isAsciiDigit( *( p+1 ) ) )
125 || *p == '-'
126 || *p == '&' ) )
128 // A number could be scanned in directly!
129 sal_uInt16 nLen;
130 if( !refVar->Scan( OUString( p ), &nLen ) )
132 refVar.clear();
134 else
136 p += nLen;
139 else if( !bVar && *p == '"' )
141 // A string
142 OUStringBuffer aString;
143 p++;
144 for( ;; )
146 // This is perhaps an error
147 if( !*p )
149 return nullptr;
151 // Double quotes are OK
152 if( *p == '"' && (*++p) != '"' )
154 break;
156 aString.append(*p++);
158 refVar->PutString( aString.makeStringAndClear() );
160 else
162 refVar = QualifiedName( pObj, pGbl, &p, SbxClassType::DontCare );
164 *ppBuf = p;
165 return refVar;
168 // Read in of a simple term. The operands +, -, * and /
169 // are supported.
171 static SbxVariableRef MulDiv( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf )
173 const sal_Unicode* p = *ppBuf;
174 SbxVariableRef refVar( Operand( pObj, pGbl, &p, false ) );
175 p = SkipWhitespace( p );
176 while( refVar.is() && ( *p == '*' || *p == '/' ) )
178 sal_Unicode cOp = *p++;
179 SbxVariableRef refVar2( Operand( pObj, pGbl, &p, false ) );
180 if( refVar2.is() )
182 // temporary variable!
183 SbxVariable* pVar = refVar.get();
184 pVar = new SbxVariable( *pVar );
185 refVar = pVar;
186 if( cOp == '*' )
187 *refVar *= *refVar2;
188 else
189 *refVar /= *refVar2;
191 else
193 refVar.clear();
194 break;
197 *ppBuf = p;
198 return refVar;
201 static SbxVariableRef PlusMinus( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf )
203 const sal_Unicode* p = *ppBuf;
204 SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) );
205 p = SkipWhitespace( p );
206 while( refVar.is() && ( *p == '+' || *p == '-' ) )
208 sal_Unicode cOp = *p++;
209 SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) );
210 if( refVar2.is() )
212 // temporary Variable!
213 SbxVariable* pVar = refVar.get();
214 pVar = new SbxVariable( *pVar );
215 refVar = pVar;
216 if( cOp == '+' )
217 *refVar += *refVar2;
218 else
219 *refVar -= *refVar2;
221 else
223 refVar.clear();
224 break;
227 *ppBuf = p;
228 return refVar;
231 static SbxVariableRef Assign( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf )
233 const sal_Unicode* p = *ppBuf;
234 SbxVariableRef refVar( Operand( pObj, pGbl, &p, true ) );
235 p = SkipWhitespace( p );
236 if( refVar.is() )
238 if( *p == '=' )
240 // Assign only onto properties!
241 if( refVar->GetClass() != SbxClassType::Property )
243 SbxBase::SetError( ERRCODE_BASIC_BAD_ACTION );
244 refVar.clear();
246 else
248 p++;
249 SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) );
250 if( refVar2.is() )
252 SbxVariable* pVar = refVar.get();
253 SbxVariable* pVar2 = refVar2.get();
254 *pVar = *pVar2;
255 pVar->SetParameters( nullptr );
259 else
260 // Simple call: once activating
261 refVar->Broadcast( SfxHintId::BasicDataWanted );
263 *ppBuf = p;
264 return refVar;
267 // Read in of an element. This is a symbol, optional followed
268 // by a parameter list. The symbol will be searched in the
269 // specified object and the parameter list will be attached if necessary.
271 static SbxVariableRef Element
272 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
273 SbxClassType t )
275 OUString aSym;
276 const sal_Unicode* p = Symbol( *ppBuf, aSym );
277 SbxVariableRef refVar;
278 if( !aSym.isEmpty() )
280 SbxFlagBits nOld = pObj->GetFlags();
281 if( pObj == pGbl )
283 pObj->SetFlag( SbxFlagBits::GlobalSearch );
285 refVar = pObj->Find( aSym, t );
286 pObj->SetFlags( nOld );
287 if( refVar.is() )
289 refVar->SetParameters( nullptr );
290 // Follow still parameter?
291 p = SkipWhitespace( p );
292 if( *p == '(' )
294 p++;
295 auto refPar = tools::make_ref<SbxArray>();
296 sal_uInt16 nArg = 0;
297 // We are once relaxed and accept as well
298 // the line- or command end as delimiter
299 // Search parameter always global!
300 while( *p && *p != ')' && *p != ']' )
302 SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p );
303 if( !refArg.is() )
305 // Error during the parsing
306 refVar.clear(); break;
308 else
310 // One copies the parameter, so that
311 // one have the current status (triggers also
312 // the call per access)
313 refPar->Put( new SbxVariable( *refArg ), ++nArg );
315 p = SkipWhitespace( p );
316 if( *p == ',' )
317 p++;
319 if( *p == ')' )
320 p++;
321 if( refVar.is() )
322 refVar->SetParameters( refPar.get() );
325 else
326 SbxBase::SetError( ERRCODE_BASIC_NO_METHOD );
328 *ppBuf = p;
329 return refVar;
332 // Mainroutine
334 SbxVariable* SbxObject::Execute( const OUString& rTxt )
336 SbxVariableRef pVar;
337 const sal_Unicode* p = rTxt.getStr();
338 for( ;; )
340 p = SkipWhitespace( p );
341 if( !*p )
343 break;
345 if( *p++ != '[' )
347 SetError( ERRCODE_BASIC_SYNTAX ); break;
349 pVar = Assign( this, this, &p );
350 if( !pVar.is() )
352 break;
354 p = SkipWhitespace( p );
355 if( *p++ != ']' )
357 SetError( ERRCODE_BASIC_SYNTAX ); break;
360 return pVar.get();
363 SbxVariable* SbxObject::FindQualified( const OUString& rName, SbxClassType t )
365 SbxVariableRef pVar;
366 const sal_Unicode* p = rName.getStr();
367 p = SkipWhitespace( p );
368 if( !*p )
370 return nullptr;
372 pVar = QualifiedName( this, this, &p, t );
373 p = SkipWhitespace( p );
374 if( *p )
376 SetError( ERRCODE_BASIC_SYNTAX );
378 return pVar.get();
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */