merge the formfield patch from ooo-build
[ooovba.git] / basic / source / runtime / step0.cxx
blob3b6297ecba606746bafd87a9a88d7eee3cafd20a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: step0.cxx,v $
10 * $Revision: 1.32 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basic.hxx"
33 #include <vcl/msgbox.hxx>
34 #include <tools/fsys.hxx>
36 #include "errobject.hxx"
37 #include "runtime.hxx"
38 #include "sbintern.hxx"
39 #include "iosys.hxx"
40 #include <sb.hrc>
41 #include <basrid.hxx>
42 #include "sbunoobj.hxx"
43 #include "image.hxx"
44 #include <com/sun/star/uno/Any.hxx>
45 #include <com/sun/star/util/SearchOptions.hdl>
46 #include <vcl/svapp.hxx>
47 #include <unotools/textsearch.hxx>
49 #include <algorithm>
51 // for a patch forward declaring these methods below makes sense
52 // but, #FIXME lets really just move the methods to the top
53 void lcl_clearImpl( SbxVariableRef& refVar, SbxDataType& eType );
54 void lcl_eraseImpl( SbxVariableRef& refVar, bool bVBAEnabled );
56 SbxVariable* getDefaultProp( SbxVariable* pRef );
58 void SbiRuntime::StepNOP()
61 void SbiRuntime::StepArith( SbxOperator eOp )
63 SbxVariableRef p1 = PopVar();
64 TOSMakeTemp();
65 SbxVariable* p2 = GetTOS();
67 p2->ResetFlag( SBX_FIXED );
68 p2->Compute( eOp, *p1 );
70 checkArithmeticOverflow( p2 );
73 void SbiRuntime::StepUnary( SbxOperator eOp )
75 TOSMakeTemp();
76 SbxVariable* p = GetTOS();
77 p->Compute( eOp, *p );
80 void SbiRuntime::StepCompare( SbxOperator eOp )
82 SbxVariableRef p1 = PopVar();
83 SbxVariableRef p2 = PopVar();
85 // Make sure objects with default params have
86 // values ( and type ) set as appropriate
87 SbxDataType p1Type = p1->GetType();
88 SbxDataType p2Type = p2->GetType();
89 if ( p1Type == SbxEMPTY )
91 p1->Broadcast( SBX_HINT_DATAWANTED );
92 p1Type = p1->GetType();
94 if ( p2Type == SbxEMPTY )
96 p2->Broadcast( SBX_HINT_DATAWANTED );
97 p2Type = p2->GetType();
99 if ( p1Type == p2Type )
101 // if both sides are an object and have default props
102 // then we need to use the default props
103 // we don't need to worry if only one side ( lhs, rhs ) is an
104 // object ( object side will get coerced to correct type in
105 // Compare )
106 if ( p1Type == SbxOBJECT )
108 SbxVariable* pDflt = getDefaultProp( p1 );
109 if ( pDflt )
111 p1 = pDflt;
112 p1->Broadcast( SBX_HINT_DATAWANTED );
114 pDflt = getDefaultProp( p2 );
115 if ( pDflt )
117 p2 = pDflt;
118 p2->Broadcast( SBX_HINT_DATAWANTED );
123 #ifndef WIN
124 static SbxVariable* pTRUE = NULL;
125 static SbxVariable* pFALSE = NULL;
126 static SbxVariable* pNULL = NULL;
127 // why do this on non-windows ?
128 // why do this at all ?
129 // I dumbly follow the pattern :-/
130 if ( bVBAEnabled && ( p1->IsNull() || p2->IsNull() ) )
132 if( !pNULL )
134 pNULL = new SbxVariable;
135 pNULL->PutNull();
136 pNULL->AddRef();
138 PushVar( pNULL );
140 else if( p2->Compare( eOp, *p1 ) )
142 if( !pTRUE )
144 pTRUE = new SbxVariable;
145 pTRUE->PutBool( TRUE );
146 pTRUE->AddRef();
148 PushVar( pTRUE );
150 else
152 if( !pFALSE )
154 pFALSE = new SbxVariable;
155 pFALSE->PutBool( FALSE );
156 pFALSE->AddRef();
158 PushVar( pFALSE );
160 #else
161 SbxVariable* pRes = new SbxVariable;
162 if ( bVBAEnabled && ( p1->IsNull() || p2->IsNull() ) )
163 pRes->PutNull();
164 else
166 BOOL bRes = p2->Compare( eOp, *p1 );
167 pRes->PutBool( bRes );
169 PushVar( pRes );
170 #endif
173 void SbiRuntime::StepEXP() { StepArith( SbxEXP ); }
174 void SbiRuntime::StepMUL() { StepArith( SbxMUL ); }
175 void SbiRuntime::StepDIV() { StepArith( SbxDIV ); }
176 void SbiRuntime::StepIDIV() { StepArith( SbxIDIV ); }
177 void SbiRuntime::StepMOD() { StepArith( SbxMOD ); }
178 void SbiRuntime::StepPLUS() { StepArith( SbxPLUS ); }
179 void SbiRuntime::StepMINUS() { StepArith( SbxMINUS ); }
180 void SbiRuntime::StepCAT() { StepArith( SbxCAT ); }
181 void SbiRuntime::StepAND() { StepArith( SbxAND ); }
182 void SbiRuntime::StepOR() { StepArith( SbxOR ); }
183 void SbiRuntime::StepXOR() { StepArith( SbxXOR ); }
184 void SbiRuntime::StepEQV() { StepArith( SbxEQV ); }
185 void SbiRuntime::StepIMP() { StepArith( SbxIMP ); }
187 void SbiRuntime::StepNEG() { StepUnary( SbxNEG ); }
188 void SbiRuntime::StepNOT() { StepUnary( SbxNOT ); }
190 void SbiRuntime::StepEQ() { StepCompare( SbxEQ ); }
191 void SbiRuntime::StepNE() { StepCompare( SbxNE ); }
192 void SbiRuntime::StepLT() { StepCompare( SbxLT ); }
193 void SbiRuntime::StepGT() { StepCompare( SbxGT ); }
194 void SbiRuntime::StepLE() { StepCompare( SbxLE ); }
195 void SbiRuntime::StepGE() { StepCompare( SbxGE ); }
197 namespace
199 bool NeedEsc(sal_Unicode cCode)
201 String sEsc(RTL_CONSTASCII_USTRINGPARAM(".^$+\\|{}()"));
202 return (STRING_NOTFOUND != sEsc.Search(cCode));
205 String VBALikeToRegexp(const String &rIn)
207 String sResult;
208 const sal_Unicode *start = rIn.GetBuffer();
209 const sal_Unicode *end = start + rIn.Len();
211 int seenright = 0;
213 sResult.Append('^');
215 while (start < end)
217 switch (*start)
219 case '?':
220 sResult.Append('.');
221 start++;
222 break;
223 case '*':
224 sResult.Append(String(RTL_CONSTASCII_USTRINGPARAM(".*")));
225 start++;
226 break;
227 case '#':
228 sResult.Append(String(RTL_CONSTASCII_USTRINGPARAM("[0-9]")));
229 start++;
230 break;
231 case ']':
232 sResult.Append('\\');
233 sResult.Append(*start++);
234 break;
235 case '[':
236 sResult.Append(*start++);
237 seenright = 0;
238 while (start < end && !seenright)
240 switch (*start)
242 case '[':
243 case '?':
244 case '*':
245 sResult.Append('\\');
246 sResult.Append(*start);
247 break;
248 case ']':
249 sResult.Append(*start);
250 seenright = 1;
251 break;
252 case '!':
253 sResult.Append('^');
254 break;
255 default:
256 if (NeedEsc(*start))
257 sResult.Append('\\');
258 sResult.Append(*start);
259 break;
261 start++;
263 break;
264 default:
265 if (NeedEsc(*start))
266 sResult.Append('\\');
267 sResult.Append(*start++);
271 sResult.Append('$');
273 return sResult;
277 void SbiRuntime::StepLIKE()
279 SbxVariableRef refVar1 = PopVar();
280 SbxVariableRef refVar2 = PopVar();
282 String pattern = VBALikeToRegexp(refVar1->GetString());
283 String value = refVar2->GetString();
285 com::sun::star::util::SearchOptions aSearchOpt;
287 aSearchOpt.algorithmType = com::sun::star::util::SearchAlgorithms_REGEXP;
289 aSearchOpt.Locale = Application::GetSettings().GetLocale();
290 aSearchOpt.searchString = pattern;
292 int bTextMode(1);
293 bool bCompatibility = ( pINST && pINST->IsCompatibility() );
294 if( bCompatibility )
295 bTextMode = GetImageFlag( SBIMG_COMPARETEXT );
297 if( bTextMode )
298 aSearchOpt.transliterateFlags |= com::sun::star::i18n::TransliterationModules_IGNORE_CASE;
300 SbxVariable* pRes = new SbxVariable;
301 utl::TextSearch aSearch(aSearchOpt);
302 xub_StrLen nStart=0, nEnd=value.Len();
303 int bRes = aSearch.SearchFrwrd(value, &nStart, &nEnd);
304 pRes->PutBool( bRes != 0 );
306 PushVar( pRes );
309 // TOS und TOS-1 sind beides Objektvariable und enthalten den selben Pointer
311 void SbiRuntime::StepIS()
313 SbxVariableRef refVar1 = PopVar();
314 SbxVariableRef refVar2 = PopVar();
315 BOOL bRes = BOOL(
316 refVar1->GetType() == SbxOBJECT
317 && refVar2->GetType() == SbxOBJECT );
318 if ( bVBAEnabled && !bRes )
319 Error( SbERR_INVALID_USAGE_OBJECT );
320 bRes = ( bRes && refVar1->GetObject() == refVar2->GetObject() );
321 SbxVariable* pRes = new SbxVariable;
322 pRes->PutBool( bRes );
323 PushVar( pRes );
326 // Aktualisieren des Wertes von TOS
328 void SbiRuntime::StepGET()
330 SbxVariable* p = GetTOS();
331 p->Broadcast( SBX_HINT_DATAWANTED );
334 // #67607 Uno-Structs kopieren
335 inline void checkUnoStructCopy( SbxVariableRef& refVal, SbxVariableRef& refVar )
337 SbxDataType eVarType = refVar->GetType();
338 if( eVarType != SbxOBJECT )
339 return;
341 SbxObjectRef xValObj = (SbxObject*)refVal->GetObject();
342 if( !xValObj.Is() || xValObj->ISA(SbUnoAnyObject) )
343 return;
345 // #115826: Exclude ProcedureProperties to avoid call to Property Get procedure
346 if( refVar->ISA(SbProcedureProperty) )
347 return;
349 SbxObjectRef xVarObj = (SbxObject*)refVar->GetObject();
350 SbxDataType eValType = refVal->GetType();
351 if( eValType == SbxOBJECT && xVarObj == xValObj )
353 SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxObject*)xVarObj);
354 if( pUnoObj )
356 Any aAny = pUnoObj->getUnoAny();
357 if( aAny.getValueType().getTypeClass() == TypeClass_STRUCT )
359 SbUnoObject* pNewUnoObj = new SbUnoObject( pUnoObj->GetName(), aAny );
360 // #70324: ClassName uebernehmen
361 pNewUnoObj->SetClassName( pUnoObj->GetClassName() );
362 refVar->PutObject( pNewUnoObj );
369 // Ablage von TOS in TOS-1
371 void SbiRuntime::StepPUT()
373 SbxVariableRef refVal = PopVar();
374 SbxVariableRef refVar = PopVar();
375 // Store auf die eigene Methode (innerhalb einer Function)?
376 BOOL bFlagsChanged = FALSE;
377 USHORT n = 0;
378 if( (SbxVariable*) refVar == (SbxVariable*) pMeth )
380 bFlagsChanged = TRUE;
381 n = refVar->GetFlags();
382 refVar->SetFlag( SBX_WRITE );
385 // if left side arg is an object or variant and right handside isn't
386 // either an object or a variant then try and see if a default
387 // property exists.
388 // to use e.g. Range{"A1") = 34
389 // could equate to Range("A1").Value = 34
390 if ( bVBAEnabled )
392 if ( refVar->GetType() == SbxOBJECT )
394 SbxVariable* pDflt = getDefaultProp( refVar );
395 if ( pDflt )
396 refVar = pDflt;
398 if ( refVal->GetType() == SbxOBJECT )
400 SbxVariable* pDflt = getDefaultProp( refVal );
401 if ( pDflt )
402 refVal = pDflt;
406 *refVar = *refVal;
407 // lhs is a property who's value is currently null
408 if ( !bVBAEnabled || ( bVBAEnabled && refVar->GetType() != SbxEMPTY ) )
409 // #67607 Uno-Structs kopieren
410 checkUnoStructCopy( refVal, refVar );
411 if( bFlagsChanged )
412 refVar->SetFlags( n );
416 // Speichern Objektvariable
417 // Nicht-Objekt-Variable fuehren zu Fehlern
419 void SbiRuntime::StepSET_Impl( SbxVariableRef& refVal, SbxVariableRef& refVar, bool bHandleDefaultProp )
421 // #67733 Typen mit Array-Flag sind auch ok
422 SbxDataType eValType = refVal->GetType();
423 SbxDataType eVarType = refVar->GetType();
424 if( (eValType != SbxOBJECT
425 && eValType != SbxEMPTY
426 // seems like when using the default method its possible for objects
427 // to be empty ( no broadcast has taken place yet ) or the actual value is
429 && !bHandleDefaultProp
430 && !(eValType & SbxARRAY)) ||
431 (eVarType != SbxOBJECT
432 && eVarType != SbxEMPTY
433 && !bHandleDefaultProp
434 && !(eVarType & SbxARRAY) ) )
436 Error( SbERR_INVALID_USAGE_OBJECT );
438 else
440 // Getting in here causes problems with objects with default properties
441 // if they are SbxEMPTY I guess
442 if ( !bHandleDefaultProp || ( bHandleDefaultProp && refVal->GetType() == SbxOBJECT ) )
444 // Auf refVal GetObject fuer Collections ausloesen
445 SbxBase* pObjVarObj = refVal->GetObject();
446 if( pObjVarObj )
448 SbxVariableRef refObjVal = PTR_CAST(SbxObject,pObjVarObj);
450 // #67733 Typen mit Array-Flag sind auch ok
451 if( refObjVal )
452 refVal = refObjVal;
453 else if( !(eValType & SbxARRAY) )
454 refVal = NULL;
458 // #52896 Wenn Uno-Sequences bzw. allgemein Arrays einer als
459 // Object deklarierten Variable zugewiesen werden, kann hier
460 // refVal ungueltig sein!
461 if( !refVal )
463 Error( SbERR_INVALID_USAGE_OBJECT );
465 else
467 // Store auf die eigene Methode (innerhalb einer Function)?
468 BOOL bFlagsChanged = FALSE;
469 USHORT n = 0;
470 if( (SbxVariable*) refVar == (SbxVariable*) pMeth )
472 bFlagsChanged = TRUE;
473 n = refVar->GetFlags();
474 refVar->SetFlag( SBX_WRITE );
476 SbProcedureProperty* pProcProperty = PTR_CAST(SbProcedureProperty,(SbxVariable*)refVar);
477 if( pProcProperty )
478 pProcProperty->setSet( true );
480 if ( bHandleDefaultProp )
482 // get default properties for lhs & rhs where necessary
483 // SbxVariable* defaultProp = NULL; unused variable
484 bool bLHSHasDefaultProp = false;
485 // LHS try determine if a default prop exists
486 if ( refVar->GetType() == SbxOBJECT )
488 SbxVariable* pDflt = getDefaultProp( refVar );
489 if ( pDflt )
491 refVar = pDflt;
492 bLHSHasDefaultProp = true;
495 // RHS only get a default prop is the rhs has one
496 if ( refVal->GetType() == SbxOBJECT )
498 // check if lhs is a null object
499 // if it is then use the object not the default property
500 SbxObject* pObj = NULL;
503 pObj = PTR_CAST(SbxObject,(SbxVariable*)refVar);
505 // calling GetObject on a SbxEMPTY variable raises
506 // object not set errors, make sure its an Object
507 if ( !pObj && refVar->GetType() == SbxOBJECT )
509 SbxBase* pObjVarObj = refVar->GetObject();
510 pObj = PTR_CAST(SbxObject,pObjVarObj);
512 SbxVariable* pDflt = NULL;
513 if ( pObj || bLHSHasDefaultProp )
514 // lhs is either a valid object || or has a defaultProp
515 pDflt = getDefaultProp( refVal );
516 if ( pDflt )
517 refVal = pDflt;
521 *refVar = *refVal;
523 // lhs is a property who's value is currently (Empty e.g. no broadcast yet)
524 // in this case if there is a default prop involved the value of the
525 // default property may infact be void so the type will also be SbxEMPTY
526 // in this case we do not want to call checkUnoStructCopy 'cause that will
527 // cause an error also
528 if ( !bHandleDefaultProp || ( bHandleDefaultProp && ( refVar->GetType() != SbxEMPTY ) ) )
529 // #67607 Uno-Structs kopieren
530 checkUnoStructCopy( refVal, refVar );
531 if( bFlagsChanged )
532 refVar->SetFlags( n );
537 void SbiRuntime::StepSET()
539 SbxVariableRef refVal = PopVar();
540 SbxVariableRef refVar = PopVar();
541 StepSET_Impl( refVal, refVar, bVBAEnabled ); // this is really assigment
544 void SbiRuntime::StepVBASET()
546 SbxVariableRef refVal = PopVar();
547 SbxVariableRef refVar = PopVar();
548 // don't handle default property
549 StepSET_Impl( refVal, refVar, false ); // set obj = something
553 // JSM 07.10.95
554 void SbiRuntime::StepLSET()
556 SbxVariableRef refVal = PopVar();
557 SbxVariableRef refVar = PopVar();
558 if( refVar->GetType() != SbxSTRING
559 || refVal->GetType() != SbxSTRING )
560 Error( SbERR_INVALID_USAGE_OBJECT );
561 else
563 // Store auf die eigene Methode (innerhalb einer Function)?
564 USHORT n = refVar->GetFlags();
565 if( (SbxVariable*) refVar == (SbxVariable*) pMeth )
566 refVar->SetFlag( SBX_WRITE );
567 String aRefVarString = refVar->GetString();
568 String aRefValString = refVal->GetString();
570 USHORT nVarStrLen = aRefVarString.Len();
571 USHORT nValStrLen = aRefValString.Len();
572 String aNewStr;
573 if( nVarStrLen > nValStrLen )
575 aRefVarString.Fill(nVarStrLen,' ');
576 aNewStr = aRefValString.Copy( 0, nValStrLen );
577 aNewStr += aRefVarString.Copy( nValStrLen, nVarStrLen - nValStrLen );
579 else
581 aNewStr = aRefValString.Copy( 0, nVarStrLen );
584 refVar->PutString( aNewStr );
585 refVar->SetFlags( n );
589 // JSM 07.10.95
590 void SbiRuntime::StepRSET()
592 SbxVariableRef refVal = PopVar();
593 SbxVariableRef refVar = PopVar();
594 if( refVar->GetType() != SbxSTRING
595 || refVal->GetType() != SbxSTRING )
596 Error( SbERR_INVALID_USAGE_OBJECT );
597 else
599 // Store auf die eigene Methode (innerhalb einer Function)?
600 USHORT n = refVar->GetFlags();
601 if( (SbxVariable*) refVar == (SbxVariable*) pMeth )
602 refVar->SetFlag( SBX_WRITE );
603 String aRefVarString = refVar->GetString();
604 String aRefValString = refVal->GetString();
606 USHORT nPos = 0;
607 USHORT nVarStrLen = aRefVarString.Len();
608 if( nVarStrLen > aRefValString.Len() )
610 aRefVarString.Fill(nVarStrLen,' ');
611 nPos = nVarStrLen - aRefValString.Len();
613 aRefVarString = aRefVarString.Copy( 0, nPos );
614 aRefVarString += aRefValString.Copy( 0, nVarStrLen - nPos );
615 refVar->PutString(aRefVarString);
617 refVar->SetFlags( n );
621 // Ablage von TOS in TOS-1, dann ReadOnly-Bit setzen
623 void SbiRuntime::StepPUTC()
625 SbxVariableRef refVal = PopVar();
626 SbxVariableRef refVar = PopVar();
627 refVar->SetFlag( SBX_WRITE );
628 *refVar = *refVal;
629 refVar->ResetFlag( SBX_WRITE );
630 refVar->SetFlag( SBX_CONST );
633 // DIM
634 // TOS = Variable fuer das Array mit Dimensionsangaben als Parameter
636 void SbiRuntime::StepDIM()
638 SbxVariableRef refVar = PopVar();
639 DimImpl( refVar );
642 // #56204 DIM-Funktionalitaet in Hilfsmethode auslagern (step0.cxx)
643 void SbiRuntime::DimImpl( SbxVariableRef refVar )
645 // If refDim then this DIM statement is terminating a ReDIM and
646 // previous StepERASE_CLEAR for an array, the following actions have
647 // been delayed from ( StepERASE_CLEAR ) 'till here
648 if ( refRedim )
650 if ( !refRedimpArray ) // only erase the array not ReDim Preserve
651 lcl_eraseImpl( refVar, bVBAEnabled );
652 SbxDataType eType = refVar->GetType();
653 lcl_clearImpl( refVar, eType );
654 refRedim = NULL;
656 SbxArray* pDims = refVar->GetParameters();
657 // Muss eine gerade Anzahl Argumente haben
658 // Man denke daran, dass Arg[0] nicht zaehlt!
659 if( pDims && !( pDims->Count() & 1 ) )
660 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
661 else
663 SbxDataType eType = refVar->IsFixed() ? refVar->GetType() : SbxVARIANT;
664 SbxDimArray* pArray = new SbxDimArray( eType );
665 // AB 2.4.1996, auch Arrays ohne Dimensionsangaben zulassen (VB-komp.)
666 if( pDims )
668 for( USHORT i = 1; i < pDims->Count(); )
670 INT32 lb = pDims->Get( i++ )->GetLong();
671 INT32 ub = pDims->Get( i++ )->GetLong();
672 if( ub < lb )
673 Error( SbERR_OUT_OF_RANGE ), ub = lb;
674 pArray->AddDim32( lb, ub );
675 if ( lb != ub )
676 pArray->setHasFixedSize( true );
679 else
681 // #62867 Beim Anlegen eines Arrays der Laenge 0 wie bei
682 // Uno-Sequences der Laenge 0 eine Dimension anlegen
683 pArray->unoAddDim( 0, -1 );
685 USHORT nSavFlags = refVar->GetFlags();
686 refVar->ResetFlag( SBX_FIXED );
687 refVar->PutObject( pArray );
688 refVar->SetFlags( nSavFlags );
689 refVar->SetParameters( NULL );
693 // REDIM
694 // TOS = Variable fuer das Array
695 // argv = Dimensionsangaben
697 void SbiRuntime::StepREDIM()
699 // Im Moment ist es nichts anderes als Dim, da doppeltes Dim
700 // bereits vom Compiler erkannt wird.
701 StepDIM();
705 // Helper function for StepREDIMP
706 void implCopyDimArray( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex,
707 short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
709 sal_Int32& ri = pActualIndices[nActualDim];
710 for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ )
712 if( nActualDim < nMaxDimIndex )
714 implCopyDimArray( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1,
715 pActualIndices, pLowerBounds, pUpperBounds );
717 else
719 SbxVariable* pSource = pOldArray->Get32( pActualIndices );
720 SbxVariable* pDest = pNewArray->Get32( pActualIndices );
721 if( pSource && pDest )
722 *pDest = *pSource;
727 // REDIM PRESERVE
728 // TOS = Variable fuer das Array
729 // argv = Dimensionsangaben
731 void SbiRuntime::StepREDIMP()
733 SbxVariableRef refVar = PopVar();
734 DimImpl( refVar );
736 // Now check, if we can copy from the old array
737 if( refRedimpArray.Is() )
739 SbxBase* pElemObj = refVar->GetObject();
740 SbxDimArray* pNewArray = PTR_CAST(SbxDimArray,pElemObj);
741 SbxDimArray* pOldArray = (SbxDimArray*)(SbxArray*)refRedimpArray;
742 if( pNewArray )
744 short nDimsNew = pNewArray->GetDims();
745 short nDimsOld = pOldArray->GetDims();
746 short nDims = nDimsNew;
747 BOOL bRangeError = FALSE;
749 // Store dims to use them for copying later
750 sal_Int32* pLowerBounds = new sal_Int32[nDims];
751 sal_Int32* pUpperBounds = new sal_Int32[nDims];
752 sal_Int32* pActualIndices = new sal_Int32[nDims];
754 if( nDimsOld != nDimsNew )
756 bRangeError = TRUE;
758 else
760 // Compare bounds
761 for( short i = 1 ; i <= nDims ; i++ )
763 sal_Int32 lBoundNew, uBoundNew;
764 sal_Int32 lBoundOld, uBoundOld;
765 pNewArray->GetDim32( i, lBoundNew, uBoundNew );
766 pOldArray->GetDim32( i, lBoundOld, uBoundOld );
768 /* #69094 Allow all dimensions to be changed
769 although Visual Basic is not able to do so.
770 // All bounds but the last have to be the same
771 if( i < nDims && ( lBoundNew != lBoundOld || uBoundNew != uBoundOld ) )
773 bRangeError = TRUE;
774 break;
776 else
779 // #69094: if( i == nDims )
781 lBoundNew = std::max( lBoundNew, lBoundOld );
782 uBoundNew = std::min( uBoundNew, uBoundOld );
784 short j = i - 1;
785 pActualIndices[j] = pLowerBounds[j] = lBoundNew;
786 pUpperBounds[j] = uBoundNew;
791 if( bRangeError )
793 StarBASIC::Error( SbERR_OUT_OF_RANGE );
795 else
797 // Copy data from old array by going recursively through all dimensions
798 // (It would be faster to work on the flat internal data array of an
799 // SbyArray but this solution is clearer and easier)
800 implCopyDimArray( pNewArray, pOldArray, nDims - 1,
801 0, pActualIndices, pLowerBounds, pUpperBounds );
804 delete[] pUpperBounds;
805 delete[] pLowerBounds;
806 delete[] pActualIndices;
807 refRedimpArray = NULL;
811 //StarBASIC::FatalError( SbERR_NOT_IMPLEMENTED );
814 // REDIM_COPY
815 // TOS = Array-Variable, Reference to array is copied
816 // Variable is cleared as in ERASE
818 void SbiRuntime::StepREDIMP_ERASE()
820 SbxVariableRef refVar = PopVar();
821 refRedim = refVar;
822 SbxDataType eType = refVar->GetType();
823 if( eType & SbxARRAY )
825 SbxBase* pElemObj = refVar->GetObject();
826 SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj);
827 if( pDimArray )
829 refRedimpArray = pDimArray;
833 else
834 if( refVar->IsFixed() )
835 refVar->Clear();
836 else
837 refVar->SetType( SbxEMPTY );
840 void lcl_clearImpl( SbxVariableRef& refVar, SbxDataType& eType )
842 USHORT nSavFlags = refVar->GetFlags();
843 refVar->ResetFlag( SBX_FIXED );
844 refVar->SetType( SbxDataType(eType & 0x0FFF) );
845 refVar->SetFlags( nSavFlags );
846 refVar->Clear();
849 void lcl_eraseImpl( SbxVariableRef& refVar, bool bVBAEnabled )
851 SbxDataType eType = refVar->GetType();
852 if( eType & SbxARRAY )
854 if ( bVBAEnabled )
856 SbxBase* pElemObj = refVar->GetObject();
857 SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj);
858 bool bClearValues = true;
859 if( pDimArray )
861 if ( pDimArray->hasFixedSize() )
863 // Clear all Value(s)
864 pDimArray->SbxArray::Clear();
865 bClearValues = false;
867 else
868 pDimArray->Clear(); // clear Dims
870 if ( bClearValues )
872 SbxArray* pArray = PTR_CAST(SbxArray,pElemObj);
873 if ( pArray )
874 pArray->Clear();
877 else
878 // AB 2.4.1996
879 // Arrays haben bei Erase nach VB ein recht komplexes Verhalten. Hier
880 // werden zunaechst nur die Typ-Probleme bei REDIM (#26295) beseitigt:
881 // Typ hart auf den Array-Typ setzen, da eine Variable mit Array
882 // SbxOBJECT ist. Bei REDIM entsteht dann ein SbxOBJECT-Array und
883 // der ursruengliche Typ geht verloren -> Laufzeitfehler
884 lcl_clearImpl( refVar, eType );
886 else
887 if( refVar->IsFixed() )
888 refVar->Clear();
889 else
890 refVar->SetType( SbxEMPTY );
893 // Variable loeschen
894 // TOS = Variable
896 void SbiRuntime::StepERASE()
898 SbxVariableRef refVar = PopVar();
899 lcl_eraseImpl( refVar, bVBAEnabled );
902 void SbiRuntime::StepERASE_CLEAR()
904 refRedim = PopVar();
907 void SbiRuntime::StepARRAYACCESS()
909 if( !refArgv )
910 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
911 SbxVariableRef refVar = PopVar();
912 refVar->SetParameters( refArgv );
913 PopArgv();
914 PushVar( CheckArray( refVar ) );
917 // Einrichten eines Argvs
918 // nOp1 bleibt so -> 1. Element ist Returnwert
920 void SbiRuntime::StepARGC()
922 PushArgv();
923 refArgv = new SbxArray;
924 nArgc = 1;
927 // Speichern eines Arguments in Argv
929 void SbiRuntime::StepARGV()
931 if( !refArgv )
932 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
933 else
935 SbxVariableRef pVal = PopVar();
937 // Before fix of #94916:
938 // if( pVal->ISA(SbxMethod) || pVal->ISA(SbxProperty) )
939 if( pVal->ISA(SbxMethod) || pVal->ISA(SbUnoProperty) || pVal->ISA(SbProcedureProperty) )
941 // Methoden und Properties evaluieren!
942 SbxVariable* pRes = new SbxVariable( *pVal );
943 pVal = pRes;
945 refArgv->Put( pVal, nArgc++ );
949 // Input to Variable. Die Variable ist auf TOS und wird
950 // anschliessend entfernt.
952 void SbiRuntime::StepINPUT()
954 String s;
955 char ch = 0;
956 SbError err;
957 // Skip whitespace
958 while( ( err = pIosys->GetError() ) == 0 )
960 ch = pIosys->Read();
961 if( ch != ' ' && ch != '\t' && ch != '\n' )
962 break;
964 if( !err )
966 // Scan until comma or whitespace
967 char sep = ( ch == '"' ) ? ch : 0;
968 if( sep ) ch = pIosys->Read();
969 while( ( err = pIosys->GetError() ) == 0 )
971 if( ch == sep )
973 ch = pIosys->Read();
974 if( ch != sep )
975 break;
977 else if( !sep && (ch == ',' || ch == '\n') )
978 break;
979 s += ch;
980 ch = pIosys->Read();
982 // skip whitespace
983 if( ch == ' ' || ch == '\t' )
984 while( ( err = pIosys->GetError() ) == 0 )
986 if( ch != ' ' && ch != '\t' && ch != '\n' )
987 break;
988 ch = pIosys->Read();
991 if( !err )
993 SbxVariableRef pVar = GetTOS();
994 // Zuerst versuchen, die Variable mit einem numerischen Wert
995 // zu fuellen, dann mit einem Stringwert
996 if( !pVar->IsFixed() || pVar->IsNumeric() )
998 USHORT nLen = 0;
999 if( !pVar->Scan( s, &nLen ) )
1001 err = SbxBase::GetError();
1002 SbxBase::ResetError();
1004 // Der Wert muss komplett eingescant werden
1005 else if( nLen != s.Len() && !pVar->PutString( s ) )
1007 err = SbxBase::GetError();
1008 SbxBase::ResetError();
1010 else if( nLen != s.Len() && pVar->IsNumeric() )
1012 err = SbxBase::GetError();
1013 SbxBase::ResetError();
1014 if( !err )
1015 err = SbERR_CONVERSION;
1018 else
1020 pVar->PutString( s );
1021 err = SbxBase::GetError();
1022 SbxBase::ResetError();
1025 if( err == SbERR_USER_ABORT )
1026 Error( err );
1027 else if( err )
1029 if( pRestart && !pIosys->GetChannel() )
1031 BasResId aId( IDS_SBERR_START + 4 );
1032 String aMsg( aId );
1034 //****** DONT CHECK IN, TEST ONLY *******
1035 //****** DONT CHECK IN, TEST ONLY *******
1036 // ErrorBox( NULL, WB_OK, aMsg ).Execute();
1037 //****** DONT CHECK IN, TEST ONLY *******
1038 //****** DONT CHECK IN, TEST ONLY *******
1040 pCode = pRestart;
1042 else
1043 Error( err );
1045 else
1047 // pIosys->ResetChannel();
1048 PopVar();
1052 // Line Input to Variable. Die Variable ist auf TOS und wird
1053 // anschliessend entfernt.
1055 void SbiRuntime::StepLINPUT()
1057 ByteString aInput;
1058 pIosys->Read( aInput );
1059 Error( pIosys->GetError() );
1060 SbxVariableRef p = PopVar();
1061 p->PutString( String( aInput, gsl_getSystemTextEncoding() ) );
1062 // pIosys->ResetChannel();
1065 // Programmende
1067 void SbiRuntime::StepSTOP()
1069 pInst->Stop();
1072 // FOR-Variable initialisieren
1074 void SbiRuntime::StepINITFOR()
1076 PushFor();
1079 void SbiRuntime::StepINITFOREACH()
1081 PushForEach();
1084 // FOR-Variable inkrementieren
1086 void SbiRuntime::StepNEXT()
1088 if( !pForStk )
1090 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
1091 return;
1093 if( pForStk->eForType == FOR_TO )
1094 pForStk->refVar->Compute( SbxPLUS, *pForStk->refInc );
1097 // Anfang CASE: TOS in CASE-Stack
1099 void SbiRuntime::StepCASE()
1101 if( !refCaseStk.Is() )
1102 refCaseStk = new SbxArray;
1103 SbxVariableRef xVar = PopVar();
1104 refCaseStk->Put( xVar, refCaseStk->Count() );
1107 // Ende CASE: Variable freigeben
1109 void SbiRuntime::StepENDCASE()
1111 if( !refCaseStk || !refCaseStk->Count() )
1112 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
1113 else
1114 refCaseStk->Remove( refCaseStk->Count() - 1 );
1117 // Standard-Fehlerbehandlung
1119 void SbiRuntime::StepSTDERROR()
1121 pError = NULL; bError = TRUE;
1122 pInst->aErrorMsg = String();
1123 pInst->nErr = 0L;
1124 pInst->nErl = 0;
1125 nError = 0L;
1126 SbxErrObject::getUnoErrObject()->Clear();
1129 void SbiRuntime::StepNOERROR()
1131 pInst->aErrorMsg = String();
1132 pInst->nErr = 0L;
1133 pInst->nErl = 0;
1134 nError = 0L;
1135 SbxErrObject::getUnoErrObject()->Clear();
1136 bError = FALSE;
1139 // UP verlassen
1141 void SbiRuntime::StepLEAVE()
1143 bRun = FALSE;
1144 // If VBA and we are leaving an ErrorHandler then clear the error ( it's been processed )
1145 if ( bInError && pError )
1146 SbxErrObject::getUnoErrObject()->Clear();
1149 void SbiRuntime::StepCHANNEL() // TOS = Kanalnummer
1151 SbxVariableRef pChan = PopVar();
1152 short nChan = pChan->GetInteger();
1153 pIosys->SetChannel( nChan );
1154 Error( pIosys->GetError() );
1157 void SbiRuntime::StepCHANNEL0()
1159 pIosys->ResetChannel();
1162 void SbiRuntime::StepPRINT() // print TOS
1164 SbxVariableRef p = PopVar();
1165 String s1 = p->GetString();
1166 String s;
1167 if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE )
1168 s = ' '; // ein Blank davor
1169 s += s1;
1170 ByteString aByteStr( s, gsl_getSystemTextEncoding() );
1171 pIosys->Write( aByteStr );
1172 Error( pIosys->GetError() );
1175 void SbiRuntime::StepPRINTF() // print TOS in field
1177 SbxVariableRef p = PopVar();
1178 String s1 = p->GetString();
1179 String s;
1180 if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE )
1181 s = ' '; // ein Blank davor
1182 s += s1;
1183 s.Expand( 14, ' ' );
1184 ByteString aByteStr( s, gsl_getSystemTextEncoding() );
1185 pIosys->Write( aByteStr );
1186 Error( pIosys->GetError() );
1189 void SbiRuntime::StepWRITE() // write TOS
1191 SbxVariableRef p = PopVar();
1192 // Muss der String gekapselt werden?
1193 char ch = 0;
1194 switch (p->GetType() )
1196 case SbxSTRING: ch = '"'; break;
1197 case SbxCURRENCY:
1198 case SbxBOOL:
1199 case SbxDATE: ch = '#'; break;
1200 default: break;
1202 String s;
1203 if( ch )
1204 s += ch;
1205 s += p->GetString();
1206 if( ch )
1207 s += ch;
1208 ByteString aByteStr( s, gsl_getSystemTextEncoding() );
1209 pIosys->Write( aByteStr );
1210 Error( pIosys->GetError() );
1213 void SbiRuntime::StepRENAME() // Rename Tos+1 to Tos
1215 SbxVariableRef pTos1 = PopVar();
1216 SbxVariableRef pTos = PopVar();
1217 String aDest = pTos1->GetString();
1218 String aSource = pTos->GetString();
1220 // <-- UCB
1221 if( hasUno() )
1223 implStepRenameUCB( aSource, aDest );
1225 else
1226 // --> UCB
1228 #ifdef _OLD_FILE_IMPL
1229 DirEntry aSourceDirEntry( aSource );
1230 if( aSourceDirEntry.Exists() )
1232 if( aSourceDirEntry.MoveTo( DirEntry(aDest) ) != FSYS_ERR_OK )
1233 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
1235 else
1236 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
1237 #else
1238 implStepRenameOSL( aSource, aDest );
1239 #endif
1243 // TOS = Prompt
1245 void SbiRuntime::StepPROMPT()
1247 SbxVariableRef p = PopVar();
1248 ByteString aStr( p->GetString(), gsl_getSystemTextEncoding() );
1249 pIosys->SetPrompt( aStr );
1252 // Set Restart point
1254 void SbiRuntime::StepRESTART()
1256 pRestart = pCode;
1259 // Leerer Ausdruck auf Stack fuer fehlenden Parameter
1261 void SbiRuntime::StepEMPTY()
1263 // #57915 Die Semantik von StepEMPTY() ist die Repraesentation eines fehlenden
1264 // Arguments. Dies wird in VB durch ein durch den Wert 448 (SbERR_NAMED_NOT_FOUND)
1265 // vom Typ Error repraesentiert. StepEmpty jetzt muesste besser StepMISSING()
1266 // heissen, aber der Name wird der Einfachkeit halber beibehalten.
1267 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
1268 xVar->PutErr( 448 );
1269 PushVar( xVar );
1270 // ALT: PushVar( new SbxVariable( SbxEMPTY ) );
1273 // TOS = Fehlercode
1275 void SbiRuntime::StepERROR()
1277 SbxVariableRef refCode = PopVar();
1278 USHORT n = refCode->GetUShort();
1279 SbError error = StarBASIC::GetSfxFromVBError( n );
1280 pInst->Error( error );