LibreOffice Module basic (master) 1
sbxexec.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <basic/sbx.hxx>
23#include <basic/sberrors.hxx>
24#include <rtl/character.hxx>
25#include <rtl/ustrbuf.hxx>
26
27#include <basiccharclass.hxx>
28
30 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
31 SbxClassType, bool bCompatible );
32
33static const sal_Unicode* SkipWhitespace( const sal_Unicode* p )
34{
36 p++;
37 return p;
38}
39
40// Scanning of a symbol. The symbol were inserted in rSym, the return value
41// is the new scan position. The symbol is at errors empty.
42
43static const sal_Unicode* Symbol( const sal_Unicode* p, OUString& rSym, bool bCompatible )
44{
45 sal_uInt16 nLen = 0;
46 // Did we have a nonstandard symbol?
47 if( *p == '[' )
48 {
49 rSym = ++p;
50 while( *p && *p != ']' )
51 {
52 p++;
53 nLen++;
54 }
55 p++;
56 }
57 else
58 {
59 // A symbol had to begin with an alphabetic character or an underline
60 if( !BasicCharClass::isAlpha( *p, bCompatible ) && *p != '_' )
61 {
63 }
64 else
65 {
66 rSym = p;
67 // The it can contain alphabetic characters, numbers or underlines
68 while( *p && (BasicCharClass::isAlphaNumeric( *p, bCompatible ) || *p == '_') )
69 {
70 p++;
71 nLen++;
72 }
73 // Ignore standard BASIC suffixes
74 if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
75 {
76 p++;
77 }
78 }
79 }
80 rSym = rSym.copy( 0, nLen );
81 return p;
82}
83
84// Qualified name. Element.Element...
85
87 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, SbxClassType t, bool bCompatible )
88{
89
90 SbxVariableRef refVar;
91 const sal_Unicode* p = SkipWhitespace( *ppBuf );
92 if( BasicCharClass::isAlpha( *p, bCompatible ) || *p == '_' || *p == '[' )
93 {
94 // Read in the element
95 refVar = Element( pObj, pGbl, &p, t, bCompatible );
96 while( refVar.is() && (*p == '.' || *p == '!') )
97 {
98 // It follows still an objectelement. The current element
99 // had to be a SBX-Object or had to deliver such an object!
100 pObj = dynamic_cast<SbxObject*>( refVar.get() );
101 if( !pObj )
102 // Then it had to deliver an object
103 pObj = dynamic_cast<SbxObject*>( refVar->GetObject() );
104 refVar.clear();
105 if( !pObj )
106 break;
107 p++;
108 // And the next element please
109 refVar = Element( pObj, pGbl, &p, t, bCompatible );
110 }
111 }
112 else
114 *ppBuf = p;
115 return refVar;
116}
117
118// Read in of an operand. This could be a number, a string or
119// a function (with optional parameters).
120
122 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bVar, bool bCompatible )
123{
124 SbxVariableRef refVar( new SbxVariable );
125 const sal_Unicode* p = SkipWhitespace( *ppBuf );
126 if( !bVar && ( rtl::isAsciiDigit( *p )
127 || ( *p == '.' && rtl::isAsciiDigit( *( p+1 ) ) )
128 || *p == '-'
129 || *p == '&' ) )
130 {
131 // A number could be scanned in directly!
132 sal_uInt16 nLen;
133 if( !refVar->Scan( OUString( p ), &nLen ) )
134 {
135 refVar.clear();
136 }
137 else
138 {
139 p += nLen;
140 }
141 }
142 else if( !bVar && *p == '"' )
143 {
144 // A string
145 OUStringBuffer aString;
146 p++;
147 for( ;; )
148 {
149 // This is perhaps an error
150 if( !*p )
151 {
152 return nullptr;
153 }
154 // Double quotes are OK
155 if( *p == '"' && (*++p) != '"' )
156 {
157 break;
158 }
159 aString.append(*p++);
160 }
161 refVar->PutString( aString.makeStringAndClear() );
162 }
163 else
164 {
165 refVar = QualifiedName( pObj, pGbl, &p, SbxClassType::DontCare, bCompatible );
166 }
167 *ppBuf = p;
168 return refVar;
169}
170
171// Read in of a simple term. The operands +, -, * and /
172// are supported.
173
174static SbxVariableRef MulDiv( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bCompatible )
175{
176 const sal_Unicode* p = *ppBuf;
177 SbxVariableRef refVar( Operand( pObj, pGbl, &p, false, bCompatible ) );
178 p = SkipWhitespace( p );
179 while( refVar.is() && ( *p == '*' || *p == '/' ) )
180 {
181 sal_Unicode cOp = *p++;
182 SbxVariableRef refVar2( Operand( pObj, pGbl, &p, false, bCompatible ) );
183 if( refVar2.is() )
184 {
185 // temporary variable!
186 SbxVariable* pVar = refVar.get();
187 pVar = new SbxVariable( *pVar );
188 refVar = pVar;
189 if( cOp == '*' )
190 *refVar *= *refVar2;
191 else
192 *refVar /= *refVar2;
193 }
194 else
195 {
196 refVar.clear();
197 break;
198 }
199 }
200 *ppBuf = p;
201 return refVar;
202}
203
204static SbxVariableRef PlusMinus( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bCompatible )
205{
206 const sal_Unicode* p = *ppBuf;
207 SbxVariableRef refVar( MulDiv( pObj, pGbl, &p, bCompatible ) );
208 p = SkipWhitespace( p );
209 while( refVar.is() && ( *p == '+' || *p == '-' ) )
210 {
211 sal_Unicode cOp = *p++;
212 SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p, bCompatible ) );
213 if( refVar2.is() )
214 {
215 // temporary Variable!
216 SbxVariable* pVar = refVar.get();
217 pVar = new SbxVariable( *pVar );
218 refVar = pVar;
219 if( cOp == '+' )
220 *refVar += *refVar2;
221 else
222 *refVar -= *refVar2;
223 }
224 else
225 {
226 refVar.clear();
227 break;
228 }
229 }
230 *ppBuf = p;
231 return refVar;
232}
233
234static SbxVariableRef Assign( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bCompatible )
235{
236 const sal_Unicode* p = *ppBuf;
237 SbxVariableRef refVar( Operand( pObj, pGbl, &p, true, bCompatible ) );
238 p = SkipWhitespace( p );
239 if( refVar.is() )
240 {
241 if( *p == '=' )
242 {
243 // Assign only onto properties!
244 if( refVar->GetClass() != SbxClassType::Property )
245 {
247 refVar.clear();
248 }
249 else
250 {
251 p++;
252 SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p, bCompatible ) );
253 if( refVar2.is() )
254 {
255 SbxVariable* pVar = refVar.get();
256 SbxVariable* pVar2 = refVar2.get();
257 *pVar = *pVar2;
258 pVar->SetParameters( nullptr );
259 }
260 }
261 }
262 else
263 // Simple call: once activating
264 refVar->Broadcast( SfxHintId::BasicDataWanted );
265 }
266 *ppBuf = p;
267 return refVar;
268}
269
270// Read in of an element. This is a symbol, optional followed
271// by a parameter list. The symbol will be searched in the
272// specified object and the parameter list will be attached if necessary.
273
275 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
276 SbxClassType t, bool bCompatible )
277{
278 OUString aSym;
279 const sal_Unicode* p = Symbol( *ppBuf, aSym, bCompatible );
280 SbxVariableRef refVar;
281 if( !aSym.isEmpty() )
282 {
283 SbxFlagBits nOld = pObj->GetFlags();
284 if( pObj == pGbl )
285 {
287 }
288 refVar = pObj->Find( aSym, t );
289 pObj->SetFlags( nOld );
290 if( refVar.is() )
291 {
292 refVar->SetParameters( nullptr );
293 // Follow still parameter?
294 p = SkipWhitespace( p );
295 if( *p == '(' )
296 {
297 p++;
298 auto refPar = tools::make_ref<SbxArray>();
299 sal_uInt32 nArg = 0;
300 // We are once relaxed and accept as well
301 // the line- or command end as delimiter
302 // Search parameter always global!
303 while( *p && *p != ')' && *p != ']' )
304 {
305 SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p, bCompatible );
306 if( !refArg.is() )
307 {
308 // Error during the parsing
309 refVar.clear(); break;
310 }
311 else
312 {
313 // One copies the parameter, so that
314 // one have the current status (triggers also
315 // the call per access)
316 refPar->Put(new SbxVariable(*refArg), ++nArg);
317 }
318 p = SkipWhitespace( p );
319 if( *p == ',' )
320 p++;
321 }
322 if( *p == ')' )
323 p++;
324 if( refVar.is() )
325 refVar->SetParameters( refPar.get() );
326 }
327 }
328 else
330 }
331 *ppBuf = p;
332 return refVar;
333}
334
335// Mainroutine
336
337SbxVariable* SbxObject::Execute( const OUString& rTxt )
338{
339 SbxVariableRef pVar;
340 const sal_Unicode* p = rTxt.getStr();
341 for( ;; )
342 {
343 p = SkipWhitespace( p );
344 if( !*p )
345 {
346 break;
347 }
348 if( *p++ != '[' )
349 {
351 }
352 pVar = Assign( this, this, &p, IsOptionCompatible() );
353 if( !pVar.is() )
354 {
355 break;
356 }
357 p = SkipWhitespace( p );
358 if( *p++ != ']' )
359 {
361 }
362 }
363 return pVar.get();
364}
365
367{
368 SbxVariableRef pVar;
369 const sal_Unicode* p = rName.getStr();
370 p = SkipWhitespace( p );
371 if( !*p )
372 {
373 return nullptr;
374 }
375 pVar = QualifiedName( this, this, &p, t, IsOptionCompatible() );
376 p = SkipWhitespace( p );
377 if( *p )
378 {
380 }
381 return pVar.get();
382}
383
385{
386 if (const SbxObject* pObj = GetParent())
387 return pObj->IsOptionCompatible();
388 return false;
389}
390
391/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
static void SetError(ErrCode)
Definition: sbxbase.cxx:116
void SetFlags(SbxFlagBits n)
Definition: sbxcore.hxx:102
void SetFlag(SbxFlagBits n)
Definition: sbxcore.hxx:108
SbxFlagBits GetFlags() const
Definition: sbxcore.hxx:105
SbxVariable * Execute(const OUString &)
Definition: sbxexec.cxx:337
virtual bool IsOptionCompatible() const
Definition: sbxexec.cxx:384
virtual SbxVariable * Find(const OUString &, SbxClassType)
Definition: sbxobj.cxx:182
SbxVariable * FindQualified(const OUString &, SbxClassType)
Definition: sbxexec.cxx:366
const SbxObject * GetParent() const
Definition: sbxvar.hxx:296
void SetParameters(SbxArray *p)
Definition: sbxvar.cxx:178
T * get() const
bool is() const
void * p
bool isAlpha(sal_Unicode c, bool bCompatible)
bool isWhitespace(sal_Unicode c)
bool isAlphaNumeric(sal_Unicode c, bool bCompatible)
#define ERRCODE_BASIC_BAD_ACTION
Definition: sberrors.hxx:47
#define ERRCODE_BASIC_NO_METHOD
Definition: sberrors.hxx:42
#define ERRCODE_BASIC_SYNTAX
Definition: sberrors.hxx:25
SbxClassType
Definition: sbxdef.hxx:27
SbxFlagBits
Definition: sbxdef.hxx:131
static SbxVariableRef PlusMinus(SbxObject *pObj, SbxObject *pGbl, const sal_Unicode **ppBuf, bool bCompatible)
Definition: sbxexec.cxx:204
static SbxVariableRef MulDiv(SbxObject *pObj, SbxObject *pGbl, const sal_Unicode **ppBuf, bool bCompatible)
Definition: sbxexec.cxx:174
static const sal_Unicode * SkipWhitespace(const sal_Unicode *p)
Definition: sbxexec.cxx:33
static SbxVariableRef Assign(SbxObject *pObj, SbxObject *pGbl, const sal_Unicode **ppBuf, bool bCompatible)
Definition: sbxexec.cxx:234
static SbxVariableRef Operand(SbxObject *pObj, SbxObject *pGbl, const sal_Unicode **ppBuf, bool bVar, bool bCompatible)
Definition: sbxexec.cxx:122
static const sal_Unicode * Symbol(const sal_Unicode *p, OUString &rSym, bool bCompatible)
Definition: sbxexec.cxx:43
static SbxVariableRef Element(SbxObject *pObj, SbxObject *pGbl, const sal_Unicode **ppBuf, SbxClassType, bool bCompatible)
Definition: sbxexec.cxx:275
static SbxVariableRef QualifiedName(SbxObject *pObj, SbxObject *pGbl, const sal_Unicode **ppBuf, SbxClassType t, bool bCompatible)
Definition: sbxexec.cxx:87
sal_uInt16 sal_Unicode