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