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