Branch data Line data Source code
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 <tools/errcode.hxx>
21 : : #include <vcl/svapp.hxx>
22 : : #include <basic/sbx.hxx>
23 : :
24 : :
25 : : class SbxSimpleCharClass
26 : : {
27 : : public:
28 : 1272 : bool isAlpha( sal_Unicode c ) const
29 : : {
30 [ + + ][ - + ]: 1272 : bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
[ + + ][ + + ]
31 : 1272 : return bRet;
32 : : }
33 : :
34 : 1164 : bool isDigit( sal_Unicode c ) const
35 : : {
36 [ + + ][ - + ]: 1164 : bool bRet = (c >= '0' && c <= '9');
37 : 1164 : return bRet;
38 : : }
39 : :
40 : 1164 : bool isAlphaNumeric( sal_Unicode c ) const
41 : : {
42 [ + - ][ + + ]: 1164 : bool bRet = isDigit( c ) || isAlpha( c );
43 : 1164 : return bRet;
44 : : }
45 : : };
46 : :
47 : :
48 : : static SbxVariable* Element
49 : : ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf,
50 : : SbxClassType, const SbxSimpleCharClass& rCharClass );
51 : :
52 : 180 : static const xub_Unicode* SkipWhitespace( const xub_Unicode* p )
53 : : {
54 [ + + ][ + - ]: 180 : while( *p && ( *p == ' ' || *p == '\t' ) )
[ - + ][ - + ]
55 : 0 : p++;
56 : 180 : return p;
57 : : }
58 : :
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.
61 : :
62 : 72 : static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass )
63 : : {
64 : 72 : sal_uInt16 nLen = 0;
65 : : // Did we have a nonstandard symbol?
66 [ - + ]: 72 : if( *p == '[' )
67 : : {
68 : 0 : rSym = ++p;
69 [ # # ][ # # ]: 0 : while( *p && *p != ']' )
[ # # ]
70 : 0 : p++, nLen++;
71 : 0 : p++;
72 : : }
73 : : else
74 : : {
75 : : // A symbol had to begin with a alphabetic character or an underline
76 [ - + ][ # # ]: 72 : if( !rCharClass.isAlpha( *p ) && *p != '_' )
[ - + ]
77 : 0 : SbxBase::SetError( SbxERR_SYNTAX );
78 : : else
79 : : {
80 : 72 : rSym = p;
81 : : // The it can contain alphabetic characters, numbers or underlines
82 [ + + ][ + + ]: 1200 : while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') )
[ + + ][ + + ]
83 : 1128 : p++, nLen++;
84 : : // BASIC-Standard-Suffixes were ignored
85 [ + + ][ + - ]: 72 : if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
[ + - ][ + - ]
[ + - ][ - + ]
86 : 0 : p++;
87 : : }
88 : : }
89 : 72 : rSym.Erase( nLen );
90 : 72 : return p;
91 : : }
92 : :
93 : : // Qualified name. Element.Element....
94 : :
95 : 36 : static SbxVariable* QualifiedName
96 : : ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, SbxClassType t )
97 : : {
98 : : static SbxSimpleCharClass aCharClass;
99 : :
100 : 36 : SbxVariableRef refVar;
101 : 36 : const xub_Unicode* p = SkipWhitespace( *ppBuf );
102 [ # # ][ # # ]: 36 : if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' )
[ + - ][ - + ]
103 : : {
104 : : // Read in the element
105 [ + - ][ + - ]: 36 : refVar = Element( pObj, pGbl, &p, t, aCharClass );
106 [ + - ][ + + ]: 72 : while( refVar.Is() && (*p == '.' || *p == '!') )
[ - + ][ + + ]
107 : : {
108 : : // It follows still an objectelement. The current element
109 : : // had to be a SBX-Object or had to deliver such an object!
110 [ + - ][ + - ]: 36 : pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar);
[ + - ][ + - ]
111 [ - + ]: 36 : if( !pObj )
112 : : // Then it had to deliver an object
113 [ # # ][ # # ]: 0 : pObj = PTR_CAST(SbxObject,refVar->GetObject());
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
114 [ + - ]: 36 : refVar.Clear();
115 [ - + ]: 36 : if( !pObj )
116 : 0 : break;
117 : 36 : p++;
118 : : // And the next element please
119 [ + - ][ + - ]: 36 : refVar = Element( pObj, pGbl, &p, t, aCharClass );
120 : : }
121 : : }
122 : : else
123 [ # # ]: 0 : SbxBase::SetError( SbxERR_SYNTAX );
124 : 36 : *ppBuf = p;
125 [ + - ]: 36 : if( refVar.Is() )
126 : 36 : refVar->AddRef();
127 [ + - ]: 36 : return refVar;
128 : : }
129 : :
130 : : // Read in of an operand. This could be a number, a string or
131 : : // a function (with optional parameters).
132 : :
133 : 0 : static SbxVariable* Operand
134 : : ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, bool bVar )
135 : : {
136 : : static SbxSimpleCharClass aCharClass;
137 : :
138 [ # # ][ # # ]: 0 : SbxVariableRef refVar( new SbxVariable );
139 : 0 : const xub_Unicode* p = SkipWhitespace( *ppBuf );
140 [ # # ]: 0 : if( !bVar && ( aCharClass.isDigit( *p )
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
141 : 0 : || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) )
142 : : || *p == '-'
143 : : || *p == '&' ) )
144 : : {
145 : : // A number could be scanned in directly!
146 : : sal_uInt16 nLen;
147 [ # # ][ # # ]: 0 : if( !refVar->Scan( rtl::OUString( p ), &nLen ) )
[ # # ][ # # ]
148 [ # # ]: 0 : refVar.Clear();
149 : : else
150 : 0 : p += nLen;
151 : : }
152 [ # # ][ # # ]: 0 : else if( !bVar && *p == '"' )
153 : : {
154 : : // A string
155 [ # # ]: 0 : XubString aString;
156 : 0 : p++;
157 : 0 : for( ;; )
158 : : {
159 : : // This is perhaps an error
160 [ # # ]: 0 : if( !*p )
161 : 0 : return NULL;
162 : : // Double quotes are OK
163 [ # # ]: 0 : if( *p == '"' )
164 [ # # ]: 0 : if( *++p != '"' )
165 : 0 : break;
166 [ # # ]: 0 : aString += *p++;
167 : : }
168 [ # # ][ # # ]: 0 : refVar->PutString( aString );
[ # # ][ # # ]
169 : : }
170 : : else
171 [ # # ][ # # ]: 0 : refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE );
172 : 0 : *ppBuf = p;
173 [ # # ]: 0 : if( refVar.Is() )
174 : 0 : refVar->AddRef();
175 [ # # ]: 0 : return refVar;
176 : : }
177 : :
178 : : // Read in of a simple term. The operands +, -, * and /
179 : : // are supported.
180 : :
181 : 0 : static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
182 : : {
183 : 0 : const xub_Unicode* p = *ppBuf;
184 [ # # ]: 0 : SbxVariableRef refVar( Operand( pObj, pGbl, &p, false ) );
185 : 0 : p = SkipWhitespace( p );
186 [ # # ][ # # ]: 0 : while( refVar.Is() && ( *p == '*' || *p == '/' ) )
[ # # ][ # # ]
187 : : {
188 : 0 : xub_Unicode cOp = *p++;
189 [ # # ]: 0 : SbxVariableRef refVar2( Operand( pObj, pGbl, &p, false ) );
190 [ # # ]: 0 : if( refVar2.Is() )
191 : : {
192 : : // temporary variable!
193 : 0 : SbxVariable* pVar = refVar;
194 [ # # ][ # # ]: 0 : pVar = new SbxVariable( *pVar );
195 [ # # ]: 0 : refVar = pVar;
196 [ # # ]: 0 : if( cOp == '*' )
197 [ # # ]: 0 : *refVar *= *refVar2;
198 : : else
199 [ # # ]: 0 : *refVar /= *refVar2;
200 : : }
201 : : else
202 : : {
203 [ # # ]: 0 : refVar.Clear();
204 : : break;
205 : : }
206 [ # # ][ # # ]: 0 : }
207 : 0 : *ppBuf = p;
208 [ # # ]: 0 : if( refVar.Is() )
209 : 0 : refVar->AddRef();
210 [ # # ]: 0 : return refVar;
211 : : }
212 : :
213 : 0 : static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
214 : : {
215 : 0 : const xub_Unicode* p = *ppBuf;
216 [ # # ]: 0 : SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) );
217 : 0 : p = SkipWhitespace( p );
218 [ # # ][ # # ]: 0 : while( refVar.Is() && ( *p == '+' || *p == '-' ) )
[ # # ][ # # ]
219 : : {
220 : 0 : xub_Unicode cOp = *p++;
221 [ # # ]: 0 : SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) );
222 [ # # ]: 0 : if( refVar2.Is() )
223 : : {
224 : : // temporaere Variable!
225 : 0 : SbxVariable* pVar = refVar;
226 [ # # ][ # # ]: 0 : pVar = new SbxVariable( *pVar );
227 [ # # ]: 0 : refVar = pVar;
228 [ # # ]: 0 : if( cOp == '+' )
229 [ # # ]: 0 : *refVar += *refVar2;
230 : : else
231 [ # # ]: 0 : *refVar -= *refVar2;
232 : : }
233 : : else
234 : : {
235 [ # # ]: 0 : refVar.Clear();
236 : : break;
237 : : }
238 [ # # ][ # # ]: 0 : }
239 : 0 : *ppBuf = p;
240 [ # # ]: 0 : if( refVar.Is() )
241 : 0 : refVar->AddRef();
242 [ # # ]: 0 : return refVar;
243 : : }
244 : :
245 : 0 : static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
246 : : {
247 : 0 : const xub_Unicode* p = *ppBuf;
248 [ # # ]: 0 : SbxVariableRef refVar( Operand( pObj, pGbl, &p, true ) );
249 : 0 : p = SkipWhitespace( p );
250 [ # # ]: 0 : if( refVar.Is() )
251 : : {
252 [ # # ]: 0 : if( *p == '=' )
253 : : {
254 : : // Assign only onto properties!
255 [ # # ][ # # ]: 0 : if( refVar->GetClass() != SbxCLASS_PROPERTY )
256 : : {
257 [ # # ]: 0 : SbxBase::SetError( SbxERR_BAD_ACTION );
258 [ # # ]: 0 : refVar.Clear();
259 : : }
260 : : else
261 : : {
262 : 0 : p++;
263 [ # # ]: 0 : SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) );
264 [ # # ]: 0 : if( refVar2.Is() )
265 : : {
266 : 0 : SbxVariable* pVar = refVar;
267 : 0 : SbxVariable* pVar2 = refVar2;
268 [ # # ]: 0 : *pVar = *pVar2;
269 [ # # ]: 0 : pVar->SetParameters( NULL );
270 [ # # ]: 0 : }
271 : : }
272 : : }
273 : : else
274 : : // Simple call: once activating
275 [ # # ]: 0 : refVar->Broadcast( SBX_HINT_DATAWANTED );
276 : : }
277 : 0 : *ppBuf = p;
278 [ # # ]: 0 : if( refVar.Is() )
279 : 0 : refVar->AddRef();
280 [ # # ]: 0 : return refVar;
281 : : }
282 : :
283 : : // Read in of an element. This is a symbol, optional followed
284 : : // by a parameter list. The symbol will be searched in the
285 : : // specified object and the parameter list will be attached if necessary.
286 : :
287 : 72 : static SbxVariable* Element
288 : : ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf,
289 : : SbxClassType t, const SbxSimpleCharClass& rCharClass )
290 : : {
291 [ + - ]: 72 : XubString aSym;
292 [ + - ]: 72 : const xub_Unicode* p = Symbol( *ppBuf, aSym, rCharClass );
293 : 72 : SbxVariableRef refVar;
294 [ + - ]: 72 : if( aSym.Len() )
295 : : {
296 : 72 : sal_uInt16 nOld = pObj->GetFlags();
297 [ + + ]: 72 : if( pObj == pGbl )
298 : 36 : pObj->SetFlag( SBX_GBLSEARCH );
299 [ + - ][ + - ]: 72 : refVar = pObj->Find( aSym, t );
[ + - ]
300 : 72 : pObj->SetFlags( nOld );
301 [ + - ]: 72 : if( refVar.Is() )
302 : : {
303 [ + - ]: 72 : refVar->SetParameters( NULL );
304 : : // Follow still parameter?
305 : 72 : p = SkipWhitespace( p );
306 [ - + ]: 72 : if( *p == '(' )
307 : : {
308 : 0 : p++;
309 [ # # ][ # # ]: 0 : SbxArrayRef refPar = new SbxArray;
310 : 0 : sal_uInt16 nArg = 0;
311 : : // We are once relaxed and accept as well
312 : : // the line- or commandend as delimiter
313 : : // Search parameter always global!
314 [ # # ][ # # ]: 0 : while( *p && *p != ')' && *p != ']' )
[ # # ][ # # ]
315 : : {
316 [ # # ]: 0 : SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p );
317 [ # # ]: 0 : if( !refArg )
318 : : {
319 : : // Error during the parsing
320 [ # # ]: 0 : refVar.Clear(); break;
321 : : }
322 : : else
323 : : {
324 : : // One copies the parameter, so that
325 : : // one have the current status (triggers also
326 : : // the call per access)
327 : 0 : SbxVariable* pArg = refArg;
328 [ # # ][ # # ]: 0 : refPar->Put( new SbxVariable( *pArg ), ++nArg );
[ # # ]
329 : : }
330 : 0 : p = SkipWhitespace( p );
331 [ # # ]: 0 : if( *p == ',' )
332 : 0 : p++;
333 [ # # ][ # # ]: 0 : }
334 [ # # ]: 0 : if( *p == ')' )
335 : 0 : p++;
336 [ # # ]: 0 : if( refVar.Is() )
337 [ # # ][ # # ]: 0 : refVar->SetParameters( refPar );
338 : : }
339 : : }
340 : : else
341 [ # # ]: 0 : SbxBase::SetError( SbxERR_NO_METHOD );
342 : : }
343 : 72 : *ppBuf = p;
344 [ + - ]: 72 : if( refVar.Is() )
345 : 72 : refVar->AddRef();
346 [ + - ][ + - ]: 72 : return refVar;
347 : : }
348 : :
349 : : // Mainroutine
350 : :
351 : 0 : SbxVariable* SbxObject::Execute( const XubString& rTxt )
352 : : {
353 : 0 : SbxVariable* pVar = NULL;
354 : 0 : const xub_Unicode* p = rTxt.GetBuffer();
355 : 0 : for( ;; )
356 : : {
357 : 0 : p = SkipWhitespace( p );
358 [ # # ]: 0 : if( !*p )
359 : 0 : break;
360 [ # # ]: 0 : if( *p++ != '[' )
361 : : {
362 [ # # ]: 0 : SetError( SbxERR_SYNTAX ); break;
363 : : }
364 [ # # ]: 0 : pVar = Assign( this, this, &p );
365 [ # # ]: 0 : if( !pVar )
366 : 0 : break;
367 : 0 : p = SkipWhitespace( p );
368 [ # # ]: 0 : if( *p++ != ']' )
369 : : {
370 [ # # ]: 0 : SetError( SbxERR_SYNTAX ); break;
371 : : }
372 : : }
373 : 0 : return pVar;
374 : : }
375 : :
376 : 36 : SbxVariable* SbxObject::FindQualified( const XubString& rName, SbxClassType t )
377 : : {
378 : 36 : SbxVariable* pVar = NULL;
379 : 36 : const xub_Unicode* p = rName.GetBuffer();
380 : 36 : p = SkipWhitespace( p );
381 [ - + ]: 36 : if( !*p )
382 : 0 : return NULL;;
383 [ + - ]: 36 : pVar = QualifiedName( this, this, &p, t );
384 : 36 : p = SkipWhitespace( p );
385 [ - + ]: 36 : if( *p )
386 [ # # ]: 0 : SetError( SbxERR_SYNTAX );
387 : 36 : return pVar;
388 : : }
389 : :
390 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|