1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 #include <tools/errcode.hxx>
27 #ifndef _APP_HXX //autogen
28 #include <vcl/svapp.hxx>
29 #endif
30 #include <basic/sbx.hxx>
31
32
33 class SbxSimpleCharClass
34 {
35 public:
isAlpha(sal_Unicode c) const36 sal_Bool isAlpha( sal_Unicode c ) const
37 {
38 sal_Bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
39 return bRet;
40 }
41
isDigit(sal_Unicode c) const42 sal_Bool isDigit( sal_Unicode c ) const
43 {
44 sal_Bool bRet = (c >= '0' && c <= '9');
45 return bRet;
46 }
47
isAlphaNumeric(sal_Unicode c) const48 sal_Bool isAlphaNumeric( sal_Unicode c ) const
49 {
50 sal_Bool bRet = isDigit( c ) || isAlpha( c );
51 return bRet;
52 }
53 };
54
55
56 static SbxVariable* Element
57 ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf,
58 SbxClassType, const SbxSimpleCharClass& rCharClass );
59
SkipWhitespace(const xub_Unicode * p)60 static const xub_Unicode* SkipWhitespace( const xub_Unicode* p )
61 {
62 while( *p && ( *p == ' ' || *p == '\t' ) )
63 p++;
64 return p;
65 }
66
67 // Scannen eines Symbol. Das Symbol wird in rSym eingetragen, der Returnwert
68 // ist die neue Scanposition. Bei Fehlern ist das Symbol leer.
69
Symbol(const xub_Unicode * p,XubString & rSym,const SbxSimpleCharClass & rCharClass)70 static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass )
71 {
72 sal_uInt16 nLen = 0;
73 // Haben wir ein Sondersymbol?
74 if( *p == '[' )
75 {
76 rSym = ++p;
77 while( *p && *p != ']' )
78 p++, nLen++;
79 p++;
80 }
81 else
82 {
83 // Ein Symbol muss mit einem Buchstaben oder einem Underline beginnen
84 if( !rCharClass.isAlpha( *p ) && *p != '_' )
85 SbxBase::SetError( SbxERR_SYNTAX );
86 else
87 {
88 rSym = p;
89 // Dann darf es Buchstaben, Zahlen oder Underlines enthalten
90 while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') )
91 p++, nLen++;
92 // BASIC-Standard-Suffixe werden ignoriert
93 if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
94 p++;
95 }
96 }
97 rSym.Erase( nLen );
98 return p;
99 }
100
101 // Qualifizierter Name. Element.Element....
102
QualifiedName(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf,SbxClassType t)103 static SbxVariable* QualifiedName
104 ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, SbxClassType t )
105 {
106 static SbxSimpleCharClass aCharClass;
107
108 SbxVariableRef refVar;
109 const xub_Unicode* p = SkipWhitespace( *ppBuf );
110 if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' )
111 {
112 // Element einlesen
113 refVar = Element( pObj, pGbl, &p, t, aCharClass );
114 while( refVar.Is() && (*p == '.' || *p == '!') )
115 {
116 // Es folgt noch ein Objektelement. Das aktuelle Element
117 // muss also ein SBX-Objekt sein oder liefern!
118 pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar);
119 if( !pObj )
120 // Dann muss es ein Objekt liefern
121 pObj = PTR_CAST(SbxObject,refVar->GetObject());
122 refVar.Clear();
123 if( !pObj )
124 break;
125 p++;
126 // Und das naechste Element bitte
127 refVar = Element( pObj, pGbl, &p, t, aCharClass );
128 }
129 }
130 else
131 SbxBase::SetError( SbxERR_SYNTAX );
132 *ppBuf = p;
133 if( refVar.Is() )
134 refVar->AddRef();
135 return refVar;
136 }
137
138 // Einlesen eines Operanden. Dies kann eine Zahl, ein String oder
139 // eine Funktion (mit optionalen Parametern) sein.
140
Operand(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf,sal_Bool bVar)141 static SbxVariable* Operand
142 ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, sal_Bool bVar )
143 {
144 static SbxSimpleCharClass aCharClass;
145
146 SbxVariableRef refVar( new SbxVariable );
147 const xub_Unicode* p = SkipWhitespace( *ppBuf );
148 if( !bVar && ( aCharClass.isDigit( *p )
149 || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) )
150 || *p == '-'
151 || *p == '&' ) )
152 {
153 // Eine Zahl kann direkt eingescant werden!
154 sal_uInt16 nLen;
155 if( !refVar->Scan( XubString( p ), &nLen ) )
156 refVar.Clear();
157 else
158 p += nLen;
159 }
160 else if( !bVar && *p == '"' )
161 {
162 // Ein String
163 XubString aString;
164 p++;
165 for( ;; )
166 {
167 // Das ist wohl ein Fehler
168 if( !*p )
169 return NULL;
170 // Doppelte Quotes sind OK
171 if( *p == '"' )
172 if( *++p != '"' )
173 break;
174 aString += *p++;
175 }
176 refVar->PutString( aString );
177 }
178 else
179 refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE );
180 *ppBuf = p;
181 if( refVar.Is() )
182 refVar->AddRef();
183 return refVar;
184 }
185
186 // Einlesen einer einfachen Term. Die Operatoren +, -, * und /
187 // werden unterstuetzt.
188
MulDiv(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf)189 static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
190 {
191 const xub_Unicode* p = *ppBuf;
192 SbxVariableRef refVar( Operand( pObj, pGbl, &p, sal_False ) );
193 p = SkipWhitespace( p );
194 while( refVar.Is() && ( *p == '*' || *p == '/' ) )
195 {
196 xub_Unicode cOp = *p++;
197 SbxVariableRef refVar2( Operand( pObj, pGbl, &p, sal_False ) );
198 if( refVar2.Is() )
199 {
200 // temporaere Variable!
201 SbxVariable* pVar = refVar;
202 pVar = new SbxVariable( *pVar );
203 refVar = pVar;
204 if( cOp == '*' )
205 *refVar *= *refVar2;
206 else
207 *refVar /= *refVar2;
208 }
209 else
210 {
211 refVar.Clear();
212 break;
213 }
214 }
215 *ppBuf = p;
216 if( refVar.Is() )
217 refVar->AddRef();
218 return refVar;
219 }
220
PlusMinus(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf)221 static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
222 {
223 const xub_Unicode* p = *ppBuf;
224 SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) );
225 p = SkipWhitespace( p );
226 while( refVar.Is() && ( *p == '+' || *p == '-' ) )
227 {
228 xub_Unicode cOp = *p++;
229 SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) );
230 if( refVar2.Is() )
231 {
232 // temporaere Variable!
233 SbxVariable* pVar = refVar;
234 pVar = new SbxVariable( *pVar );
235 refVar = pVar;
236 if( cOp == '+' )
237 *refVar += *refVar2;
238 else
239 *refVar -= *refVar2;
240 }
241 else
242 {
243 refVar.Clear();
244 break;
245 }
246 }
247 *ppBuf = p;
248 if( refVar.Is() )
249 refVar->AddRef();
250 return refVar;
251 }
252
Assign(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf)253 static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
254 {
255 const xub_Unicode* p = *ppBuf;
256 SbxVariableRef refVar( Operand( pObj, pGbl, &p, sal_True ) );
257 p = SkipWhitespace( p );
258 if( refVar.Is() )
259 {
260 if( *p == '=' )
261 {
262 // Nur auf Props zuweisen!
263 if( refVar->GetClass() != SbxCLASS_PROPERTY )
264 {
265 SbxBase::SetError( SbxERR_BAD_ACTION );
266 refVar.Clear();
267 }
268 else
269 {
270 p++;
271 SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) );
272 if( refVar2.Is() )
273 {
274 SbxVariable* pVar = refVar;
275 SbxVariable* pVar2 = refVar2;
276 *pVar = *pVar2;
277 pVar->SetParameters( NULL );
278 }
279 }
280 }
281 else
282 // Einfacher Aufruf: einmal aktivieren
283 refVar->Broadcast( SBX_HINT_DATAWANTED );
284 }
285 *ppBuf = p;
286 if( refVar.Is() )
287 refVar->AddRef();
288 return refVar;
289 }
290
291 // Einlesen eines Elements. Dies ist ein Symbol, optional gefolgt
292 // von einer Parameterliste. Das Symbol wird im angegebenen Objekt
293 // gesucht und die Parameterliste wird ggf. angefuegt.
294
Element(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf,SbxClassType t,const SbxSimpleCharClass & rCharClass)295 static SbxVariable* Element
296 ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf,
297 SbxClassType t, const SbxSimpleCharClass& rCharClass )
298 {
299 XubString aSym;
300 const xub_Unicode* p = Symbol( *ppBuf, aSym, rCharClass );
301 SbxVariableRef refVar;
302 if( aSym.Len() )
303 {
304 sal_uInt16 nOld = pObj->GetFlags();
305 if( pObj == pGbl )
306 pObj->SetFlag( SBX_GBLSEARCH );
307 refVar = pObj->Find( aSym, t );
308 pObj->SetFlags( nOld );
309 if( refVar.Is() )
310 {
311 refVar->SetParameters( NULL );
312 // folgen noch Parameter?
313 p = SkipWhitespace( p );
314 if( *p == '(' )
315 {
316 p++;
317 SbxArrayRef refPar = new SbxArray;
318 sal_uInt16 nArg = 0;
319 // Wird sind mal relaxed und akzeptieren auch
320 // das Zeilen- oder Komandoende als Begrenzer
321 // Parameter immer global suchen!
322 while( *p && *p != ')' && *p != ']' )
323 {
324 SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p );
325 if( !refArg )
326 {
327 // Fehler beim Parsing
328 refVar.Clear(); break;
329 }
330 else
331 {
332 // Man kopiere den Parameter, damit
333 // man den aktuellen Zustand hat (loest auch
334 // den Aufruf per Zugriff aus)
335 SbxVariable* pArg = refArg;
336 refPar->Put( new SbxVariable( *pArg ), ++nArg );
337 }
338 p = SkipWhitespace( p );
339 if( *p == ',' )
340 p++;
341 }
342 if( *p == ')' )
343 p++;
344 if( refVar.Is() )
345 refVar->SetParameters( refPar );
346 }
347 }
348 else
349 SbxBase::SetError( SbxERR_NO_METHOD );
350 }
351 *ppBuf = p;
352 if( refVar.Is() )
353 refVar->AddRef();
354 return refVar;
355 }
356
357 // Hauptroutine
358
Execute(const XubString & rTxt)359 SbxVariable* SbxObject::Execute( const XubString& rTxt )
360 {
361 SbxVariable* pVar = NULL;
362 const xub_Unicode* p = rTxt.GetBuffer();
363 for( ;; )
364 {
365 p = SkipWhitespace( p );
366 if( !*p )
367 break;
368 if( *p++ != '[' )
369 {
370 SetError( SbxERR_SYNTAX ); break;
371 }
372 pVar = Assign( this, this, &p );
373 if( !pVar )
374 break;
375 p = SkipWhitespace( p );
376 if( *p++ != ']' )
377 {
378 SetError( SbxERR_SYNTAX ); break;
379 }
380 }
381 return pVar;
382 }
383
FindQualified(const XubString & rName,SbxClassType t)384 SbxVariable* SbxObject::FindQualified( const XubString& rName, SbxClassType t )
385 {
386 SbxVariable* pVar = NULL;
387 const xub_Unicode* p = rName.GetBuffer();
388 p = SkipWhitespace( p );
389 if( !*p )
390 return NULL;;
391 pVar = QualifiedName( this, this, &p, t );
392 p = SkipWhitespace( p );
393 if( *p )
394 SetError( SbxERR_SYNTAX );
395 return pVar;
396 }
397
398