Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / basic / source / sbx / sbxexec.cxx
blob3eaaecf8b7c2a76872d3692936d25efed0f74ee3
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 <tools/errcode.hxx>
21 #include <vcl/svapp.hxx>
22 #include <basic/sbx.hxx>
25 class SbxSimpleCharClass
27 public:
28 bool isAlpha( sal_Unicode c ) const
30 bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
31 return bRet;
34 bool isDigit( sal_Unicode c ) const
36 bool bRet = (c >= '0' && c <= '9');
37 return bRet;
40 bool isAlphaNumeric( sal_Unicode c ) const
42 bool bRet = isDigit( c ) || isAlpha( c );
43 return bRet;
48 static SbxVariable* Element
49 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
50 SbxClassType, const SbxSimpleCharClass& rCharClass );
52 static const sal_Unicode* SkipWhitespace( const sal_Unicode* p )
54 while( *p && ( *p == ' ' || *p == '\t' ) )
55 p++;
56 return p;
59 // Scanning of a symbol. The symbol were inserted in rSym, the return value
60 // is the new scan position. The symbol is at errors empty.
62 static const sal_Unicode* Symbol( const sal_Unicode* p, OUString& rSym, const SbxSimpleCharClass& rCharClass )
64 sal_uInt16 nLen = 0;
65 // Did we have a nonstandard symbol?
66 if( *p == '[' )
68 rSym = ++p;
69 while( *p && *p != ']' )
71 p++, nLen++;
73 p++;
75 else
77 // A symbol had to begin with a alphabetic character or an underline
78 if( !rCharClass.isAlpha( *p ) && *p != '_' )
80 SbxBase::SetError( SbxERR_SYNTAX );
82 else
84 rSym = p;
85 // The it can contain alphabetic characters, numbers or underlines
86 while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') )
88 p++, nLen++;
90 // BASIC-Standard-Suffixes were ignored
91 if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
93 p++;
97 rSym = rSym.copy( 0, nLen );
98 return p;
101 // Qualified name. Element.Element....
103 static SbxVariable* QualifiedName
104 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, SbxClassType t )
106 static SbxSimpleCharClass aCharClass;
108 SbxVariableRef refVar;
109 const sal_Unicode* p = SkipWhitespace( *ppBuf );
110 if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' )
112 // Read in the element
113 refVar = Element( pObj, pGbl, &p, t, aCharClass );
114 while( refVar.Is() && (*p == '.' || *p == '!') )
116 // It follows still an objectelement. The current element
117 // had to be a SBX-Object or had to deliver such an object!
118 pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar);
119 if( !pObj )
120 // Then it had to deliver an object
121 pObj = PTR_CAST(SbxObject,refVar->GetObject());
122 refVar.Clear();
123 if( !pObj )
124 break;
125 p++;
126 // And the next element please
127 refVar = Element( pObj, pGbl, &p, t, aCharClass );
130 else
131 SbxBase::SetError( SbxERR_SYNTAX );
132 *ppBuf = p;
133 if( refVar.Is() )
134 refVar->AddRef();
135 return refVar;
138 // Read in of an operand. This could be a number, a string or
139 // a function (with optional parameters).
141 static SbxVariable* Operand
142 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf, bool bVar )
144 static SbxSimpleCharClass aCharClass;
146 SbxVariableRef refVar( new SbxVariable );
147 const sal_Unicode* p = SkipWhitespace( *ppBuf );
148 if( !bVar && ( aCharClass.isDigit( *p )
149 || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) )
150 || *p == '-'
151 || *p == '&' ) )
153 // A number could be scanned in directly!
154 sal_uInt16 nLen;
155 if( !refVar->Scan( OUString( p ), &nLen ) )
157 refVar.Clear();
159 else
161 p += nLen;
164 else if( !bVar && *p == '"' )
166 // A string
167 OUString aString;
168 p++;
169 for( ;; )
171 // This is perhaps an error
172 if( !*p )
174 return NULL;
176 // Double quotes are OK
177 if( *p == '"' )
179 if( *++p != '"' )
181 break;
184 aString += OUString(*p++);
186 refVar->PutString( aString );
188 else
190 refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE );
192 *ppBuf = p;
193 if( refVar.Is() )
194 refVar->AddRef();
195 return refVar;
198 // Read in of a simple term. The operands +, -, * and /
199 // are supported.
201 static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf )
203 const sal_Unicode* p = *ppBuf;
204 SbxVariableRef refVar( Operand( pObj, pGbl, &p, false ) );
205 p = SkipWhitespace( p );
206 while( refVar.Is() && ( *p == '*' || *p == '/' ) )
208 sal_Unicode cOp = *p++;
209 SbxVariableRef refVar2( Operand( pObj, pGbl, &p, false ) );
210 if( refVar2.Is() )
212 // temporary variable!
213 SbxVariable* pVar = refVar;
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 if( refVar.Is() )
229 refVar->AddRef();
230 return refVar;
233 static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf )
235 const sal_Unicode* p = *ppBuf;
236 SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) );
237 p = SkipWhitespace( p );
238 while( refVar.Is() && ( *p == '+' || *p == '-' ) )
240 sal_Unicode cOp = *p++;
241 SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) );
242 if( refVar2.Is() )
244 // temporaere Variable!
245 SbxVariable* pVar = refVar;
246 pVar = new SbxVariable( *pVar );
247 refVar = pVar;
248 if( cOp == '+' )
249 *refVar += *refVar2;
250 else
251 *refVar -= *refVar2;
253 else
255 refVar.Clear();
256 break;
259 *ppBuf = p;
260 if( refVar.Is() )
261 refVar->AddRef();
262 return refVar;
265 static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf )
267 const sal_Unicode* p = *ppBuf;
268 SbxVariableRef refVar( Operand( pObj, pGbl, &p, true ) );
269 p = SkipWhitespace( p );
270 if( refVar.Is() )
272 if( *p == '=' )
274 // Assign only onto properties!
275 if( refVar->GetClass() != SbxCLASS_PROPERTY )
277 SbxBase::SetError( SbxERR_BAD_ACTION );
278 refVar.Clear();
280 else
282 p++;
283 SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) );
284 if( refVar2.Is() )
286 SbxVariable* pVar = refVar;
287 SbxVariable* pVar2 = refVar2;
288 *pVar = *pVar2;
289 pVar->SetParameters( NULL );
293 else
294 // Simple call: once activating
295 refVar->Broadcast( SBX_HINT_DATAWANTED );
297 *ppBuf = p;
298 if( refVar.Is() )
299 refVar->AddRef();
300 return refVar;
303 // Read in of an element. This is a symbol, optional followed
304 // by a parameter list. The symbol will be searched in the
305 // specified object and the parameter list will be attached if necessary.
307 static SbxVariable* Element
308 ( SbxObject* pObj, SbxObject* pGbl, const sal_Unicode** ppBuf,
309 SbxClassType t, const SbxSimpleCharClass& rCharClass )
311 OUString aSym;
312 const sal_Unicode* p = Symbol( *ppBuf, aSym, rCharClass );
313 SbxVariableRef refVar;
314 if( !aSym.isEmpty() )
316 sal_uInt16 nOld = pObj->GetFlags();
317 if( pObj == pGbl )
319 pObj->SetFlag( SBX_GBLSEARCH );
321 refVar = pObj->Find( aSym, t );
322 pObj->SetFlags( nOld );
323 if( refVar.Is() )
325 refVar->SetParameters( NULL );
326 // Follow still parameter?
327 p = SkipWhitespace( p );
328 if( *p == '(' )
330 p++;
331 SbxArrayRef refPar = new SbxArray;
332 sal_uInt16 nArg = 0;
333 // We are once relaxed and accept as well
334 // the line- or commandend as delimiter
335 // Search parameter always global!
336 while( *p && *p != ')' && *p != ']' )
338 SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p );
339 if( !refArg )
341 // Error during the parsing
342 refVar.Clear(); break;
344 else
346 // One copies the parameter, so that
347 // one have the current status (triggers also
348 // the call per access)
349 SbxVariable* pArg = refArg;
350 refPar->Put( new SbxVariable( *pArg ), ++nArg );
352 p = SkipWhitespace( p );
353 if( *p == ',' )
354 p++;
356 if( *p == ')' )
357 p++;
358 if( refVar.Is() )
359 refVar->SetParameters( refPar );
362 else
363 SbxBase::SetError( SbxERR_NO_METHOD );
365 *ppBuf = p;
366 if( refVar.Is() )
367 refVar->AddRef();
368 return refVar;
371 // Mainroutine
373 SbxVariable* SbxObject::Execute( const OUString& rTxt )
375 SbxVariable* pVar = NULL;
376 const sal_Unicode* p = rTxt.getStr();
377 for( ;; )
379 p = SkipWhitespace( p );
380 if( !*p )
382 break;
384 if( *p++ != '[' )
386 SetError( SbxERR_SYNTAX ); break;
388 pVar = Assign( this, this, &p );
389 if( !pVar )
391 break;
393 p = SkipWhitespace( p );
394 if( *p++ != ']' )
396 SetError( SbxERR_SYNTAX ); break;
399 return pVar;
402 SbxVariable* SbxObject::FindQualified( const OUString& rName, SbxClassType t )
404 SbxVariable* pVar = NULL;
405 const sal_Unicode* p = rName.getStr();
406 p = SkipWhitespace( p );
407 if( !*p )
409 return NULL;;
411 pVar = QualifiedName( this, this, &p, t );
412 p = SkipWhitespace( p );
413 if( *p )
415 SetError( SbxERR_SYNTAX );
417 return pVar;
420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */