xref: /AOO41X/main/basic/source/runtime/methods.cxx (revision 5980243063f6840bf3a2e60b2243db5da5e78fa6)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_basic.hxx"
24 
25 #include <tools/date.hxx>
26 #include <basic/sbxvar.hxx>
27 #include <vos/process.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/sound.hxx>
31 #include <tools/wintypes.hxx>
32 #include <vcl/msgbox.hxx>
33 #include <basic/sbx.hxx>
34 #include <svl/zforlist.hxx>
35 #include <rtl/math.hxx>
36 #include <tools/urlobj.hxx>
37 #include <osl/time.h>
38 #include <unotools/charclass.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <tools/wldcrd.hxx>
41 #include <i18npool/lang.h>
42 #include <vcl/dibtools.hxx>
43 
44 #include "runtime.hxx"
45 #include "sbunoobj.hxx"
46 #ifdef WNT
47 #include <tools/prewin.h>
48 #include "winbase.h"
49 #include <tools/postwin.h>
50 #ifndef _FSYS_HXX //autogen
51 #include <tools/fsys.hxx>
52 #endif
53 #else
54 #include <osl/file.hxx>
55 #endif
56 #include "errobject.hxx"
57 
58 #ifdef _USE_UNO
59 #include <comphelper/processfactory.hxx>
60 
61 #include <com/sun/star/uno/Sequence.hxx>
62 #include <com/sun/star/util/DateTime.hpp>
63 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
64 #include <com/sun/star/lang/Locale.hpp>
65 #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
66 #include <com/sun/star/io/XInputStream.hpp>
67 #include <com/sun/star/io/XOutputStream.hpp>
68 #include <com/sun/star/io/XStream.hpp>
69 #include <com/sun/star/io/XSeekable.hpp>
70 
71 using namespace comphelper;
72 using namespace osl;
73 using namespace com::sun::star::uno;
74 using namespace com::sun::star::lang;
75 using namespace com::sun::star::ucb;
76 using namespace com::sun::star::io;
77 using namespace com::sun::star::frame;
78 
79 #endif /* _USE_UNO */
80 
81 //#define _ENABLE_CUR_DIR
82 
83 #include "stdobj.hxx"
84 #include <basic/sbstdobj.hxx>
85 #include "rtlproto.hxx"
86 #include "basrid.hxx"
87 #include "image.hxx"
88 #include "sb.hrc"
89 #include "iosys.hxx"
90 #include "ddectrl.hxx"
91 #include <sbintern.hxx>
92 #include <basic/vbahelper.hxx>
93 
94 #include <list>
95 #include <math.h>
96 #include <stdio.h>
97 #include <stdlib.h>
98 #include <ctype.h>
99 
100 #if defined (WNT) || defined (OS2)
101 #include <direct.h>   // _getdcwd get current work directory, _chdrive
102 #endif
103 
104 #ifdef UNX
105 #include <errno.h>
106 #include <unistd.h>
107 #endif
108 
109 #ifdef WNT
110 #include <io.h>
111 #endif
112 
113 #include <basic/sbobjmod.hxx>
114 
115 // from source/classes/sbxmod.cxx
116 Reference< XModel > getDocumentModel( StarBASIC* );
117 
118 static void FilterWhiteSpace( String& rStr )
119 {
120     rStr.EraseAllChars( ' ' );
121     rStr.EraseAllChars( '\t' );
122     rStr.EraseAllChars( '\n' );
123     rStr.EraseAllChars( '\r' );
124 }
125 
126 static long GetDayDiff( const Date& rDate )
127 {
128     Date aRefDate( 1,1,1900 );
129     long nDiffDays;
130     if ( aRefDate > rDate )
131     {
132         nDiffDays = (long)(aRefDate - rDate);
133         nDiffDays *= -1;
134     }
135     else
136         nDiffDays = (long)(rDate - aRefDate);
137     nDiffDays += 2; // Anpassung VisualBasic: 1.Jan.1900 == 2
138     return nDiffDays;
139 }
140 
141 static CharClass& GetCharClass( void )
142 {
143     static sal_Bool bNeedsInit = sal_True;
144     static ::com::sun::star::lang::Locale aLocale;
145     if( bNeedsInit )
146     {
147         bNeedsInit = sal_False;
148         aLocale = Application::GetSettings().GetLocale();
149     }
150     static CharClass aCharClass( aLocale );
151     return aCharClass;
152 }
153 
154 static inline sal_Bool isFolder( FileStatus::Type aType )
155 {
156     return ( aType == FileStatus::Directory || aType == FileStatus::Volume );
157 }
158 
159 
160 //*** UCB file access ***
161 
162 // Converts possibly relative paths to absolute paths
163 // according to the setting done by ChDir/ChDrive
164 String getFullPath( const String& aRelPath )
165 {
166     ::rtl::OUString aFileURL;
167 
168     // #80204 Try first if it already is a valid URL
169     INetURLObject aURLObj( aRelPath );
170     aFileURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE );
171 
172     if( !aFileURL.getLength() )
173     {
174         File::getFileURLFromSystemPath( aRelPath, aFileURL );
175     }
176 
177     return aFileURL;
178 }
179 
180 // Sets (virtual) current path for UCB file access
181 void implChDir( const String& aDir )
182 {
183     (void)aDir;
184     // TODO
185 }
186 
187 // Sets (virtual) current drive for UCB file access
188 void implChDrive( const String& aDrive )
189 {
190     (void)aDrive;
191     // TODO
192 }
193 
194 // Returns (virtual) current path for UCB file access
195 String implGetCurDir( void )
196 {
197     String aRetStr;
198 
199     return aRetStr;
200 }
201 
202 // TODO: -> SbiGlobals
203 static com::sun::star::uno::Reference< XSimpleFileAccess3 > getFileAccess( void )
204 {
205     static com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI;
206     if( !xSFI.is() )
207     {
208         com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
209         if( xSMgr.is() )
210         {
211             xSFI = com::sun::star::uno::Reference< XSimpleFileAccess3 >( xSMgr->createInstance
212                 ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
213         }
214     }
215     return xSFI;
216 }
217 
218 
219 
220 // Properties und Methoden legen beim Get (bPut = sal_False) den Returnwert
221 // im Element 0 des Argv ab; beim Put (bPut = sal_True) wird der Wert aus
222 // Element 0 gespeichert.
223 
224 // CreateObject( class )
225 
226 RTLFUNC(CreateObject)
227 {
228     (void)bWrite;
229 
230     String aClass( rPar.Get( 1 )->GetString() );
231     SbxObjectRef p = SbxBase::CreateObject( aClass );
232     if( !p )
233         StarBASIC::Error( SbERR_CANNOT_LOAD );
234     else
235     {
236         // Convenience: BASIC als Parent eintragen
237         p->SetParent( pBasic );
238         rPar.Get( 0 )->PutObject( p );
239     }
240 }
241 
242 // Error( n )
243 
244 RTLFUNC(Error)
245 {
246     (void)bWrite;
247 
248     if( !pBasic )
249         StarBASIC::Error( SbERR_INTERNAL_ERROR );
250     else
251     {
252         String aErrorMsg;
253         SbError nErr = 0L;
254         sal_Int32 nCode = 0;
255         if( rPar.Count() == 1 )
256         {
257             nErr = StarBASIC::GetErrBasic();
258             aErrorMsg = StarBASIC::GetErrorMsg();
259         }
260         else
261         {
262             nCode = rPar.Get( 1 )->GetLong();
263             if( nCode > 65535L )
264                 StarBASIC::Error( SbERR_CONVERSION );
265             else
266                 nErr = StarBASIC::GetSfxFromVBError( (sal_uInt16)nCode );
267         }
268 
269         bool bVBA = SbiRuntime::isVBAEnabled();
270         String tmpErrMsg;
271         if( bVBA && aErrorMsg.Len() > 0 )
272         {
273             tmpErrMsg = aErrorMsg;
274         }
275         else
276         {
277             pBasic->MakeErrorText( nErr, aErrorMsg );
278             tmpErrMsg = pBasic->GetErrorText();
279         }
280         // If this rtlfunc 'Error'  passed a errcode the same as the active Err Objects's
281         // current err then  return the description for the error message if it is set
282         // ( complicated isn't it ? )
283         if ( bVBA && rPar.Count() > 1 )
284         {
285             com::sun::star::uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() );
286             if ( xErrObj.is() && xErrObj->getNumber() == nCode && xErrObj->getDescription().getLength() )
287                 tmpErrMsg = xErrObj->getDescription();
288         }
289         rPar.Get( 0 )->PutString( tmpErrMsg );
290     }
291 }
292 
293 // Sinus
294 
295 RTLFUNC(Sin)
296 {
297     (void)pBasic;
298     (void)bWrite;
299 
300     if ( rPar.Count() < 2 )
301         StarBASIC::Error( SbERR_BAD_ARGUMENT );
302     else
303     {
304         SbxVariableRef pArg = rPar.Get( 1 );
305         rPar.Get( 0 )->PutDouble( sin( pArg->GetDouble() ) );
306     }
307 }
308 
309 // Cosinus
310 
311 RTLFUNC(Cos)
312 {
313     (void)pBasic;
314     (void)bWrite;
315 
316     if ( rPar.Count() < 2 )
317         StarBASIC::Error( SbERR_BAD_ARGUMENT );
318     else
319     {
320         SbxVariableRef pArg = rPar.Get( 1 );
321         rPar.Get( 0 )->PutDouble( cos( pArg->GetDouble() ) );
322     }
323 }
324 
325 // Atn
326 
327 RTLFUNC(Atn)
328 {
329     (void)pBasic;
330     (void)bWrite;
331 
332     if ( rPar.Count() < 2 )
333         StarBASIC::Error( SbERR_BAD_ARGUMENT );
334     else
335     {
336         SbxVariableRef pArg = rPar.Get( 1 );
337         rPar.Get( 0 )->PutDouble( atan( pArg->GetDouble() ) );
338     }
339 }
340 
341 
342 
343 RTLFUNC(Abs)
344 {
345     (void)pBasic;
346     (void)bWrite;
347 
348     if ( rPar.Count() < 2 )
349         StarBASIC::Error( SbERR_BAD_ARGUMENT );
350     else
351     {
352         SbxVariableRef pArg = rPar.Get( 1 );
353         rPar.Get( 0 )->PutDouble( fabs( pArg->GetDouble() ) );
354     }
355 }
356 
357 
358 RTLFUNC(Asc)
359 {
360     (void)pBasic;
361     (void)bWrite;
362 
363     if ( rPar.Count() < 2 )
364         StarBASIC::Error( SbERR_BAD_ARGUMENT );
365     else
366     {
367         SbxVariableRef pArg = rPar.Get( 1 );
368         String aStr( pArg->GetString() );
369         if ( aStr.Len() == 0 )
370         {
371             StarBASIC::Error( SbERR_BAD_ARGUMENT );
372             rPar.Get(0)->PutEmpty();
373         }
374         else
375         {
376             sal_Unicode aCh = aStr.GetBuffer()[0];
377             rPar.Get(0)->PutLong( aCh );
378         }
379     }
380 }
381 
382 void implChr( SbxArray& rPar, bool bChrW )
383 {
384     if ( rPar.Count() < 2 )
385         StarBASIC::Error( SbERR_BAD_ARGUMENT );
386     else
387     {
388         SbxVariableRef pArg = rPar.Get( 1 );
389 
390         String aStr;
391         if( !bChrW && SbiRuntime::isVBAEnabled() )
392         {
393             sal_Char c = (sal_Char)pArg->GetByte();
394             ByteString s( c );
395             aStr = String( s, gsl_getSystemTextEncoding() );
396         }
397         else
398         {
399             sal_Unicode aCh = (sal_Unicode)pArg->GetUShort();
400             aStr = String( aCh );
401         }
402         rPar.Get(0)->PutString( aStr );
403     }
404 }
405 
406 RTLFUNC(Chr)
407 {
408     (void)pBasic;
409     (void)bWrite;
410 
411     bool bChrW = false;
412     implChr( rPar, bChrW );
413 }
414 
415 RTLFUNC(ChrW)
416 {
417     (void)pBasic;
418     (void)bWrite;
419 
420     bool bChrW = true;
421     implChr( rPar, bChrW );
422 }
423 
424 
425 #ifdef UNX
426 #define _MAX_PATH 260
427 #define _PATH_INCR 250
428 #endif
429 
430 RTLFUNC(CurDir)
431 {
432     (void)pBasic;
433     (void)bWrite;
434 
435     // #57064 Obwohl diese Funktion nicht mit DirEntry arbeitet, ist sie von
436     // der Anpassung an virtuelle URLs nich betroffen, da bei Nutzung der
437     // DirEntry-Funktionalitaet keine Moeglichkeit besteht, das aktuelle so
438     // zu ermitteln, dass eine virtuelle URL geliefert werden koennte.
439 
440 //  rPar.Get(0)->PutEmpty();
441 #if defined (WNT) || defined (OS2)
442     int nCurDir = 0;  // Current dir // JSM
443     if ( rPar.Count() == 2 )
444     {
445         String aDrive = rPar.Get(1)->GetString();
446         if ( aDrive.Len() != 1 )
447         {
448             StarBASIC::Error( SbERR_BAD_ARGUMENT );
449             return;
450         }
451         else
452         {
453             nCurDir = (int)aDrive.GetBuffer()[0];
454             if ( !isalpha( nCurDir ) )
455             {
456                 StarBASIC::Error( SbERR_BAD_ARGUMENT );
457                 return;
458             }
459             else
460                 nCurDir -= ( 'A' - 1 );
461         }
462     }
463     char* pBuffer = new char[ _MAX_PATH ];
464 #ifdef OS2
465     if( !nCurDir )
466         nCurDir = _getdrive();
467 #endif
468     if ( _getdcwd( nCurDir, pBuffer, _MAX_PATH ) != 0 )
469         rPar.Get(0)->PutString( String::CreateFromAscii( pBuffer ) );
470     else
471         StarBASIC::Error( SbERR_NO_DEVICE );
472     delete [] pBuffer;
473 
474 #elif defined( UNX )
475 
476     int nSize = _PATH_INCR;
477     char* pMem;
478     while( sal_True )
479       {
480         pMem = new char[nSize];
481         if( !pMem )
482           {
483             StarBASIC::Error( SbERR_NO_MEMORY );
484             return;
485           }
486         if( getcwd( pMem, nSize-1 ) != NULL )
487           {
488             rPar.Get(0)->PutString( String::CreateFromAscii(pMem) );
489             delete [] pMem;
490             return;
491           }
492         if( errno != ERANGE )
493           {
494             StarBASIC::Error( SbERR_INTERNAL_ERROR );
495             delete [] pMem;
496             return;
497           }
498         delete [] pMem;
499         nSize += _PATH_INCR;
500       };
501 
502 #endif
503 }
504 
505 RTLFUNC(ChDir) // JSM
506 {
507     (void)bWrite;
508 
509     rPar.Get(0)->PutEmpty();
510     if (rPar.Count() == 2)
511     {
512 #ifdef _ENABLE_CUR_DIR
513         String aPath = rPar.Get(1)->GetString();
514         sal_Bool bError = sal_False;
515 #ifdef WNT
516         // #55997 Laut MI hilft es bei File-URLs einen DirEntry zwischenzuschalten
517         // #40996 Harmoniert bei Verwendung der WIN32-Funktion nicht mit getdir
518         DirEntry aEntry( aPath );
519         ByteString aFullPath( aEntry.GetFull(), gsl_getSystemTextEncoding() );
520         if( chdir( aFullPath.GetBuffer()) )
521             bError = sal_True;
522 #else
523         if (!DirEntry(aPath).SetCWD())
524             bError = sal_True;
525 #endif
526         if( bError )
527             StarBASIC::Error( SbERR_PATH_NOT_FOUND );
528 #endif
529         // VBA: track current directory per document type (separately for Writer, Calc, Impress, etc.)
530         if( SbiRuntime::isVBAEnabled() )
531             ::basic::vba::registerCurrentDirectory( getDocumentModel( pBasic ), rPar.Get(1)->GetString() );
532     }
533     else
534         StarBASIC::Error( SbERR_BAD_ARGUMENT );
535 }
536 
537 RTLFUNC(ChDrive) // JSM
538 {
539     (void)pBasic;
540     (void)bWrite;
541 
542     rPar.Get(0)->PutEmpty();
543     if (rPar.Count() == 2)
544     {
545 #ifdef _ENABLE_CUR_DIR
546         // Keine Laufwerke in Unix
547 #ifndef UNX
548         String aPar1 = rPar.Get(1)->GetString();
549 
550 #if defined (WNT) || defined (OS2)
551         if (aPar1.Len() > 0)
552         {
553             int nCurDrive = (int)aPar1.GetBuffer()[0]; ;
554             if ( !isalpha( nCurDrive ) )
555             {
556                 StarBASIC::Error( SbERR_BAD_ARGUMENT );
557                 return;
558             }
559             else
560                 nCurDrive -= ( 'A' - 1 );
561             if (_chdrive(nCurDrive))
562                 StarBASIC::Error( SbERR_NO_DEVICE );
563         }
564 #endif
565 
566 #endif
567         // #ifndef UNX
568 #endif
569     }
570     else
571         StarBASIC::Error( SbERR_BAD_ARGUMENT );
572 }
573 
574 
575 // Implementation of StepRENAME with UCB
576 void implStepRenameUCB( const String& aSource, const String& aDest )
577 {
578     com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
579     if( xSFI.is() )
580     {
581         try
582         {
583             String aSourceFullPath = getFullPath( aSource );
584             if( !xSFI->exists( aSourceFullPath ) )
585             {
586                 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
587                 return;
588             }
589 
590             String aDestFullPath = getFullPath( aDest );
591             if( xSFI->exists( aDestFullPath ) )
592                 StarBASIC::Error( SbERR_FILE_EXISTS );
593             else
594                 xSFI->move( aSourceFullPath, aDestFullPath );
595         }
596         catch( Exception & )
597         {
598             StarBASIC::Error( SbERR_FILE_NOT_FOUND );
599         }
600     }
601 }
602 
603 // Implementation of StepRENAME with OSL
604 void implStepRenameOSL( const String& aSource, const String& aDest )
605 {
606     FileBase::RC nRet = File::move( getFullPathUNC( aSource ), getFullPathUNC( aDest ) );
607     if( nRet != FileBase::E_None )
608     {
609         StarBASIC::Error( SbERR_PATH_NOT_FOUND );
610     }
611 }
612 
613 RTLFUNC(FileCopy) // JSM
614 {
615     (void)pBasic;
616     (void)bWrite;
617 
618     rPar.Get(0)->PutEmpty();
619     if (rPar.Count() == 3)
620     {
621         String aSource = rPar.Get(1)->GetString();
622         String aDest = rPar.Get(2)->GetString();
623         // <-- UCB
624         if( hasUno() )
625         {
626             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
627             if( xSFI.is() )
628             {
629                 try
630                 {
631                     xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) );
632                 }
633                 catch( Exception & )
634                 {
635                     StarBASIC::Error( SbERR_PATH_NOT_FOUND );
636                 }
637             }
638         }
639         else
640         // --> UCB
641         {
642 #ifdef _OLD_FILE_IMPL
643             DirEntry aSourceDirEntry(aSource);
644             if (aSourceDirEntry.Exists())
645             {
646                 if (aSourceDirEntry.CopyTo(DirEntry(aDest),FSYS_ACTION_COPYFILE) != FSYS_ERR_OK)
647                     StarBASIC::Error( SbERR_PATH_NOT_FOUND );
648             }
649             else
650                     StarBASIC::Error( SbERR_PATH_NOT_FOUND );
651 #else
652             FileBase::RC nRet = File::copy( getFullPathUNC( aSource ), getFullPathUNC( aDest ) );
653             if( nRet != FileBase::E_None )
654             {
655                 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
656             }
657 #endif
658         }
659     }
660     else
661         StarBASIC::Error( SbERR_BAD_ARGUMENT );
662 }
663 
664 RTLFUNC(Kill) // JSM
665 {
666     (void)pBasic;
667     (void)bWrite;
668 
669     rPar.Get(0)->PutEmpty();
670     if (rPar.Count() == 2)
671     {
672         String aFileSpec = rPar.Get(1)->GetString();
673 
674         // <-- UCB
675         if( hasUno() )
676         {
677             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
678             if( xSFI.is() )
679             {
680                 String aFullPath = getFullPath( aFileSpec );
681                 if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) )
682                 {
683                     StarBASIC::Error( SbERR_FILE_NOT_FOUND );
684                     return;
685                 }
686                 try
687                 {
688                     xSFI->kill( aFullPath );
689                 }
690                 catch( Exception & )
691                 {
692                     StarBASIC::Error( ERRCODE_IO_GENERAL );
693                 }
694             }
695         }
696         else
697         // --> UCB
698         {
699 #ifdef _OLD_FILE_IMPL
700             if(DirEntry(aFileSpec).Kill() != FSYS_ERR_OK)
701                 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
702 #else
703             File::remove( getFullPathUNC( aFileSpec ) );
704 #endif
705         }
706     }
707     else
708         StarBASIC::Error( SbERR_BAD_ARGUMENT );
709 }
710 
711 RTLFUNC(MkDir) // JSM
712 {
713     (void)pBasic;
714     (void)bWrite;
715 
716     rPar.Get(0)->PutEmpty();
717     if (rPar.Count() == 2)
718     {
719         String aPath = rPar.Get(1)->GetString();
720 
721         // <-- UCB
722         if( hasUno() )
723         {
724             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
725             if( xSFI.is() )
726             {
727                 try
728                 {
729                     xSFI->createFolder( getFullPath( aPath ) );
730                 }
731                 catch( Exception & )
732                 {
733                     StarBASIC::Error( ERRCODE_IO_GENERAL );
734                 }
735             }
736         }
737         else
738         // --> UCB
739         {
740 #ifdef _OLD_FILE_IMPL
741             if (!DirEntry(aPath).MakeDir())
742                 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
743 #else
744             Directory::create( getFullPathUNC( aPath ) );
745 #endif
746         }
747     }
748     else
749         StarBASIC::Error( SbERR_BAD_ARGUMENT );
750 }
751 
752 
753 #ifndef _OLD_FILE_IMPL
754 
755 // In OSL only empty directories can be deleted
756 // so we have to delete all files recursively
757 void implRemoveDirRecursive( const String& aDirPath )
758 {
759     DirectoryItem aItem;
760     FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem );
761     sal_Bool bExists = (nRet == FileBase::E_None);
762 
763     FileStatus aFileStatus( FileStatusMask_Type );
764     nRet = aItem.getFileStatus( aFileStatus );
765     FileStatus::Type aType = aFileStatus.getFileType();
766     sal_Bool bFolder = isFolder( aType );
767 
768     if( !bExists || !bFolder )
769     {
770         StarBASIC::Error( SbERR_PATH_NOT_FOUND );
771         return;
772     }
773 
774     Directory aDir( aDirPath );
775     nRet = aDir.open();
776     if( nRet != FileBase::E_None )
777     {
778         StarBASIC::Error( SbERR_PATH_NOT_FOUND );
779         return;
780     }
781 
782     for( ;; )
783     {
784         DirectoryItem aItem2;
785         nRet = aDir.getNextItem( aItem2 );
786         if( nRet != FileBase::E_None )
787             break;
788 
789         // Handle flags
790         FileStatus aFileStatus2( FileStatusMask_Type | FileStatusMask_FileURL );
791         nRet = aItem2.getFileStatus( aFileStatus2 );
792         ::rtl::OUString aPath = aFileStatus2.getFileURL();
793 
794         // Directory?
795         FileStatus::Type aType2 = aFileStatus2.getFileType();
796         sal_Bool bFolder2 = isFolder( aType2 );
797         if( bFolder2 )
798         {
799             implRemoveDirRecursive( aPath );
800         }
801         else
802         {
803             File::remove( aPath );
804         }
805     }
806     nRet = aDir.close();
807 
808     nRet = Directory::remove( aDirPath );
809 }
810 #endif
811 
812 
813 RTLFUNC(RmDir) // JSM
814 {
815     (void)pBasic;
816     (void)bWrite;
817 
818     rPar.Get(0)->PutEmpty();
819     if (rPar.Count() == 2)
820     {
821         String aPath = rPar.Get(1)->GetString();
822         // <-- UCB
823         if( hasUno() )
824         {
825             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
826             if( xSFI.is() )
827             {
828                 try
829                 {
830                     if( !xSFI->isFolder( aPath ) )
831                     {
832                         StarBASIC::Error( SbERR_PATH_NOT_FOUND );
833                         return;
834                     }
835                     SbiInstance* pInst = pINST;
836                     bool bCompatibility = ( pInst && pInst->IsCompatibility() );
837                     if( bCompatibility )
838                     {
839                         Sequence< ::rtl::OUString > aContent = xSFI->getFolderContents( aPath, true );
840                         sal_Int32 nCount = aContent.getLength();
841                         if( nCount > 0 )
842                         {
843                             StarBASIC::Error( SbERR_ACCESS_ERROR );
844                             return;
845                         }
846                     }
847 
848                     xSFI->kill( getFullPath( aPath ) );
849                 }
850                 catch( Exception & )
851                 {
852                     StarBASIC::Error( ERRCODE_IO_GENERAL );
853                 }
854             }
855         }
856         else
857         // --> UCB
858         {
859 #ifdef _OLD_FILE_IMPL
860             DirEntry aDirEntry(aPath);
861             if (aDirEntry.Kill() != FSYS_ERR_OK)
862                 StarBASIC::Error( SbERR_PATH_NOT_FOUND );
863 #else
864             implRemoveDirRecursive( getFullPathUNC( aPath ) );
865 #endif
866         }
867     }
868     else
869         StarBASIC::Error( SbERR_BAD_ARGUMENT );
870 }
871 
872 RTLFUNC(SendKeys) // JSM
873 {
874     (void)pBasic;
875     (void)bWrite;
876 
877     rPar.Get(0)->PutEmpty();
878     StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
879 }
880 
881 RTLFUNC(Exp)
882 {
883     (void)pBasic;
884     (void)bWrite;
885 
886     if( rPar.Count() < 2 )
887         StarBASIC::Error( SbERR_BAD_ARGUMENT );
888     else
889     {
890         double aDouble = rPar.Get( 1 )->GetDouble();
891         aDouble = exp( aDouble );
892         checkArithmeticOverflow( aDouble );
893         rPar.Get( 0 )->PutDouble( aDouble );
894     }
895 }
896 
897 RTLFUNC(FileLen)
898 {
899     (void)pBasic;
900     (void)bWrite;
901 
902     if ( rPar.Count() < 2 )
903         StarBASIC::Error( SbERR_BAD_ARGUMENT );
904     else
905     {
906         SbxVariableRef pArg = rPar.Get( 1 );
907         String aStr( pArg->GetString() );
908         sal_Int32 nLen = 0;
909         // <-- UCB
910         if( hasUno() )
911         {
912             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
913             if( xSFI.is() )
914             {
915                 try
916                 {
917                     nLen = xSFI->getSize( getFullPath( aStr ) );
918                 }
919                 catch( Exception & )
920                 {
921                     StarBASIC::Error( ERRCODE_IO_GENERAL );
922                 }
923             }
924         }
925         else
926         // --> UCB
927         {
928 #ifdef _OLD_FILE_IMPL
929             FileStat aStat = DirEntry( aStr );
930             nLen = aStat.GetSize();
931 #else
932             DirectoryItem aItem;
933             FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( aStr ), aItem );
934             FileStatus aFileStatus( FileStatusMask_FileSize );
935             nRet = aItem.getFileStatus( aFileStatus );
936             nLen = (sal_Int32)aFileStatus.getFileSize();
937 #endif
938         }
939         rPar.Get(0)->PutLong( (long)nLen );
940     }
941 }
942 
943 
944 RTLFUNC(Hex)
945 {
946     (void)pBasic;
947     (void)bWrite;
948 
949     if ( rPar.Count() < 2 )
950         StarBASIC::Error( SbERR_BAD_ARGUMENT );
951     else
952     {
953         char aBuffer[16];
954         SbxVariableRef pArg = rPar.Get( 1 );
955         if ( pArg->IsInteger() )
956             snprintf( aBuffer, sizeof(aBuffer), "%X", pArg->GetInteger() );
957         else
958             snprintf( aBuffer, sizeof(aBuffer), "%lX", static_cast<long unsigned int>(pArg->GetLong()) );
959         rPar.Get(0)->PutString( String::CreateFromAscii( aBuffer ) );
960     }
961 }
962 
963 // InStr( [start],string,string,[compare] )
964 
965 RTLFUNC(InStr)
966 {
967     (void)pBasic;
968     (void)bWrite;
969 
970     sal_uIntPtr nArgCount = rPar.Count()-1;
971     if ( nArgCount < 2 )
972         StarBASIC::Error( SbERR_BAD_ARGUMENT );
973     else
974     {
975         sal_uInt16 nStartPos = 1;
976 
977         sal_uInt16 nFirstStringPos = 1;
978         if ( nArgCount >= 3 )
979         {
980             sal_Int32 lStartPos = rPar.Get(1)->GetLong();
981             if( lStartPos <= 0 || lStartPos > 0xffff )
982             {
983                 StarBASIC::Error( SbERR_BAD_ARGUMENT );
984                 lStartPos = 1;
985             }
986             nStartPos = (sal_uInt16)lStartPos;
987             nFirstStringPos++;
988         }
989 
990         SbiInstance* pInst = pINST;
991         int bTextMode;
992         bool bCompatibility = ( pInst && pInst->IsCompatibility() );
993         if( bCompatibility )
994         {
995             SbiRuntime* pRT = pInst ? pInst->pRun : NULL;
996             bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
997         }
998         else
999         {
1000             bTextMode = 1;;
1001         }
1002         if ( nArgCount == 4 )
1003             bTextMode = rPar.Get(4)->GetInteger();
1004 
1005         sal_uInt16 nPos;
1006         const String& rToken = rPar.Get(nFirstStringPos+1)->GetString();
1007 
1008         // #97545 Always find empty string
1009         if( !rToken.Len() )
1010         {
1011             nPos = nStartPos;
1012         }
1013         else
1014         {
1015             if( !bTextMode )
1016             {
1017                 const String& rStr1 = rPar.Get(nFirstStringPos)->GetString();
1018 
1019                 nPos = rStr1.Search( rToken, nStartPos-1 );
1020                 if ( nPos == STRING_NOTFOUND )
1021                     nPos = 0;
1022                 else
1023                     nPos++;
1024             }
1025             else
1026             {
1027                 String aStr1 = rPar.Get(nFirstStringPos)->GetString();
1028                 String aToken = rToken;
1029 
1030                 aStr1.ToUpperAscii();
1031                 aToken.ToUpperAscii();
1032 
1033                 nPos = aStr1.Search( aToken, nStartPos-1 );
1034                 if ( nPos == STRING_NOTFOUND )
1035                     nPos = 0;
1036                 else
1037                     nPos++;
1038             }
1039         }
1040         rPar.Get(0)->PutLong( nPos );
1041     }
1042 }
1043 
1044 
1045 // InstrRev(string1, string2[, start[, compare]])
1046 
1047 RTLFUNC(InStrRev)
1048 {
1049     (void)pBasic;
1050     (void)bWrite;
1051 
1052     sal_uIntPtr nArgCount = rPar.Count()-1;
1053     if ( nArgCount < 2 )
1054         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1055     else
1056     {
1057         String aStr1 = rPar.Get(1)->GetString();
1058         String aToken = rPar.Get(2)->GetString();
1059 
1060         sal_Int32 lStartPos = -1;
1061         if ( nArgCount >= 3 )
1062         {
1063             lStartPos = rPar.Get(3)->GetLong();
1064             if( (lStartPos <= 0 && lStartPos != -1) || lStartPos > 0xffff )
1065             {
1066                 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1067                 lStartPos = -1;
1068             }
1069         }
1070 
1071         SbiInstance* pInst = pINST;
1072         int bTextMode;
1073         bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1074         if( bCompatibility )
1075         {
1076             SbiRuntime* pRT = pInst ? pInst->pRun : NULL;
1077             bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
1078         }
1079         else
1080         {
1081             bTextMode = 1;;
1082         }
1083         if ( nArgCount == 4 )
1084             bTextMode = rPar.Get(4)->GetInteger();
1085 
1086         sal_uInt16 nStrLen = aStr1.Len();
1087         sal_uInt16 nStartPos = lStartPos == -1 ? nStrLen : (sal_uInt16)lStartPos;
1088 
1089         sal_uInt16 nPos = 0;
1090         if( nStartPos <= nStrLen )
1091         {
1092             sal_uInt16 nTokenLen = aToken.Len();
1093             if( !nTokenLen )
1094             {
1095                 // Always find empty string
1096                 nPos = nStartPos;
1097             }
1098             else if( nStrLen > 0 )
1099             {
1100                 if( !bTextMode )
1101                 {
1102                     ::rtl::OUString aOUStr1 ( aStr1 );
1103                     ::rtl::OUString aOUToken( aToken );
1104                     sal_Int32 nRet = aOUStr1.lastIndexOf( aOUToken, nStartPos );
1105                     if( nRet == -1 )
1106                         nPos = 0;
1107                     else
1108                         nPos = (sal_uInt16)nRet + 1;
1109                 }
1110                 else
1111                 {
1112                     aStr1.ToUpperAscii();
1113                     aToken.ToUpperAscii();
1114 
1115                     ::rtl::OUString aOUStr1 ( aStr1 );
1116                     ::rtl::OUString aOUToken( aToken );
1117                     sal_Int32 nRet = aOUStr1.lastIndexOf( aOUToken, nStartPos );
1118 
1119                     if( nRet == -1 )
1120                         nPos = 0;
1121                     else
1122                         nPos = (sal_uInt16)nRet + 1;
1123                 }
1124             }
1125         }
1126         rPar.Get(0)->PutLong( nPos );
1127     }
1128 }
1129 
1130 
1131 /*
1132     Int( 2.8 )  =  2.0
1133     Int( -2.8 ) = -3.0
1134     Fix( 2.8 )  =  2.0
1135     Fix( -2.8 ) = -2.0    <- !!
1136 */
1137 
1138 RTLFUNC(Int)
1139 {
1140     (void)pBasic;
1141     (void)bWrite;
1142 
1143     if ( rPar.Count() < 2 )
1144         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1145     else
1146     {
1147         SbxVariableRef pArg = rPar.Get( 1 );
1148         double aDouble= pArg->GetDouble();
1149         /*
1150             floor( 2.8 ) =  2.0
1151             floor( -2.8 ) = -3.0
1152         */
1153         aDouble = floor( aDouble );
1154         rPar.Get(0)->PutDouble( aDouble );
1155     }
1156 }
1157 
1158 
1159 
1160 RTLFUNC(Fix)
1161 {
1162     (void)pBasic;
1163     (void)bWrite;
1164 
1165     if ( rPar.Count() < 2 )
1166         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1167     else
1168     {
1169         SbxVariableRef pArg = rPar.Get( 1 );
1170         double aDouble = pArg->GetDouble();
1171         if ( aDouble >= 0.0 )
1172             aDouble = floor( aDouble );
1173         else
1174             aDouble = ceil( aDouble );
1175         rPar.Get(0)->PutDouble( aDouble );
1176     }
1177 }
1178 
1179 
1180 RTLFUNC(LCase)
1181 {
1182     (void)pBasic;
1183     (void)bWrite;
1184 
1185     if ( rPar.Count() < 2 )
1186         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1187     else
1188     {
1189         CharClass& rCharClass = GetCharClass();
1190         String aStr( rPar.Get(1)->GetString() );
1191         rCharClass.toLower( aStr );
1192         rPar.Get(0)->PutString( aStr );
1193     }
1194 }
1195 
1196 RTLFUNC(Left)
1197 {
1198     (void)pBasic;
1199     (void)bWrite;
1200 
1201     if ( rPar.Count() < 3 )
1202         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1203     else
1204     {
1205         String aStr( rPar.Get(1)->GetString() );
1206         sal_Int32 lResultLen = rPar.Get(2)->GetLong();
1207         if( lResultLen > 0xffff )
1208         {
1209             lResultLen = 0xffff;
1210         }
1211         else if( lResultLen < 0 )
1212         {
1213             lResultLen = 0;
1214             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1215         }
1216         aStr.Erase( (sal_uInt16)lResultLen );
1217         rPar.Get(0)->PutString( aStr );
1218     }
1219 }
1220 
1221 RTLFUNC(Log)
1222 {
1223     (void)pBasic;
1224     (void)bWrite;
1225 
1226     if ( rPar.Count() < 2 )
1227         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1228     else
1229     {
1230         double aArg = rPar.Get(1)->GetDouble();
1231         if ( aArg > 0 )
1232         {
1233             double d = log( aArg );
1234             checkArithmeticOverflow( d );
1235             rPar.Get( 0 )->PutDouble( d );
1236         }
1237         else
1238             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1239     }
1240 }
1241 
1242 RTLFUNC(LTrim)
1243 {
1244     (void)pBasic;
1245     (void)bWrite;
1246 
1247     if ( rPar.Count() < 2 )
1248         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1249     else
1250     {
1251         String aStr( rPar.Get(1)->GetString() );
1252         aStr.EraseLeadingChars();
1253         rPar.Get(0)->PutString( aStr );
1254     }
1255 }
1256 
1257 
1258 // Mid( String, nStart, nLength )
1259 
1260 RTLFUNC(Mid)
1261 {
1262     (void)pBasic;
1263     (void)bWrite;
1264 
1265     sal_uIntPtr nArgCount = rPar.Count()-1;
1266     if ( nArgCount < 2 )
1267         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1268     else
1269     {
1270         // #23178: Funktionalitaet von Mid$ als Anweisung nachbilden, indem
1271         // als weiterer (4.) Parameter ein Ersetzungsstring aufgenommen wird.
1272         // Anders als im Original kann in dieser Variante der 3. Parameter
1273         // nLength nicht weggelassen werden. Ist ueber bWrite schon vorgesehen.
1274         if( nArgCount == 4 )
1275             bWrite = sal_True;
1276 
1277         String aArgStr = rPar.Get(1)->GetString();
1278         sal_uInt16 nStartPos = (sal_uInt16)(rPar.Get(2)->GetLong() );
1279         if ( nStartPos == 0 )
1280             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1281         else
1282         {
1283             nStartPos--;
1284             sal_uInt16 nLen = 0xffff;
1285             bool bWriteNoLenParam = false;
1286             if ( nArgCount == 3 || bWrite )
1287             {
1288                 sal_Int32 n = rPar.Get(3)->GetLong();
1289                 if( bWrite && n == -1 )
1290                     bWriteNoLenParam = true;
1291                 nLen = (sal_uInt16)n;
1292             }
1293             String aResultStr;
1294             if ( bWrite )
1295             {
1296                 SbiInstance* pInst = pINST;
1297                 bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1298                 if( bCompatibility )
1299                 {
1300                     sal_uInt16 nArgLen = aArgStr.Len();
1301                     if( nStartPos + 1 > nArgLen )
1302                     {
1303                         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1304                         return;
1305                     }
1306 
1307                     String aReplaceStr = rPar.Get(4)->GetString();
1308                     sal_uInt16 nReplaceStrLen = aReplaceStr.Len();
1309                     sal_uInt16 nReplaceLen;
1310                     if( bWriteNoLenParam )
1311                     {
1312                         nReplaceLen = nReplaceStrLen;
1313                     }
1314                     else
1315                     {
1316                         nReplaceLen = nLen;
1317                         if( nReplaceLen > nReplaceStrLen )
1318                             nReplaceLen = nReplaceStrLen;
1319                     }
1320 
1321                     sal_uInt16 nReplaceEndPos = nStartPos + nReplaceLen;
1322                     if( nReplaceEndPos > nArgLen )
1323                         nReplaceLen -= (nReplaceEndPos - nArgLen);
1324 
1325                     aResultStr = aArgStr;
1326                     sal_uInt16 nErase = nReplaceLen;
1327                     aResultStr.Erase( nStartPos, nErase );
1328                     aResultStr.Insert( aReplaceStr, 0, nReplaceLen, nStartPos );
1329                 }
1330                 else
1331                 {
1332                     aResultStr = aArgStr;
1333                     aResultStr.Erase( nStartPos, nLen );
1334                     aResultStr.Insert(rPar.Get(4)->GetString(),0,nLen,nStartPos);
1335                 }
1336 
1337                 rPar.Get(1)->PutString( aResultStr );
1338             }
1339             else
1340             {
1341                 aResultStr = aArgStr.Copy( nStartPos, nLen );
1342                 rPar.Get(0)->PutString( aResultStr );
1343             }
1344         }
1345     }
1346 }
1347 
1348 RTLFUNC(Oct)
1349 {
1350     (void)pBasic;
1351     (void)bWrite;
1352 
1353     if ( rPar.Count() < 2 )
1354         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1355     else
1356     {
1357         char aBuffer[16];
1358         SbxVariableRef pArg = rPar.Get( 1 );
1359         if ( pArg->IsInteger() )
1360             snprintf( aBuffer, sizeof(aBuffer), "%o", pArg->GetInteger() );
1361         else
1362             snprintf( aBuffer, sizeof(aBuffer), "%lo", static_cast<long unsigned int>(pArg->GetLong()) );
1363         rPar.Get(0)->PutString( String::CreateFromAscii( aBuffer ) );
1364     }
1365 }
1366 
1367 // Replace(expression, find, replace[, start[, count[, compare]]])
1368 
1369 RTLFUNC(Replace)
1370 {
1371     (void)pBasic;
1372     (void)bWrite;
1373 
1374     sal_uIntPtr nArgCount = rPar.Count()-1;
1375     if ( nArgCount < 3 || nArgCount > 6 )
1376         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1377     else
1378     {
1379         String aExpStr = rPar.Get(1)->GetString();
1380         String aFindStr = rPar.Get(2)->GetString();
1381         String aReplaceStr = rPar.Get(3)->GetString();
1382 
1383         sal_Int32 lStartPos = 1;
1384         if ( nArgCount >= 4 )
1385         {
1386             if( rPar.Get(4)->GetType() != SbxEMPTY )
1387                 lStartPos = rPar.Get(4)->GetLong();
1388             if( lStartPos < 1  || lStartPos > 0xffff )
1389             {
1390                 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1391                 lStartPos = 1;
1392             }
1393         }
1394 
1395         sal_Int32 lCount = -1;
1396         if( nArgCount >=5 )
1397         {
1398             if( rPar.Get(5)->GetType() != SbxEMPTY )
1399                 lCount = rPar.Get(5)->GetLong();
1400             if( lCount < -1 || lCount > 0xffff )
1401             {
1402                 StarBASIC::Error( SbERR_BAD_ARGUMENT );
1403                 lCount = -1;
1404             }
1405         }
1406 
1407         SbiInstance* pInst = pINST;
1408         int bTextMode;
1409         bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1410         if( bCompatibility )
1411         {
1412             SbiRuntime* pRT = pInst ? pInst->pRun : NULL;
1413             bTextMode = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
1414         }
1415         else
1416         {
1417             bTextMode = 1;
1418         }
1419         if ( nArgCount == 6 )
1420             bTextMode = rPar.Get(6)->GetInteger();
1421 
1422         sal_uInt16 nExpStrLen = aExpStr.Len();
1423         sal_uInt16 nFindStrLen = aFindStr.Len();
1424         sal_uInt16 nReplaceStrLen = aReplaceStr.Len();
1425 
1426         if( lStartPos <= nExpStrLen )
1427         {
1428             sal_uInt16 nPos = static_cast<sal_uInt16>( lStartPos - 1 );
1429             sal_uInt16 nCounts = 0;
1430             while( lCount == -1 || lCount > nCounts )
1431             {
1432                 String aSrcStr( aExpStr );
1433                 if( bTextMode )
1434                 {
1435                     aSrcStr.ToUpperAscii();
1436                     aFindStr.ToUpperAscii();
1437                 }
1438                 nPos = aSrcStr.Search( aFindStr, nPos );
1439                 if( nPos != STRING_NOTFOUND )
1440                 {
1441                     aExpStr.Replace( nPos, nFindStrLen, aReplaceStr );
1442                     nPos = nPos - nFindStrLen + nReplaceStrLen + 1;
1443                     nCounts++;
1444                 }
1445                 else
1446                 {
1447                     break;
1448                 }
1449             }
1450         }
1451         rPar.Get(0)->PutString( aExpStr.Copy( static_cast<sal_uInt16>(lStartPos - 1) )  );
1452     }
1453 }
1454 
1455 RTLFUNC(Right)
1456 {
1457     (void)pBasic;
1458     (void)bWrite;
1459 
1460     if ( rPar.Count() < 3 )
1461         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1462     else
1463     {
1464         const String& rStr = rPar.Get(1)->GetString();
1465         sal_Int32 lResultLen = rPar.Get(2)->GetLong();
1466         if( lResultLen > 0xffff )
1467         {
1468             lResultLen = 0xffff;
1469         }
1470         else if( lResultLen < 0 )
1471         {
1472             lResultLen = 0;
1473             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1474         }
1475         sal_uInt16 nResultLen = (sal_uInt16)lResultLen;
1476         sal_uInt16 nStrLen = rStr.Len();
1477         if ( nResultLen > nStrLen )
1478             nResultLen = nStrLen;
1479         String aResultStr = rStr.Copy( nStrLen-nResultLen );
1480         rPar.Get(0)->PutString( aResultStr );
1481     }
1482 }
1483 
1484 RTLFUNC(RTL)
1485 {
1486     (void)pBasic;
1487     (void)bWrite;
1488 
1489     rPar.Get( 0 )->PutObject( pBasic->getRTL() );
1490 }
1491 
1492 RTLFUNC(RTrim)
1493 {
1494     (void)pBasic;
1495     (void)bWrite;
1496 
1497     if ( rPar.Count() < 2 )
1498         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1499     else
1500     {
1501         String aStr( rPar.Get(1)->GetString() );
1502         aStr.EraseTrailingChars();
1503         rPar.Get(0)->PutString( aStr );
1504     }
1505 }
1506 
1507 RTLFUNC(Sgn)
1508 {
1509     (void)pBasic;
1510     (void)bWrite;
1511 
1512     if ( rPar.Count() < 2 )
1513         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1514     else
1515     {
1516         double aDouble = rPar.Get(1)->GetDouble();
1517         sal_Int16 nResult = 0;
1518         if ( aDouble > 0 )
1519             nResult = 1;
1520         else if ( aDouble < 0 )
1521             nResult = -1;
1522         rPar.Get(0)->PutInteger( nResult );
1523     }
1524 }
1525 
1526 RTLFUNC(Space)
1527 {
1528     (void)pBasic;
1529     (void)bWrite;
1530 
1531     if ( rPar.Count() < 2 )
1532         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1533     else
1534     {
1535         String aStr;
1536         aStr.Fill( (sal_uInt16)(rPar.Get(1)->GetLong() ));
1537         rPar.Get(0)->PutString( aStr );
1538     }
1539 }
1540 
1541 RTLFUNC(Spc)
1542 {
1543     (void)pBasic;
1544     (void)bWrite;
1545 
1546     if ( rPar.Count() < 2 )
1547         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1548     else
1549     {
1550         String aStr;
1551         aStr.Fill( (sal_uInt16)(rPar.Get(1)->GetLong() ));
1552         rPar.Get(0)->PutString( aStr );
1553     }
1554 }
1555 
1556 RTLFUNC(Sqr)
1557 {
1558     (void)pBasic;
1559     (void)bWrite;
1560 
1561     if ( rPar.Count() < 2 )
1562         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1563     else
1564     {
1565         double aDouble = rPar.Get(1)->GetDouble();
1566         if ( aDouble >= 0 )
1567             rPar.Get(0)->PutDouble( sqrt( aDouble ));
1568         else
1569             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1570     }
1571 }
1572 
1573 RTLFUNC(Str)
1574 {
1575     (void)pBasic;
1576     (void)bWrite;
1577 
1578     if ( rPar.Count() < 2 )
1579         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1580     else
1581     {
1582         String aStr;
1583         SbxVariableRef pArg = rPar.Get( 1 );
1584         pArg->Format( aStr );
1585 
1586         // Numbers start with a space
1587         if( pArg->IsNumericRTL() )
1588         {
1589             // Kommas durch Punkte ersetzen, damit es symmetrisch zu Val ist!
1590             aStr.SearchAndReplace( ',', '.' );
1591 
1592             SbiInstance* pInst = pINST;
1593             bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1594             if( bCompatibility )
1595             {
1596                 xub_StrLen nLen = aStr.Len();
1597 
1598                 const sal_Unicode* pBuf = aStr.GetBuffer();
1599 
1600                 bool bNeg = ( pBuf[0] == '-' );
1601                 sal_uInt16 iZeroSearch = 0;
1602                 if( bNeg )
1603                     iZeroSearch++;
1604 
1605                 sal_uInt16 iNext = iZeroSearch + 1;
1606                 if( pBuf[iZeroSearch] == '0' && nLen > iNext && pBuf[iNext] == '.' )
1607                 {
1608                     aStr.Erase( iZeroSearch, 1 );
1609                     pBuf = aStr.GetBuffer();
1610                 }
1611                 if( !bNeg )
1612                     aStr.Insert( ' ', 0 );
1613             }
1614             else
1615                 aStr.Insert( ' ', 0 );
1616         }
1617         rPar.Get(0)->PutString( aStr );
1618     }
1619 }
1620 
1621 RTLFUNC(StrComp)
1622 {
1623     (void)pBasic;
1624     (void)bWrite;
1625 
1626     if ( rPar.Count() < 3 )
1627     {
1628         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1629         rPar.Get(0)->PutEmpty();
1630         return;
1631     }
1632     const String& rStr1 = rPar.Get(1)->GetString();
1633     const String& rStr2 = rPar.Get(2)->GetString();
1634 
1635     SbiInstance* pInst = pINST;
1636     sal_Int16 nTextCompare;
1637     bool bCompatibility = ( pInst && pInst->IsCompatibility() );
1638     if( bCompatibility )
1639     {
1640         SbiRuntime* pRT = pInst ? pInst->pRun : NULL;
1641         nTextCompare = pRT ? pRT->GetImageFlag( SBIMG_COMPARETEXT ) : sal_False;
1642     }
1643     else
1644     {
1645         nTextCompare = sal_True;
1646     }
1647     if ( rPar.Count() == 4 )
1648         nTextCompare = rPar.Get(3)->GetInteger();
1649 
1650     if( !bCompatibility )
1651         nTextCompare = !nTextCompare;
1652 
1653     StringCompare aResult;
1654     sal_Int32 nRetValue = 0;
1655     if( nTextCompare )
1656     {
1657         ::utl::TransliterationWrapper* pTransliterationWrapper = GetSbData()->pTransliterationWrapper;
1658         if( !pTransliterationWrapper )
1659         {
1660             com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
1661             pTransliterationWrapper = GetSbData()->pTransliterationWrapper =
1662                 new ::utl::TransliterationWrapper( xSMgr,
1663                     ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE |
1664                     ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA |
1665                     ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
1666         }
1667 
1668         LanguageType eLangType = GetpApp()->GetSettings().GetLanguage();
1669         pTransliterationWrapper->loadModuleIfNeeded( eLangType );
1670         nRetValue = pTransliterationWrapper->compareString( rStr1, rStr2 );
1671     }
1672     else
1673     {
1674         aResult = rStr1.CompareTo( rStr2 );
1675         if ( aResult == COMPARE_LESS )
1676             nRetValue = -1;
1677         else if ( aResult == COMPARE_GREATER )
1678             nRetValue = 1;
1679     }
1680 
1681     rPar.Get(0)->PutInteger( sal::static_int_cast< sal_Int16 >( nRetValue ) );
1682 }
1683 
1684 RTLFUNC(String)
1685 {
1686     (void)pBasic;
1687     (void)bWrite;
1688 
1689     if ( rPar.Count() < 2 )
1690         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1691     else
1692     {
1693         String aStr;
1694         sal_Unicode aFiller;
1695         sal_Int32 lCount = rPar.Get(1)->GetLong();
1696         if( lCount < 0 || lCount > 0xffff )
1697             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1698         sal_uInt16 nCount = (sal_uInt16)lCount;
1699         if( rPar.Get(2)->GetType() == SbxINTEGER )
1700             aFiller = (sal_Unicode)rPar.Get(2)->GetInteger();
1701         else
1702         {
1703             const String& rStr = rPar.Get(2)->GetString();
1704             aFiller = rStr.GetBuffer()[0];
1705         }
1706         aStr.Fill( nCount, aFiller );
1707         rPar.Get(0)->PutString( aStr );
1708     }
1709 }
1710 
1711 RTLFUNC(Tan)
1712 {
1713     (void)pBasic;
1714     (void)bWrite;
1715 
1716     if ( rPar.Count() < 2 )
1717         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1718     else
1719     {
1720         SbxVariableRef pArg = rPar.Get( 1 );
1721         rPar.Get( 0 )->PutDouble( tan( pArg->GetDouble() ) );
1722     }
1723 }
1724 
1725 RTLFUNC(UCase)
1726 {
1727     (void)pBasic;
1728     (void)bWrite;
1729 
1730     if ( rPar.Count() < 2 )
1731         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1732     else
1733     {
1734         CharClass& rCharClass = GetCharClass();
1735         String aStr( rPar.Get(1)->GetString() );
1736         rCharClass.toUpper( aStr );
1737         rPar.Get(0)->PutString( aStr );
1738     }
1739 }
1740 
1741 
1742 RTLFUNC(Val)
1743 {
1744     (void)pBasic;
1745     (void)bWrite;
1746 
1747     if ( rPar.Count() < 2 )
1748         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1749     else
1750     {
1751         double nResult = 0.0;
1752         char* pEndPtr;
1753 
1754         String aStr( rPar.Get(1)->GetString() );
1755 // lt. Mikkysoft bei Kommas abbrechen!
1756 //      for( sal_uInt16 n=0; n < aStr.Len(); n++ )
1757 //          if( aStr[n] == ',' ) aStr[n] = '.';
1758 
1759         FilterWhiteSpace( aStr );
1760         if ( aStr.GetBuffer()[0] == '&' && aStr.Len() > 1 )
1761         {
1762             int nRadix = 10;
1763             char aChar = (char)aStr.GetBuffer()[1];
1764             if ( aChar == 'h' || aChar == 'H' )
1765                 nRadix = 16;
1766             else if ( aChar == 'o' || aChar == 'O' )
1767                 nRadix = 8;
1768             if ( nRadix != 10 )
1769             {
1770                 ByteString aByteStr( aStr, gsl_getSystemTextEncoding() );
1771                 sal_Int16 nlResult = (sal_Int16)strtol( aByteStr.GetBuffer()+2, &pEndPtr, nRadix);
1772                 nResult = (double)nlResult;
1773             }
1774         }
1775         else
1776         {
1777             // #57844 Lokalisierte Funktion benutzen
1778             nResult = ::rtl::math::stringToDouble( aStr, '.', ',', NULL, NULL );
1779             checkArithmeticOverflow( nResult );
1780             // ATL: nResult = strtod( aStr.GetStr(), &pEndPtr );
1781         }
1782 
1783         rPar.Get(0)->PutDouble( nResult );
1784     }
1785 }
1786 
1787 
1788 // Helper functions for date conversion
1789 sal_Int16 implGetDateDay( double aDate )
1790 {
1791     aDate -= 2.0; // normieren: 1.1.1900 => 0.0
1792     Date aRefDate( 1, 1, 1900 );
1793     if ( aDate >= 0.0 )
1794     {
1795         aDate = floor( aDate );
1796         aRefDate += (sal_uIntPtr)aDate;
1797     }
1798     else
1799     {
1800         aDate = ceil( aDate );
1801         aRefDate -= (sal_uIntPtr)(-1.0 * aDate);
1802     }
1803 
1804     sal_Int16 nRet = (sal_Int16)( aRefDate.GetDay() );
1805     return nRet;
1806 }
1807 
1808 sal_Int16 implGetDateMonth( double aDate )
1809 {
1810     Date aRefDate( 1,1,1900 );
1811     long nDays = (long)aDate;
1812     nDays -= 2; // normieren: 1.1.1900 => 0.0
1813     aRefDate += nDays;
1814     sal_Int16 nRet = (sal_Int16)( aRefDate.GetMonth() );
1815     return nRet;
1816 }
1817 
1818 sal_Int16 implGetDateYear( double aDate )
1819 {
1820     Date aRefDate( 1,1,1900 );
1821     long nDays = (long) aDate;
1822     nDays -= 2; // normieren: 1.1.1900 => 0.0
1823     aRefDate += nDays;
1824     sal_Int16 nRet = (sal_Int16)( aRefDate.GetYear() );
1825     return nRet;
1826 }
1827 
1828 sal_Bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, double& rdRet )
1829 {
1830     if ( nYear < 30 && SbiRuntime::isVBAEnabled() )
1831         nYear += 2000;
1832     else if ( nYear < 100 )
1833         nYear += 1900;
1834     Date aCurDate( nDay, nMonth, nYear );
1835     if ((nYear < 100 || nYear > 9999) )
1836     {
1837         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1838         return sal_False;
1839     }
1840     if ( !SbiRuntime::isVBAEnabled() )
1841     {
1842         if ( (nMonth < 1 || nMonth > 12 )||
1843         (nDay < 1 || nDay > 31 ) )
1844         {
1845             StarBASIC::Error( SbERR_BAD_ARGUMENT );
1846             return sal_False;
1847         }
1848     }
1849     else
1850     {
1851         // grab the year & month
1852         aCurDate = Date( 1, (( nMonth % 12 ) > 0 ) ? ( nMonth % 12 ) : 12 + ( nMonth % 12 ), nYear );
1853 
1854         // adjust year based on month value
1855         // e.g. 2000, 0, xx = 1999, 12, xx ( or December of the previous year )
1856         //      2000, 13, xx = 2001, 1, xx ( or January of the following year )
1857         if( ( nMonth < 1 ) || ( nMonth > 12 ) )
1858         {
1859             // inacurrate around leap year, don't use days to calculate,
1860             // just modify the months directory
1861             sal_Int16 nYearAdj = ( nMonth /12 ); // default to positive months inputed
1862             if ( nMonth <=0 )
1863                 nYearAdj = ( ( nMonth -12 ) / 12 );
1864             aCurDate.SetYear( aCurDate.GetYear() + nYearAdj );
1865         }
1866 
1867         // adjust day value,
1868         // e.g. 2000, 2, 0 = 2000, 1, 31 or the last day of the previous month
1869         //      2000, 1, 32 = 2000, 2, 1 or the first day of the following month
1870         if( ( nDay < 1 ) || ( nDay > aCurDate.GetDaysInMonth() ) )
1871             aCurDate += nDay - 1;
1872         else
1873             aCurDate.SetDay( nDay );
1874     }
1875 
1876     long nDiffDays = GetDayDiff( aCurDate );
1877     rdRet = (double)nDiffDays;
1878     return sal_True;
1879 }
1880 
1881 // Function to convert date to ISO 8601 date format
1882 RTLFUNC(CDateToIso)
1883 {
1884     (void)pBasic;
1885     (void)bWrite;
1886 
1887     if ( rPar.Count() == 2 )
1888     {
1889         double aDate = rPar.Get(1)->GetDate();
1890 
1891         char Buffer[9];
1892         snprintf( Buffer, sizeof( Buffer ), "%04d%02d%02d",
1893             implGetDateYear( aDate ),
1894             implGetDateMonth( aDate ),
1895             implGetDateDay( aDate ) );
1896         String aRetStr = String::CreateFromAscii( Buffer );
1897         rPar.Get(0)->PutString( aRetStr );
1898     }
1899     else
1900         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1901 }
1902 
1903 // Function to convert date from ISO 8601 date format
1904 RTLFUNC(CDateFromIso)
1905 {
1906     (void)pBasic;
1907     (void)bWrite;
1908 
1909     if ( rPar.Count() == 2 )
1910     {
1911         String aStr = rPar.Get(1)->GetString();
1912         sal_Int16 iMonthStart = aStr.Len() - 4;
1913         String aYearStr  = aStr.Copy( 0, iMonthStart );
1914         String aMonthStr = aStr.Copy( iMonthStart, 2 );
1915         String aDayStr   = aStr.Copy( iMonthStart+2, 2 );
1916 
1917         double dDate;
1918         if( implDateSerial( (sal_Int16)aYearStr.ToInt32(),
1919             (sal_Int16)aMonthStr.ToInt32(), (sal_Int16)aDayStr.ToInt32(), dDate ) )
1920         {
1921             rPar.Get(0)->PutDate( dDate );
1922         }
1923     }
1924     else
1925         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1926 }
1927 
1928 RTLFUNC(DateSerial)
1929 {
1930     (void)pBasic;
1931     (void)bWrite;
1932 
1933     if ( rPar.Count() < 4 )
1934     {
1935         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1936         return;
1937     }
1938     sal_Int16 nYear = rPar.Get(1)->GetInteger();
1939     sal_Int16 nMonth = rPar.Get(2)->GetInteger();
1940     sal_Int16 nDay = rPar.Get(3)->GetInteger();
1941 
1942     double dDate;
1943     if( implDateSerial( nYear, nMonth, nDay, dDate ) )
1944         rPar.Get(0)->PutDate( dDate );
1945 }
1946 
1947 RTLFUNC(TimeSerial)
1948 {
1949     (void)pBasic;
1950     (void)bWrite;
1951 
1952     if ( rPar.Count() < 4 )
1953     {
1954         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1955         return;
1956     }
1957     sal_Int16 nHour = rPar.Get(1)->GetInteger();
1958     if ( nHour == 24 )
1959         nHour = 0;                      // Wegen UNO DateTimes, die bis 24 Uhr gehen
1960     sal_Int16 nMinute = rPar.Get(2)->GetInteger();
1961     sal_Int16 nSecond = rPar.Get(3)->GetInteger();
1962     if ((nHour < 0 || nHour > 23)   ||
1963         (nMinute < 0 || nMinute > 59 )  ||
1964         (nSecond < 0 || nSecond > 59 ))
1965     {
1966         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1967         return;
1968     }
1969 
1970     sal_Int32 nSeconds = nHour;
1971     nSeconds *= 3600;
1972     nSeconds += nMinute * 60;
1973     nSeconds += nSecond;
1974     double nDays = ((double)nSeconds) / (double)(86400.0);
1975     rPar.Get(0)->PutDate( nDays ); // JSM
1976 }
1977 
1978 RTLFUNC(DateValue)
1979 {
1980     (void)pBasic;
1981     (void)bWrite;
1982 
1983     if ( rPar.Count() < 2 )
1984         StarBASIC::Error( SbERR_BAD_ARGUMENT );
1985     else
1986     {
1987         // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden
1988         SvNumberFormatter* pFormatter = NULL;
1989         if( pINST )
1990             pFormatter = pINST->GetNumberFormatter();
1991         else
1992         {
1993             sal_uInt32 n;   // Dummy
1994             SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n );
1995         }
1996 
1997         sal_uInt32 nIndex;
1998         double fResult;
1999         String aStr( rPar.Get(1)->GetString() );
2000         sal_Bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult );
2001         short nType = pFormatter->GetType( nIndex );
2002 
2003         // DateValue("February 12, 1969") raises error if the system locale is not en_US
2004         // by using SbiInstance::GetNumberFormatter.
2005         // It seems that both locale number formatter and English number formatter
2006         // are supported in Visual Basic.
2007         LanguageType eLangType = GetpApp()->GetSettings().GetLanguage();
2008         if( !bSuccess && ( eLangType != LANGUAGE_ENGLISH_US ) )
2009         {
2010             // Create a new SvNumberFormatter by using LANGUAGE_ENGLISH to get the date value;
2011             com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >
2012                 xFactory = comphelper::getProcessServiceFactory();
2013             SvNumberFormatter aFormatter( xFactory, LANGUAGE_ENGLISH_US );
2014             bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, fResult );
2015             nType = aFormatter.GetType( nIndex );
2016         }
2017 
2018         if(bSuccess && (nType==NUMBERFORMAT_DATE || nType==NUMBERFORMAT_DATETIME))
2019         {
2020             if ( nType == NUMBERFORMAT_DATETIME )
2021             {
2022                 // Zeit abschneiden
2023                 if ( fResult  > 0.0 )
2024                     fResult = floor( fResult );
2025                 else
2026                     fResult = ceil( fResult );
2027             }
2028             // fResult += 2.0; // Anpassung  StarCalcFormatter
2029             rPar.Get(0)->PutDate( fResult ); // JSM
2030         }
2031         else
2032             StarBASIC::Error( SbERR_CONVERSION );
2033 
2034         // #39629 pFormatter kann selbst angefordert sein
2035         if( !pINST )
2036             delete pFormatter;
2037     }
2038 }
2039 
2040 RTLFUNC(TimeValue)
2041 {
2042     (void)pBasic;
2043     (void)bWrite;
2044 
2045     if ( rPar.Count() < 2 )
2046         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2047     else
2048     {
2049         // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden
2050         SvNumberFormatter* pFormatter = NULL;
2051         if( pINST )
2052             pFormatter = pINST->GetNumberFormatter();
2053         else
2054         {
2055             sal_uInt32 n;   // Dummy
2056             SbiInstance::PrepareNumberFormatter( pFormatter, n, n, n );
2057         }
2058 
2059         sal_uInt32 nIndex;
2060         double fResult;
2061         sal_Bool bSuccess = pFormatter->IsNumberFormat( rPar.Get(1)->GetString(),
2062                                                    nIndex, fResult );
2063         short nType = pFormatter->GetType(nIndex);
2064         if(bSuccess && (nType==NUMBERFORMAT_TIME||nType==NUMBERFORMAT_DATETIME))
2065         {
2066             if ( nType == NUMBERFORMAT_DATETIME )
2067                 // Tage abschneiden
2068                 fResult = fmod( fResult, 1 );
2069             rPar.Get(0)->PutDate( fResult ); // JSM
2070         }
2071         else
2072             StarBASIC::Error( SbERR_CONVERSION );
2073 
2074         // #39629 pFormatter kann selbst angefordert sein
2075         if( !pINST )
2076             delete pFormatter;
2077     }
2078 }
2079 
2080 RTLFUNC(Day)
2081 {
2082     (void)pBasic;
2083     (void)bWrite;
2084 
2085     if ( rPar.Count() < 2 )
2086         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2087     else
2088     {
2089         SbxVariableRef pArg = rPar.Get( 1 );
2090         double aDate = pArg->GetDate();
2091 
2092         sal_Int16 nDay = implGetDateDay( aDate );
2093         rPar.Get(0)->PutInteger( nDay );
2094     }
2095 }
2096 
2097 RTLFUNC(Year)
2098 {
2099     (void)pBasic;
2100     (void)bWrite;
2101 
2102     if ( rPar.Count() < 2 )
2103         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2104     else
2105     {
2106         sal_Int16 nYear = implGetDateYear( rPar.Get(1)->GetDate() );
2107         rPar.Get(0)->PutInteger( nYear );
2108     }
2109 }
2110 
2111 sal_Int16 implGetHour( double dDate )
2112 {
2113     if( dDate < 0.0 )
2114         dDate *= -1.0;
2115     double nFrac = dDate - floor( dDate );
2116     nFrac *= 86400.0;
2117     sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2118     sal_Int16 nHour = (sal_Int16)(nSeconds / 3600);
2119     return nHour;
2120 }
2121 
2122 RTLFUNC(Hour)
2123 {
2124     (void)pBasic;
2125     (void)bWrite;
2126 
2127     if ( rPar.Count() < 2 )
2128         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2129     else
2130     {
2131         double nArg = rPar.Get(1)->GetDate();
2132         sal_Int16 nHour = implGetHour( nArg );
2133         rPar.Get(0)->PutInteger( nHour );
2134     }
2135 }
2136 
2137 sal_Int16 implGetMinute( double dDate )
2138 {
2139     if( dDate < 0.0 )
2140         dDate *= -1.0;
2141     double nFrac = dDate - floor( dDate );
2142     nFrac *= 86400.0;
2143     sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2144     sal_Int16 nTemp = (sal_Int16)(nSeconds % 3600);
2145     sal_Int16 nMin = nTemp / 60;
2146     return nMin;
2147 }
2148 
2149 RTLFUNC(Minute)
2150 {
2151     (void)pBasic;
2152     (void)bWrite;
2153 
2154     if ( rPar.Count() < 2 )
2155         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2156     else
2157     {
2158         double nArg = rPar.Get(1)->GetDate();
2159         sal_Int16 nMin = implGetMinute( nArg );
2160         rPar.Get(0)->PutInteger( nMin );
2161     }
2162 }
2163 
2164 RTLFUNC(Month)
2165 {
2166     (void)pBasic;
2167     (void)bWrite;
2168 
2169     if ( rPar.Count() < 2 )
2170         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2171     else
2172     {
2173         sal_Int16 nMonth = implGetDateMonth( rPar.Get(1)->GetDate() );
2174         rPar.Get(0)->PutInteger( nMonth );
2175     }
2176 }
2177 
2178 sal_Int16 implGetSecond( double dDate )
2179 {
2180     if( dDate < 0.0 )
2181         dDate *= -1.0;
2182     double nFrac = dDate - floor( dDate );
2183     nFrac *= 86400.0;
2184     sal_Int32 nSeconds = (sal_Int32)(nFrac + 0.5);
2185     sal_Int16 nTemp = (sal_Int16)(nSeconds / 3600);
2186     nSeconds -= nTemp * 3600;
2187     nTemp = (sal_Int16)(nSeconds / 60);
2188     nSeconds -= nTemp * 60;
2189 
2190     sal_Int16 nRet = (sal_Int16)nSeconds;
2191     return nRet;
2192 }
2193 
2194 RTLFUNC(Second)
2195 {
2196     (void)pBasic;
2197     (void)bWrite;
2198 
2199     if ( rPar.Count() < 2 )
2200         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2201     else
2202     {
2203         double nArg = rPar.Get(1)->GetDate();
2204         sal_Int16 nSecond = implGetSecond( nArg );
2205         rPar.Get(0)->PutInteger( nSecond );
2206     }
2207 }
2208 
2209 double Now_Impl()
2210 {
2211     Date aDate;
2212     Time aTime;
2213     double aSerial = (double)GetDayDiff( aDate );
2214     long nSeconds = aTime.GetHour();
2215     nSeconds *= 3600;
2216     nSeconds += aTime.GetMin() * 60;
2217     nSeconds += aTime.GetSec();
2218     double nDays = ((double)nSeconds) / (double)(24.0*3600.0);
2219     aSerial += nDays;
2220     return aSerial;
2221 }
2222 
2223 // Date Now(void)
2224 
2225 RTLFUNC(Now)
2226 {
2227         (void)pBasic;
2228         (void)bWrite;
2229     rPar.Get(0)->PutDate( Now_Impl() );
2230 }
2231 
2232 // Date Time(void)
2233 
2234 RTLFUNC(Time)
2235 {
2236     (void)pBasic;
2237 
2238     if ( !bWrite )
2239     {
2240         Time aTime;
2241         SbxVariable* pMeth = rPar.Get( 0 );
2242         String aRes;
2243         if( pMeth->IsFixed() )
2244         {
2245             // Time$: hh:mm:ss
2246             char buf[ 20 ];
2247             snprintf( buf, sizeof(buf), "%02d:%02d:%02d",
2248                 aTime.GetHour(), aTime.GetMin(), aTime.GetSec() );
2249             aRes = String::CreateFromAscii( buf );
2250         }
2251         else
2252         {
2253             // Time: system dependent
2254             long nSeconds=aTime.GetHour();
2255             nSeconds *= 3600;
2256             nSeconds += aTime.GetMin() * 60;
2257             nSeconds += aTime.GetSec();
2258             double nDays = (double)nSeconds * ( 1.0 / (24.0*3600.0) );
2259             Color* pCol;
2260 
2261             // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden
2262             SvNumberFormatter* pFormatter = NULL;
2263             sal_uInt32 nIndex;
2264             if( pINST )
2265             {
2266                 pFormatter = pINST->GetNumberFormatter();
2267                 nIndex = pINST->GetStdTimeIdx();
2268             }
2269             else
2270             {
2271                 sal_uInt32 n;   // Dummy
2272                 SbiInstance::PrepareNumberFormatter( pFormatter, n, nIndex, n );
2273             }
2274 
2275             pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
2276 
2277             // #39629 pFormatter kann selbst angefordert sein
2278             if( !pINST )
2279                 delete pFormatter;
2280         }
2281         pMeth->PutString( aRes );
2282     }
2283     else
2284     {
2285         StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
2286     }
2287 }
2288 
2289 RTLFUNC(Timer)
2290 {
2291     (void)pBasic;
2292     (void)bWrite;
2293 
2294     Time aTime;
2295     long nSeconds = aTime.GetHour();
2296     nSeconds *= 3600;
2297     nSeconds += aTime.GetMin() * 60;
2298     nSeconds += aTime.GetSec();
2299     rPar.Get(0)->PutDate( (double)nSeconds );
2300 }
2301 
2302 
2303 RTLFUNC(Date)
2304 {
2305     (void)pBasic;
2306     (void)bWrite;
2307 
2308     if ( !bWrite )
2309     {
2310         Date aToday;
2311         double nDays = (double)GetDayDiff( aToday );
2312         SbxVariable* pMeth = rPar.Get( 0 );
2313         if( pMeth->IsString() )
2314         {
2315             String aRes;
2316             Color* pCol;
2317 
2318             // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden
2319             SvNumberFormatter* pFormatter = NULL;
2320             sal_uInt32 nIndex;
2321             if( pINST )
2322             {
2323                 pFormatter = pINST->GetNumberFormatter();
2324                 nIndex = pINST->GetStdDateIdx();
2325             }
2326             else
2327             {
2328                 sal_uInt32 n;   // Dummy
2329                 SbiInstance::PrepareNumberFormatter( pFormatter, nIndex, n, n );
2330             }
2331 
2332             pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
2333             pMeth->PutString( aRes );
2334 
2335             // #39629 pFormatter kann selbst angefordert sein
2336             if( !pINST )
2337                 delete pFormatter;
2338         }
2339         else
2340             pMeth->PutDate( nDays );
2341     }
2342     else
2343     {
2344         StarBASIC::Error( SbERR_NOT_IMPLEMENTED );
2345     }
2346 }
2347 
2348 RTLFUNC(IsArray)
2349 {
2350     (void)pBasic;
2351     (void)bWrite;
2352 
2353     if ( rPar.Count() < 2 )
2354         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2355     else
2356         rPar.Get(0)->PutBool((rPar.Get(1)->GetType() & SbxARRAY) ? sal_True : sal_False );
2357 }
2358 
2359 RTLFUNC(IsObject)
2360 {
2361     (void)pBasic;
2362     (void)bWrite;
2363 
2364     if ( rPar.Count() < 2 )
2365         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2366     else
2367     {
2368         SbxVariable* pVar = rPar.Get(1);
2369         SbxBase* pObj = (SbxBase*)pVar->GetObject();
2370 
2371         // #100385: GetObject can result in an error, so reset it
2372         SbxBase::ResetError();
2373 
2374         SbUnoClass* pUnoClass;
2375         sal_Bool bObject;
2376         if( pObj &&  NULL != ( pUnoClass=PTR_CAST(SbUnoClass,pObj) ) )
2377         {
2378             bObject = pUnoClass->getUnoClass().is();
2379         }
2380         else
2381         {
2382             bObject = pVar->IsObject();
2383         }
2384         rPar.Get( 0 )->PutBool( bObject );
2385     }
2386 }
2387 
2388 RTLFUNC(IsDate)
2389 {
2390     (void)pBasic;
2391     (void)bWrite;
2392 
2393     if ( rPar.Count() < 2 )
2394         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2395     else
2396     {
2397         // #46134 Nur String wird konvertiert, andere Typen ergeben sal_False
2398         SbxVariableRef xArg = rPar.Get( 1 );
2399         SbxDataType eType = xArg->GetType();
2400         sal_Bool bDate = sal_False;
2401 
2402         if( eType == SbxDATE )
2403         {
2404             bDate = sal_True;
2405         }
2406         else if( eType == SbxSTRING )
2407         {
2408             // Error loeschen
2409             SbxError nPrevError = SbxBase::GetError();
2410             SbxBase::ResetError();
2411 
2412             // Konvertierung des Parameters nach SbxDATE erzwingen
2413             xArg->SbxValue::GetDate();
2414 
2415             // Bei Fehler ist es kein Date
2416             bDate = !SbxBase::IsError();
2417 
2418             // Error-Situation wiederherstellen
2419             SbxBase::ResetError();
2420             SbxBase::SetError( nPrevError );
2421         }
2422         rPar.Get( 0 )->PutBool( bDate );
2423     }
2424 }
2425 
2426 RTLFUNC(IsEmpty)
2427 {
2428     (void)pBasic;
2429     (void)bWrite;
2430 
2431     if ( rPar.Count() < 2 )
2432         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2433     else
2434         rPar.Get( 0 )->PutBool( rPar.Get(1)->IsEmpty() );
2435 }
2436 
2437 RTLFUNC(IsError)
2438 {
2439     (void)pBasic;
2440     (void)bWrite;
2441 
2442     if ( rPar.Count() < 2 )
2443         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2444     else
2445         rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() );
2446 }
2447 
2448 RTLFUNC(IsNull)
2449 {
2450     (void)pBasic;
2451     (void)bWrite;
2452 
2453     if ( rPar.Count() < 2 )
2454         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2455     else
2456     {
2457         // #51475 Wegen Uno-Objekten auch true liefern,
2458         // wenn der pObj-Wert NULL ist
2459         SbxVariableRef pArg = rPar.Get( 1 );
2460         sal_Bool bNull = rPar.Get(1)->IsNull();
2461         if( !bNull && pArg->GetType() == SbxOBJECT )
2462         {
2463             SbxBase* pObj = pArg->GetObject();
2464             if( !pObj )
2465                 bNull = sal_True;
2466         }
2467         rPar.Get( 0 )->PutBool( bNull );
2468     }
2469 }
2470 
2471 RTLFUNC(IsNumeric)
2472 {
2473     (void)pBasic;
2474     (void)bWrite;
2475 
2476     if ( rPar.Count() < 2 )
2477         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2478     else
2479         rPar.Get( 0 )->PutBool( rPar.Get( 1 )->IsNumericRTL() );
2480 }
2481 
2482 // Das machen wir auf die billige Tour
2483 
2484 RTLFUNC(IsMissing)
2485 {
2486     (void)pBasic;
2487     (void)bWrite;
2488 
2489     if ( rPar.Count() < 2 )
2490         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2491     else
2492         // #57915 Missing wird durch Error angezeigt
2493         rPar.Get( 0 )->PutBool( rPar.Get(1)->IsErr() );
2494 }
2495 
2496 // Dir( [Maske] [,Attrs] )
2497 // ToDo: Library-globaler Datenbereich fuer Dir-Objekt und Flags
2498 
2499 
2500 String getDirectoryPath( String aPathStr )
2501 {
2502     String aRetStr;
2503 
2504     DirectoryItem aItem;
2505     FileBase::RC nRet = DirectoryItem::get( aPathStr, aItem );
2506     if( nRet == FileBase::E_None )
2507     {
2508         FileStatus aFileStatus( FileStatusMask_Type );
2509         nRet = aItem.getFileStatus( aFileStatus );
2510         if( nRet == FileBase::E_None )
2511         {
2512             FileStatus::Type aType = aFileStatus.getFileType();
2513             if( isFolder( aType ) )
2514             {
2515                 aRetStr = aPathStr;
2516             }
2517             else if( aType == FileStatus::Link )
2518             {
2519                 FileStatus aFileStatus2( FileStatusMask_LinkTargetURL );
2520                 nRet = aItem.getFileStatus( aFileStatus2 );
2521                 if( nRet == FileBase::E_None )
2522                     aRetStr = getDirectoryPath( aFileStatus2.getLinkTargetURL() );
2523             }
2524         }
2525     }
2526     return aRetStr;
2527 }
2528 
2529 // Function looks for wildcards, removes them and always returns the pure path
2530 String implSetupWildcard( const String& rFileParam, SbiRTLData* pRTLData )
2531 {
2532     static String aAsterisk = String::CreateFromAscii( "*" );
2533     static sal_Char cDelim1 = (sal_Char)'/';
2534     static sal_Char cDelim2 = (sal_Char)'\\';
2535     static sal_Char cWild1 = '*';
2536     static sal_Char cWild2 = '?';
2537 
2538     delete pRTLData->pWildCard;
2539     pRTLData->pWildCard = NULL;
2540     pRTLData->sFullNameToBeChecked = String();
2541 
2542     String aFileParam = rFileParam;
2543     xub_StrLen nLastWild = aFileParam.SearchBackward( cWild1 );
2544     if( nLastWild == STRING_NOTFOUND )
2545         nLastWild = aFileParam.SearchBackward( cWild2 );
2546     sal_Bool bHasWildcards = ( nLastWild != STRING_NOTFOUND );
2547 
2548 
2549     xub_StrLen nLastDelim = aFileParam.SearchBackward( cDelim1 );
2550     if( nLastDelim == STRING_NOTFOUND )
2551         nLastDelim = aFileParam.SearchBackward( cDelim2 );
2552 
2553     if( bHasWildcards )
2554     {
2555         // Wildcards in path?
2556         if( nLastDelim != STRING_NOTFOUND && nLastDelim > nLastWild )
2557             return aFileParam;
2558     }
2559     else
2560     {
2561         String aPathStr = getFullPath( aFileParam );
2562         if( nLastDelim != aFileParam.Len() - 1 )
2563             pRTLData->sFullNameToBeChecked = aPathStr;
2564         return aPathStr;
2565     }
2566 
2567     String aPureFileName;
2568     if( nLastDelim == STRING_NOTFOUND )
2569     {
2570         aPureFileName = aFileParam;
2571         aFileParam = String();
2572     }
2573     else
2574     {
2575         aPureFileName = aFileParam.Copy( nLastDelim + 1 );
2576         aFileParam = aFileParam.Copy( 0, nLastDelim );
2577     }
2578 
2579     // Try again to get a valid URL/UNC-path with only the path
2580     String aPathStr = getFullPath( aFileParam );
2581     xub_StrLen nPureLen = aPureFileName.Len();
2582 
2583     // Is there a pure file name left? Otherwise the path is
2584     // invalid anyway because it was not accepted by OSL before
2585     if( nPureLen && aPureFileName != aAsterisk )
2586     {
2587         pRTLData->pWildCard = new WildCard( aPureFileName );
2588     }
2589     return aPathStr;
2590 }
2591 
2592 inline sal_Bool implCheckWildcard( const String& rName, SbiRTLData* pRTLData )
2593 {
2594     sal_Bool bMatch = sal_True;
2595 
2596     if( pRTLData->pWildCard )
2597         bMatch = pRTLData->pWildCard->Matches( rName );
2598     return bMatch;
2599 }
2600 
2601 
2602 bool isRootDir( String aDirURLStr )
2603 {
2604     INetURLObject aDirURLObj( aDirURLStr );
2605     sal_Bool bRoot = sal_False;
2606 
2607     // Check if it's a root directory
2608     sal_Int32 nCount = aDirURLObj.getSegmentCount();
2609 
2610     // No segment means Unix root directory "file:///"
2611     if( nCount == 0 )
2612     {
2613         bRoot = sal_True;
2614     }
2615     // Exactly one segment needs further checking, because it
2616     // can be Unix "file:///foo/" -> no root
2617     // or Windows  "file:///c:/"  -> root
2618     else if( nCount == 1 )
2619     {
2620         ::rtl::OUString aSeg1 = aDirURLObj.getName( 0, sal_True,
2621             INetURLObject::DECODE_WITH_CHARSET );
2622         if( aSeg1.getStr()[1] == (sal_Unicode)':' )
2623         {
2624             bRoot = sal_True;
2625         }
2626     }
2627     // More than one segments can never be root
2628     // so bRoot remains sal_False
2629 
2630     return bRoot;
2631 }
2632 
2633 RTLFUNC(Dir)
2634 {
2635     (void)pBasic;
2636     (void)bWrite;
2637 
2638     String aPath;
2639 
2640     sal_uInt16 nParCount = rPar.Count();
2641     if( nParCount > 3 )
2642         StarBASIC::Error( SbERR_BAD_ARGUMENT );
2643     else
2644     {
2645         SbiRTLData* pRTLData = pINST->GetRTLData();
2646 
2647         // #34645: Kann auch von der URL-Zeile ueber 'macro: Dir' aufgerufen werden
2648         // dann existiert kein pRTLData und die Methode muss verlassen werden
2649         if( !pRTLData )
2650             return;
2651 
2652         // <-- UCB
2653         if( hasUno() )
2654         {
2655             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
2656             if( xSFI.is() )
2657             {
2658                 if ( nParCount >= 2 )
2659                 {
2660                     String aFileParam = rPar.Get(1)->GetString();
2661 
2662                     String aFileURLStr = implSetupWildcard( aFileParam, pRTLData );
2663                     if( pRTLData->sFullNameToBeChecked.Len() > 0 )
2664                     {
2665                         sal_Bool bExists = sal_False;
2666                         try { bExists = xSFI->exists( aFileURLStr ); }
2667                         catch( Exception & ) {}
2668 
2669                         String aNameOnlyStr;
2670                         if( bExists )
2671                         {
2672                             INetURLObject aFileURL( aFileURLStr );
2673                             aNameOnlyStr = aFileURL.getName( INetURLObject::LAST_SEGMENT,
2674                                 true, INetURLObject::DECODE_WITH_CHARSET );
2675                         }
2676                         rPar.Get(0)->PutString( aNameOnlyStr );
2677                         return;
2678                     }
2679 
2680                     try
2681                     {
2682                         String aDirURLStr;
2683                         sal_Bool bFolder = xSFI->isFolder( aFileURLStr );
2684 
2685                         if( bFolder )
2686                         {
2687                             aDirURLStr = aFileURLStr;
2688                         }
2689                         else
2690                         {
2691                             String aEmptyStr;
2692                             rPar.Get(0)->PutString( aEmptyStr );
2693                         }
2694 
2695                         sal_uInt16 nFlags = 0;
2696                         if ( nParCount > 2 )
2697                             pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
2698                         else
2699                             pRTLData->nDirFlags = 0;
2700 
2701                         // Read directory
2702                         sal_Bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0);
2703                         pRTLData->aDirSeq = xSFI->getFolderContents( aDirURLStr, bIncludeFolders );
2704                         pRTLData->nCurDirPos = 0;
2705 
2706                         // #78651 Add "." and ".." directories for VB compatibility
2707                         if( bIncludeFolders )
2708                         {
2709                             sal_Bool bRoot = isRootDir( aDirURLStr );
2710 
2711                             // If it's no root directory we flag the need for
2712                             // the "." and ".." directories by the value -2
2713                             // for the actual position. Later for -2 will be
2714                             // returned "." and for -1 ".."
2715                             if( !bRoot )
2716                             {
2717                                 pRTLData->nCurDirPos = -2;
2718                             }
2719                         }
2720                     }
2721                     catch( Exception & )
2722                     {
2723                         //StarBASIC::Error( ERRCODE_IO_GENERAL );
2724                     }
2725                 }
2726 
2727 
2728                 if( pRTLData->aDirSeq.getLength() > 0 )
2729                 {
2730                     sal_Bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0);
2731 
2732                     SbiInstance* pInst = pINST;
2733                     bool bCompatibility = ( pInst && pInst->IsCompatibility() );
2734                     for( ;; )
2735                     {
2736                         if( pRTLData->nCurDirPos < 0 )
2737                         {
2738                             if( pRTLData->nCurDirPos == -2 )
2739                             {
2740                                 aPath = ::rtl::OUString::createFromAscii( "." );
2741                             }
2742                             else if( pRTLData->nCurDirPos == -1 )
2743                             {
2744                                 aPath = ::rtl::OUString::createFromAscii( ".." );
2745                             }
2746                             pRTLData->nCurDirPos++;
2747                         }
2748                         else if( pRTLData->nCurDirPos >= pRTLData->aDirSeq.getLength() )
2749                         {
2750                             pRTLData->aDirSeq.realloc( 0 );
2751                             aPath.Erase();
2752                             break;
2753                         }
2754                         else
2755                         {
2756                             ::rtl::OUString aFile = pRTLData->aDirSeq.getConstArray()[pRTLData->nCurDirPos++];
2757 
2758                             if( bCompatibility )
2759                             {
2760                                 if( !bFolderFlag )
2761                                 {
2762                                     sal_Bool bFolder = xSFI->isFolder( aFile );
2763                                     if( bFolder )
2764                                         continue;
2765                                 }
2766                             }
2767                             else
2768                             {
2769                                 // Only directories
2770                                 if( bFolderFlag )
2771                                 {
2772                                     sal_Bool bFolder = xSFI->isFolder( aFile );
2773                                     if( !bFolder )
2774                                         continue;
2775                                 }
2776                             }
2777 
2778                             INetURLObject aURL( aFile );
2779                             aPath = aURL.getName( INetURLObject::LAST_SEGMENT, sal_True,
2780                                 INetURLObject::DECODE_WITH_CHARSET );
2781                         }
2782 
2783                         sal_Bool bMatch = implCheckWildcard( aPath, pRTLData );
2784                         if( !bMatch )
2785                             continue;
2786 
2787                         break;
2788                     }
2789                 }
2790                 rPar.Get(0)->PutString( aPath );
2791             }
2792         }
2793         else
2794         // --> UCB
2795         {
2796 #ifdef _OLD_FILE_IMPL
2797             if ( nParCount >= 2 )
2798             {
2799                 delete pRTLData->pDir;
2800                 pRTLData->pDir = 0; // wg. Sonderbehandlung Sb_ATTR_VOLUME
2801                 DirEntry aEntry( rPar.Get(1)->GetString() );
2802                 FileStat aStat( aEntry );
2803                 if(!aStat.GetError() && (aStat.GetKind() & FSYS_KIND_FILE))
2804                 {
2805                     // ah ja, ist nur ein dateiname
2806                     // Pfad abschneiden (wg. VB4)
2807                     rPar.Get(0)->PutString( aEntry.GetName() );
2808                     return;
2809                 }
2810                 sal_uInt16 nFlags = 0;
2811                 if ( nParCount > 2 )
2812                     pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
2813                 else
2814                     pRTLData->nDirFlags = 0;
2815 
2816                 // Sb_ATTR_VOLUME wird getrennt gehandelt
2817                 if( pRTLData->nDirFlags & Sb_ATTR_VOLUME )
2818                     aPath = aEntry.GetVolume();
2819                 else
2820                 {
2821                     // Die richtige Auswahl treffen
2822                     sal_uInt16 nMode = FSYS_KIND_FILE;
2823                     if( nFlags & Sb_ATTR_DIRECTORY )
2824                         nMode |= FSYS_KIND_DIR;
2825                     if( nFlags == Sb_ATTR_DIRECTORY )
2826                         nMode = FSYS_KIND_DIR;
2827                     pRTLData->pDir = new Dir( aEntry, (DirEntryKind) nMode );
2828                     pRTLData->nCurDirPos = 0;
2829                 }
2830             }
2831 
2832             if( pRTLData->pDir )
2833             {
2834                 for( ;; )
2835                 {
2836                     if( pRTLData->nCurDirPos >= pRTLData->pDir->Count() )
2837                     {
2838                         delete pRTLData->pDir;
2839                         pRTLData->pDir = 0;
2840                         aPath.Erase();
2841                         break;
2842                     }
2843                     DirEntry aNextEntry=(*(pRTLData->pDir))[pRTLData->nCurDirPos++];
2844                     aPath = aNextEntry.GetName(); //Full();
2845                     break;
2846                 }
2847             }
2848             rPar.Get(0)->PutString( aPath );
2849 #else
2850             // TODO: OSL
2851             if ( nParCount >= 2 )
2852             {
2853                 String aFileParam = rPar.Get(1)->GetString();
2854 
2855                 String aDirURL = implSetupWildcard( aFileParam, pRTLData );
2856 
2857                 sal_uInt16 nFlags = 0;
2858                 if ( nParCount > 2 )
2859                     pRTLData->nDirFlags = nFlags = rPar.Get(2)->GetInteger();
2860                 else
2861                     pRTLData->nDirFlags = 0;
2862 
2863                 // Read directory
2864                 sal_Bool bIncludeFolders = ((nFlags & Sb_ATTR_DIRECTORY) != 0);
2865                 pRTLData->pDir = new Directory( aDirURL );
2866                 FileBase::RC nRet = pRTLData->pDir->open();
2867                 if( nRet != FileBase::E_None )
2868                 {
2869                     delete pRTLData->pDir;
2870                     pRTLData->pDir = NULL;
2871                     rPar.Get(0)->PutString( String() );
2872                     return;
2873                 }
2874 
2875                 // #86950 Add "." and ".." directories for VB compatibility
2876                 pRTLData->nCurDirPos = 0;
2877                 if( bIncludeFolders )
2878                 {
2879                     sal_Bool bRoot = isRootDir( aDirURL );
2880 
2881                     // If it's no root directory we flag the need for
2882                     // the "." and ".." directories by the value -2
2883                     // for the actual position. Later for -2 will be
2884                     // returned "." and for -1 ".."
2885                     if( !bRoot )
2886                     {
2887                         pRTLData->nCurDirPos = -2;
2888                     }
2889                 }
2890 
2891             }
2892 
2893             if( pRTLData->pDir )
2894             {
2895                 sal_Bool bFolderFlag = ((pRTLData->nDirFlags & Sb_ATTR_DIRECTORY) != 0);
2896                 for( ;; )
2897                 {
2898                     if( pRTLData->nCurDirPos < 0 )
2899                     {
2900                         if( pRTLData->nCurDirPos == -2 )
2901                         {
2902                             aPath = ::rtl::OUString::createFromAscii( "." );
2903                         }
2904                         else if( pRTLData->nCurDirPos == -1 )
2905                         {
2906                             aPath = ::rtl::OUString::createFromAscii( ".." );
2907                         }
2908                         pRTLData->nCurDirPos++;
2909                     }
2910                     else
2911                     {
2912                         DirectoryItem aItem;
2913                         FileBase::RC nRet = pRTLData->pDir->getNextItem( aItem );
2914                         if( nRet != FileBase::E_None )
2915                         {
2916                             delete pRTLData->pDir;
2917                             pRTLData->pDir = NULL;
2918                             aPath.Erase();
2919                             break;
2920                         }
2921 
2922                         // Handle flags
2923                         FileStatus aFileStatus( FileStatusMask_Type | FileStatusMask_FileName );
2924                         nRet = aItem.getFileStatus( aFileStatus );
2925 
2926                         // Only directories?
2927                         if( bFolderFlag )
2928                         {
2929                             FileStatus::Type aType = aFileStatus.getFileType();
2930                             sal_Bool bFolder = isFolder( aType );
2931                             if( !bFolder )
2932                                 continue;
2933                         }
2934 
2935                         aPath = aFileStatus.getFileName();
2936                     }
2937 
2938                     sal_Bool bMatch = implCheckWildcard( aPath, pRTLData );
2939                     if( !bMatch )
2940                         continue;
2941 
2942                     break;
2943                 }
2944             }
2945             rPar.Get(0)->PutString( aPath );
2946 #endif
2947         }
2948     }
2949 }
2950 
2951 
2952 RTLFUNC(GetAttr)
2953 {
2954     (void)pBasic;
2955     (void)bWrite;
2956 
2957     if ( rPar.Count() == 2 )
2958     {
2959         sal_Int16 nFlags = 0;
2960 
2961         // In Windows, We want to use Windows API to get the file attributes
2962         // for VBA interoperability.
2963     #if defined( WNT )
2964         if( SbiRuntime::isVBAEnabled() )
2965         {
2966             DirEntry aEntry( rPar.Get(1)->GetString() );
2967             aEntry.ToAbs();
2968 
2969             // #57064 Bei virtuellen URLs den Real-Path extrahieren
2970             ByteString aByteStrFullPath( aEntry.GetFull(), gsl_getSystemTextEncoding() );
2971             DWORD nRealFlags = GetFileAttributes (aByteStrFullPath.GetBuffer());
2972             if (nRealFlags != 0xffffffff)
2973             {
2974                 if (nRealFlags == FILE_ATTRIBUTE_NORMAL)
2975                     nRealFlags = 0;
2976                 nFlags = (sal_Int16) (nRealFlags);
2977             }
2978             else
2979                 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
2980 
2981             rPar.Get(0)->PutInteger( nFlags );
2982 
2983             return;
2984         }
2985     #endif
2986 
2987         // <-- UCB
2988         if( hasUno() )
2989         {
2990             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
2991             if( xSFI.is() )
2992             {
2993                 try
2994                 {
2995                     String aPath = getFullPath( rPar.Get(1)->GetString() );
2996                     sal_Bool bExists = sal_False;
2997                     try { bExists = xSFI->exists( aPath ); }
2998                     catch( Exception & ) {}
2999                     if( !bExists )
3000                     {
3001                         StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3002                         return;
3003                     }
3004 
3005                     sal_Bool bReadOnly = xSFI->isReadOnly( aPath );
3006                     sal_Bool bHidden = xSFI->isHidden( aPath );
3007                     sal_Bool bDirectory = xSFI->isFolder( aPath );
3008                     if( bReadOnly )
3009                         nFlags |= 0x0001; // ATTR_READONLY
3010                     if( bHidden )
3011                         nFlags |= 0x0002; // ATTR_HIDDEN
3012                     if( bDirectory )
3013                         nFlags |= 0x0010; // ATTR_DIRECTORY
3014                 }
3015                 catch( Exception & )
3016                 {
3017                     StarBASIC::Error( ERRCODE_IO_GENERAL );
3018                 }
3019             }
3020         }
3021         else
3022         // --> UCB
3023         {
3024             DirectoryItem aItem;
3025             FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( rPar.Get(1)->GetString() ), aItem );
3026             FileStatus aFileStatus( FileStatusMask_Attributes | FileStatusMask_Type );
3027             nRet = aItem.getFileStatus( aFileStatus );
3028             sal_uInt64 nAttributes = aFileStatus.getAttributes();
3029             sal_Bool bReadOnly = (nAttributes & Attribute_ReadOnly) != 0;
3030 
3031             FileStatus::Type aType = aFileStatus.getFileType();
3032             sal_Bool bDirectory = isFolder( aType );
3033             if( bReadOnly )
3034                 nFlags |= 0x0001; // ATTR_READONLY
3035             if( bDirectory )
3036                 nFlags |= 0x0010; // ATTR_DIRECTORY
3037         }
3038         rPar.Get(0)->PutInteger( nFlags );
3039     }
3040     else
3041         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3042 }
3043 
3044 
3045 RTLFUNC(FileDateTime)
3046 {
3047     (void)pBasic;
3048     (void)bWrite;
3049 
3050     if ( rPar.Count() != 2 )
3051         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3052     else
3053     {
3054         // <-- UCB
3055         String aPath = rPar.Get(1)->GetString();
3056         Time aTime;
3057         Date aDate;
3058         if( hasUno() )
3059         {
3060             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
3061             if( xSFI.is() )
3062             {
3063                 try
3064                 {
3065                     com::sun::star::util::DateTime aUnoDT = xSFI->getDateTimeModified( aPath );
3066                     aTime = Time( aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, aUnoDT.HundredthSeconds );
3067                     aDate = Date( aUnoDT.Day, aUnoDT.Month, aUnoDT.Year );
3068                 }
3069                 catch( Exception & )
3070                 {
3071                     StarBASIC::Error( ERRCODE_IO_GENERAL );
3072                 }
3073             }
3074         }
3075         else
3076         // --> UCB
3077         {
3078 #ifdef _OLD_FILE_IMPL
3079             DirEntry aEntry( aPath );
3080             FileStat aStat( aEntry );
3081             aTime = Time( aStat.TimeModified() );
3082             aDate = Date( aStat.DateModified() );
3083 #else
3084             DirectoryItem aItem;
3085             FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( aPath ), aItem );
3086             FileStatus aFileStatus( FileStatusMask_ModifyTime );
3087             nRet = aItem.getFileStatus( aFileStatus );
3088             TimeValue aTimeVal = aFileStatus.getModifyTime();
3089             oslDateTime aDT;
3090             osl_getDateTimeFromTimeValue( &aTimeVal, &aDT );
3091 
3092             aTime = Time( aDT.Hours, aDT.Minutes, aDT.Seconds, 10000000*aDT.NanoSeconds );
3093             aDate = Date( aDT.Day, aDT.Month, aDT.Year );
3094 #endif
3095         }
3096 
3097         double fSerial = (double)GetDayDiff( aDate );
3098         long nSeconds = aTime.GetHour();
3099         nSeconds *= 3600;
3100         nSeconds += aTime.GetMin() * 60;
3101         nSeconds += aTime.GetSec();
3102         double nDays = ((double)nSeconds) / (double)(24.0*3600.0);
3103         fSerial += nDays;
3104 
3105         Color* pCol;
3106 
3107         // #39629 pINST pruefen, kann aus URL-Zeile gerufen werden
3108         SvNumberFormatter* pFormatter = NULL;
3109         sal_uInt32 nIndex;
3110         if( pINST )
3111         {
3112             pFormatter = pINST->GetNumberFormatter();
3113             nIndex = pINST->GetStdDateTimeIdx();
3114         }
3115         else
3116         {
3117             sal_uInt32 n;   // Dummy
3118             SbiInstance::PrepareNumberFormatter( pFormatter, n, n, nIndex );
3119         }
3120 
3121         String aRes;
3122         pFormatter->GetOutputString( fSerial, nIndex, aRes, &pCol );
3123         rPar.Get(0)->PutString( aRes );
3124 
3125         // #39629 pFormatter kann selbst angefordert sein
3126         if( !pINST )
3127             delete pFormatter;
3128     }
3129 }
3130 
3131 
3132 RTLFUNC(EOF)
3133 {
3134     (void)pBasic;
3135     (void)bWrite;
3136 
3137     // AB 08/16/2000: No changes for UCB
3138     if ( rPar.Count() != 2 )
3139         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3140     else
3141     {
3142         sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3143         // nChannel--;  // macht MD beim Oeffnen auch nicht
3144         SbiIoSystem* pIO = pINST->GetIoSystem();
3145         SbiStream* pSbStrm = pIO->GetStream( nChannel );
3146         if ( !pSbStrm )
3147         {
3148             StarBASIC::Error( SbERR_BAD_CHANNEL );
3149             return;
3150         }
3151         sal_Bool bIsEof;
3152         SvStream* pSvStrm = pSbStrm->GetStrm();
3153         if ( pSbStrm->IsText() )
3154         {
3155             char cBla;
3156             (*pSvStrm) >> cBla; // koennen wir noch ein Zeichen lesen
3157             bIsEof = pSvStrm->IsEof();
3158             if ( !bIsEof )
3159                 pSvStrm->SeekRel( -1 );
3160         }
3161         else
3162             bIsEof = pSvStrm->IsEof();  // fuer binaerdateien!
3163         rPar.Get(0)->PutBool( bIsEof );
3164     }
3165 }
3166 
3167 RTLFUNC(FileAttr)
3168 {
3169     (void)pBasic;
3170     (void)bWrite;
3171 
3172     // AB 08/16/2000: No changes for UCB
3173 
3174     // #57064 Obwohl diese Funktion nicht mit DirEntry arbeitet, ist sie von
3175     // der Anpassung an virtuelle URLs nich betroffen, da sie nur auf bereits
3176     // geoeffneten Dateien arbeitet und der Name hier keine Rolle spielt.
3177 
3178     if ( rPar.Count() != 3 )
3179         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3180     else
3181     {
3182         sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3183 //      nChannel--;
3184         SbiIoSystem* pIO = pINST->GetIoSystem();
3185         SbiStream* pSbStrm = pIO->GetStream( nChannel );
3186         if ( !pSbStrm )
3187         {
3188             StarBASIC::Error( SbERR_BAD_CHANNEL );
3189             return;
3190         }
3191         sal_Int16 nRet;
3192         if ( rPar.Get(2)->GetInteger() == 1 )
3193             nRet = (sal_Int16)(pSbStrm->GetMode());
3194         else
3195             nRet = 0; // System file handle not supported
3196 
3197         rPar.Get(0)->PutInteger( nRet );
3198     }
3199 }
3200 RTLFUNC(Loc)
3201 {
3202     (void)pBasic;
3203     (void)bWrite;
3204 
3205     // AB 08/16/2000: No changes for UCB
3206     if ( rPar.Count() != 2 )
3207         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3208     else
3209     {
3210         sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3211         SbiIoSystem* pIO = pINST->GetIoSystem();
3212         SbiStream* pSbStrm = pIO->GetStream( nChannel );
3213         if ( !pSbStrm )
3214         {
3215             StarBASIC::Error( SbERR_BAD_CHANNEL );
3216             return;
3217         }
3218         SvStream* pSvStrm = pSbStrm->GetStrm();
3219         sal_uIntPtr nPos;
3220         if( pSbStrm->IsRandom())
3221         {
3222             short nBlockLen = pSbStrm->GetBlockLen();
3223             nPos = nBlockLen ? (pSvStrm->Tell() / nBlockLen) : 0;
3224             nPos++; // Blockpositionen beginnen bei 1
3225         }
3226         else if ( pSbStrm->IsText() )
3227             nPos = pSbStrm->GetLine();
3228         else if( pSbStrm->IsBinary() )
3229             nPos = pSvStrm->Tell();
3230         else if ( pSbStrm->IsSeq() )
3231             nPos = ( pSvStrm->Tell()+1 ) / 128;
3232         else
3233             nPos = pSvStrm->Tell();
3234         rPar.Get(0)->PutLong( (sal_Int32)nPos );
3235     }
3236 }
3237 
3238 RTLFUNC(Lof)
3239 {
3240     (void)pBasic;
3241     (void)bWrite;
3242 
3243     // AB 08/16/2000: No changes for UCB
3244     if ( rPar.Count() != 2 )
3245         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3246     else
3247     {
3248         sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3249         SbiIoSystem* pIO = pINST->GetIoSystem();
3250         SbiStream* pSbStrm = pIO->GetStream( nChannel );
3251         if ( !pSbStrm )
3252         {
3253             StarBASIC::Error( SbERR_BAD_CHANNEL );
3254             return;
3255         }
3256         SvStream* pSvStrm = pSbStrm->GetStrm();
3257         sal_uIntPtr nOldPos = pSvStrm->Tell();
3258         sal_uIntPtr nLen = pSvStrm->Seek( STREAM_SEEK_TO_END );
3259         pSvStrm->Seek( nOldPos );
3260         rPar.Get(0)->PutLong( (sal_Int32)nLen );
3261     }
3262 }
3263 
3264 
3265 RTLFUNC(Seek)
3266 {
3267     (void)pBasic;
3268     (void)bWrite;
3269 
3270     // AB 08/16/2000: No changes for UCB
3271     int nArgs = (int)rPar.Count();
3272     if ( nArgs < 2 || nArgs > 3 )
3273     {
3274         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3275         return;
3276     }
3277     sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3278 //  nChannel--;
3279     SbiIoSystem* pIO = pINST->GetIoSystem();
3280     SbiStream* pSbStrm = pIO->GetStream( nChannel );
3281     if ( !pSbStrm )
3282     {
3283         StarBASIC::Error( SbERR_BAD_CHANNEL );
3284         return;
3285     }
3286     SvStream* pStrm = pSbStrm->GetStrm();
3287 
3288     if ( nArgs == 2 )   // Seek-Function
3289     {
3290         sal_uIntPtr nPos = pStrm->Tell();
3291         if( pSbStrm->IsRandom() )
3292             nPos = nPos / pSbStrm->GetBlockLen();
3293         nPos++; // Basic zaehlt ab 1
3294         rPar.Get(0)->PutLong( (sal_Int32)nPos );
3295     }
3296     else                // Seek-Statement
3297     {
3298         sal_Int32 nPos = rPar.Get(2)->GetLong();
3299         if ( nPos < 1 )
3300         {
3301             StarBASIC::Error( SbERR_BAD_ARGUMENT );
3302             return;
3303         }
3304         nPos--; // Basic zaehlt ab 1, SvStreams zaehlen ab 0
3305         pSbStrm->SetExpandOnWriteTo( 0 );
3306         if ( pSbStrm->IsRandom() )
3307             nPos *= pSbStrm->GetBlockLen();
3308         pStrm->Seek( (sal_uIntPtr)nPos );
3309         pSbStrm->SetExpandOnWriteTo( nPos );
3310     }
3311 }
3312 
3313 RTLFUNC(Format)
3314 {
3315     (void)pBasic;
3316     (void)bWrite;
3317 
3318     sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
3319     if ( nArgCount < 2 || nArgCount > 3 )
3320         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3321     else
3322     {
3323         String aResult;
3324         if( nArgCount == 2 )
3325             rPar.Get(1)->Format( aResult );
3326         else
3327         {
3328             String aFmt( rPar.Get(2)->GetString() );
3329             rPar.Get(1)->Format( aResult, &aFmt );
3330         }
3331         rPar.Get(0)->PutString( aResult );
3332     }
3333 }
3334 
3335 RTLFUNC(Randomize)
3336 {
3337     (void)pBasic;
3338     (void)bWrite;
3339 
3340     if ( rPar.Count() > 2 )
3341         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3342     sal_Int16 nSeed;
3343     if( rPar.Count() == 2 )
3344         nSeed = (sal_Int16)rPar.Get(1)->GetInteger();
3345     else
3346         nSeed = (sal_Int16)rand();
3347     srand( nSeed );
3348 }
3349 
3350 RTLFUNC(Rnd)
3351 {
3352     (void)pBasic;
3353     (void)bWrite;
3354 
3355     if ( rPar.Count() > 2 )
3356         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3357     else
3358     {
3359         double nRand = (double)rand();
3360         nRand = ( nRand / (double)RAND_MAX );
3361         rPar.Get(0)->PutDouble( nRand );
3362     }
3363 }
3364 
3365 
3366 //
3367 //  Syntax: Shell("Path",[ Window-Style,[ "Params", [ bSync = sal_False ]]])
3368 //
3369 //  WindowStyles (VBA-kompatibel):
3370 //      2 == Minimized
3371 //      3 == Maximized
3372 //     10 == Full-Screen (Textmodus-Anwendungen OS/2, WIN95, WNT)
3373 //
3374 // !!!HACK der WindowStyle wird im Creator an Application::StartApp
3375 //         uebergeben. Format: "xxxx2"
3376 //
3377 
3378 
3379 RTLFUNC(Shell)
3380 {
3381     (void)pBasic;
3382     (void)bWrite;
3383 
3384     // No shell command for "virtual" portal users
3385     if( needSecurityRestrictions() )
3386     {
3387         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3388         return;
3389     }
3390 
3391     sal_uIntPtr nArgCount = rPar.Count();
3392     if ( nArgCount < 2 || nArgCount > 5 )
3393     {
3394         rPar.Get(0)->PutLong(0);
3395         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3396     }
3397     else
3398     {
3399         sal_uInt16 nOptions = vos::OProcess::TOption_SearchPath|
3400                           vos::OProcess::TOption_Detached;
3401         String aCmdLine = rPar.Get(1)->GetString();
3402         // Zusaetzliche Parameter anhaengen, es muss eh alles geparsed werden
3403         if( nArgCount >= 4 )
3404         {
3405             aCmdLine.AppendAscii( " " );
3406             aCmdLine += rPar.Get(3)->GetString();
3407         }
3408         else if( !aCmdLine.Len() )
3409         {
3410             // Spezial-Behandlung (leere Liste) vermeiden
3411             aCmdLine.AppendAscii( " " );
3412         }
3413         sal_uInt16 nLen = aCmdLine.Len();
3414 
3415         // #55735 Wenn Parameter dabei sind, muessen die abgetrennt werden
3416         // #72471 Auch die einzelnen Parameter trennen
3417         std::list<String> aTokenList;
3418         String aToken;
3419         sal_uInt16 i = 0;
3420         sal_Unicode c;
3421         while( i < nLen )
3422         {
3423             // Spaces weg
3424             for ( ;; ++i )
3425             {
3426                 c = aCmdLine.GetBuffer()[ i ];
3427                 if ( c != ' ' && c != '\t' )
3428                     break;
3429             }
3430 
3431             if( c == '\"' || c == '\'' )
3432             {
3433                 sal_uInt16 iFoundPos = aCmdLine.Search( c, i + 1 );
3434 
3435                 // Wenn nichts gefunden wurde, Rest kopieren
3436                 if( iFoundPos == STRING_NOTFOUND )
3437                 {
3438                     aToken = aCmdLine.Copy( i, STRING_LEN );
3439                     i = nLen;
3440                 }
3441                 else
3442                 {
3443                     aToken = aCmdLine.Copy( i + 1, (iFoundPos - i - 1) );
3444                     i = iFoundPos + 1;
3445                 }
3446             }
3447             else
3448             {
3449                 sal_uInt16 iFoundSpacePos = aCmdLine.Search( ' ', i );
3450                 sal_uInt16 iFoundTabPos = aCmdLine.Search( '\t', i );
3451                 sal_uInt16 iFoundPos = Min( iFoundSpacePos, iFoundTabPos );
3452 
3453                 // Wenn nichts gefunden wurde, Rest kopieren
3454                 if( iFoundPos == STRING_NOTFOUND )
3455                 {
3456                     aToken = aCmdLine.Copy( i, STRING_LEN );
3457                     i = nLen;
3458                 }
3459                 else
3460                 {
3461                     aToken = aCmdLine.Copy( i, (iFoundPos - i) );
3462                     i = iFoundPos;
3463                 }
3464             }
3465 
3466             // In die Liste uebernehmen
3467             aTokenList.push_back( aToken );
3468         }
3469         // #55735 / #72471 Ende
3470 
3471         sal_Int16 nWinStyle = 0;
3472         if( nArgCount >= 3 )
3473         {
3474             nWinStyle = rPar.Get(2)->GetInteger();
3475             switch( nWinStyle )
3476             {
3477                 case 2:
3478                     nOptions |= vos::OProcess::TOption_Minimized;
3479                     break;
3480                 case 3:
3481                     nOptions |= vos::OProcess::TOption_Maximized;
3482                     break;
3483                 case 10:
3484                     nOptions |= vos::OProcess::TOption_FullScreen;
3485                     break;
3486             }
3487 
3488             sal_Bool bSync = sal_False;
3489             if( nArgCount >= 5 )
3490                 bSync = rPar.Get(4)->GetBool();
3491             if( bSync )
3492                 nOptions |= vos::OProcess::TOption_Wait;
3493         }
3494         vos::OProcess::TProcessOption eOptions =
3495             (vos::OProcess::TProcessOption)nOptions;
3496 
3497 
3498         // #72471 Parameter aufbereiten
3499         std::list<String>::const_iterator iter = aTokenList.begin();
3500         const String& rStr = *iter;
3501         ::rtl::OUString aOUStrProg( rStr.GetBuffer(), rStr.Len() );
3502         String aOUStrProgUNC = getFullPathUNC( aOUStrProg );
3503 
3504         iter++;
3505 
3506         sal_uInt16 nParamCount = sal::static_int_cast< sal_uInt16 >(
3507             aTokenList.size() - 1 );
3508         ::rtl::OUString* pArgumentList = NULL;
3509         //const char** pParamList = NULL;
3510         if( nParamCount )
3511         {
3512             pArgumentList = new ::rtl::OUString[ nParamCount ];
3513             //pParamList = new const char*[ nParamCount ];
3514             sal_uInt16 iList = 0;
3515             while( iter != aTokenList.end() )
3516             {
3517                 const String& rParamStr = (*iter);
3518                 pArgumentList[iList++] = ::rtl::OUString( rParamStr.GetBuffer(), rParamStr.Len() );
3519                 //pParamList[iList++] = (*iter).GetStr();
3520                 iter++;
3521             }
3522         }
3523 
3524         //const char* pParams = aParams.Len() ? aParams.GetStr() : 0;
3525         vos::OProcess* pApp;
3526         pApp = new vos::OProcess( aOUStrProgUNC );
3527         sal_Bool bSucc;
3528         if( nParamCount == 0 )
3529         {
3530             bSucc = pApp->execute( eOptions ) == vos::OProcess::E_None;
3531         }
3532         else
3533         {
3534             vos::OArgumentList aArgList( pArgumentList, nParamCount );
3535             bSucc = pApp->execute( eOptions, aArgList ) == vos::OProcess::E_None;
3536         }
3537 
3538         /*
3539         if( nParamCount == 0 )
3540             pApp = new vos::OProcess( pProg );
3541         else
3542             pApp = new vos::OProcess( pProg, pParamList, nParamCount );
3543         sal_Bool bSucc = pApp->execute( eOptions ) == vos::OProcess::E_None;
3544         */
3545 
3546         delete pApp;
3547         delete[] pArgumentList;
3548         if( !bSucc )
3549             StarBASIC::Error( SbERR_FILE_NOT_FOUND );
3550         else
3551             rPar.Get(0)->PutLong( 0 );
3552     }
3553 }
3554 
3555 RTLFUNC(VarType)
3556 {
3557     (void)pBasic;
3558     (void)bWrite;
3559 
3560     if ( rPar.Count() != 2 )
3561         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3562     else
3563     {
3564         SbxDataType eType = rPar.Get(1)->GetType();
3565         rPar.Get(0)->PutInteger( (sal_Int16)eType );
3566     }
3567 }
3568 
3569 // Exported function
3570 String getBasicTypeName( SbxDataType eType )
3571 {
3572     static const char* pTypeNames[] =
3573     {
3574         "Empty",            // SbxEMPTY
3575         "Null",             // SbxNULL
3576         "Integer",          // SbxINTEGER
3577         "Long",             // SbxLONG
3578         "Single",           // SbxSINGLE
3579         "Double",           // SbxDOUBLE
3580         "Currency",         // SbxCURRENCY
3581         "Date",             // SbxDATE
3582         "String",           // SbxSTRING
3583         "Object",           // SbxOBJECT
3584         "Error",            // SbxERROR
3585         "Boolean",          // SbxBOOL
3586         "Variant",          // SbxVARIANT
3587         "DataObject",       // SbxDATAOBJECT
3588         "Unknown Type",     //
3589         "Unknown Type",     //
3590         "Char",             // SbxCHAR
3591         "Byte",             // SbxBYTE
3592         "UShort",           // SbxUSHORT
3593         "ULong",            // SbxULONG
3594         "Long64",           // SbxLONG64
3595         "ULong64",          // SbxULONG64
3596         "Int",              // SbxINT
3597         "UInt",             // SbxUINT
3598         "Void",             // SbxVOID
3599         "HResult",          // SbxHRESULT
3600         "Pointer",          // SbxPOINTER
3601         "DimArray",         // SbxDIMARRAY
3602         "CArray",           // SbxCARRAY
3603         "Userdef",          // SbxUSERDEF
3604         "Lpstr",            // SbxLPSTR
3605         "Lpwstr",           // SbxLPWSTR
3606         "Unknown Type",     // SbxCoreSTRING
3607         "WString",          // SbxWSTRING
3608         "WChar",            // SbxWCHAR
3609         "Int64",            // SbxSALINT64
3610         "UInt64",           // SbxSALUINT64
3611         "Decimal",          // SbxDECIMAL
3612     };
3613 
3614     int nPos = ((int)eType) & 0x0FFF;
3615     sal_uInt16 nTypeNameCount = sizeof( pTypeNames ) / sizeof( char* );
3616     if ( nPos < 0 || nPos >= nTypeNameCount )
3617         nPos = nTypeNameCount - 1;
3618     String aRetStr = String::CreateFromAscii( pTypeNames[nPos] );
3619     return aRetStr;
3620 }
3621 
3622 RTLFUNC(TypeName)
3623 {
3624     (void)pBasic;
3625     (void)bWrite;
3626 
3627     if ( rPar.Count() != 2 )
3628         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3629     else
3630     {
3631         SbxDataType eType = rPar.Get(1)->GetType();
3632         sal_Bool bIsArray = ( ( eType & SbxARRAY ) != 0 );
3633         String aRetStr = getBasicTypeName( eType );
3634         if( bIsArray )
3635             aRetStr.AppendAscii( "()" );
3636         rPar.Get(0)->PutString( aRetStr );
3637     }
3638 }
3639 
3640 RTLFUNC(Len)
3641 {
3642     (void)pBasic;
3643     (void)bWrite;
3644 
3645     if ( rPar.Count() != 2 )
3646         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3647     else
3648     {
3649         const String& rStr = rPar.Get(1)->GetString();
3650         rPar.Get(0)->PutLong( (sal_Int32)rStr.Len() );
3651     }
3652 }
3653 
3654 RTLFUNC(DDEInitiate)
3655 {
3656     (void)pBasic;
3657     (void)bWrite;
3658 
3659     // No DDE for "virtual" portal users
3660     if( needSecurityRestrictions() )
3661     {
3662         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3663         return;
3664     }
3665 
3666     int nArgs = (int)rPar.Count();
3667     if ( nArgs != 3 )
3668     {
3669         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3670         return;
3671     }
3672     const String& rApp = rPar.Get(1)->GetString();
3673     const String& rTopic = rPar.Get(2)->GetString();
3674 
3675     SbiDdeControl* pDDE = pINST->GetDdeControl();
3676     sal_Int16 nChannel;
3677     SbError nDdeErr = pDDE->Initiate( rApp, rTopic, nChannel );
3678     if( nDdeErr )
3679         StarBASIC::Error( nDdeErr );
3680     else
3681         rPar.Get(0)->PutInteger( nChannel );
3682 }
3683 
3684 RTLFUNC(DDETerminate)
3685 {
3686     (void)pBasic;
3687     (void)bWrite;
3688 
3689     // No DDE for "virtual" portal users
3690     if( needSecurityRestrictions() )
3691     {
3692         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3693         return;
3694     }
3695 
3696     rPar.Get(0)->PutEmpty();
3697     int nArgs = (int)rPar.Count();
3698     if ( nArgs != 2 )
3699     {
3700         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3701         return;
3702     }
3703     sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3704     SbiDdeControl* pDDE = pINST->GetDdeControl();
3705     SbError nDdeErr = pDDE->Terminate( nChannel );
3706     if( nDdeErr )
3707         StarBASIC::Error( nDdeErr );
3708 }
3709 
3710 RTLFUNC(DDETerminateAll)
3711 {
3712     (void)pBasic;
3713     (void)bWrite;
3714 
3715     // No DDE for "virtual" portal users
3716     if( needSecurityRestrictions() )
3717     {
3718         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3719         return;
3720     }
3721 
3722     rPar.Get(0)->PutEmpty();
3723     int nArgs = (int)rPar.Count();
3724     if ( nArgs != 1 )
3725     {
3726         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3727         return;
3728     }
3729 
3730     SbiDdeControl* pDDE = pINST->GetDdeControl();
3731     SbError nDdeErr = pDDE->TerminateAll();
3732     if( nDdeErr )
3733         StarBASIC::Error( nDdeErr );
3734 
3735 }
3736 
3737 RTLFUNC(DDERequest)
3738 {
3739     (void)pBasic;
3740     (void)bWrite;
3741 
3742     // No DDE for "virtual" portal users
3743     if( needSecurityRestrictions() )
3744     {
3745         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3746         return;
3747     }
3748 
3749     int nArgs = (int)rPar.Count();
3750     if ( nArgs != 3 )
3751     {
3752         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3753         return;
3754     }
3755     sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3756     const String& rItem = rPar.Get(2)->GetString();
3757     SbiDdeControl* pDDE = pINST->GetDdeControl();
3758     String aResult;
3759     SbError nDdeErr = pDDE->Request( nChannel, rItem, aResult );
3760     if( nDdeErr )
3761         StarBASIC::Error( nDdeErr );
3762     else
3763         rPar.Get(0)->PutString( aResult );
3764 }
3765 
3766 RTLFUNC(DDEExecute)
3767 {
3768     (void)pBasic;
3769     (void)bWrite;
3770 
3771     // No DDE for "virtual" portal users
3772     if( needSecurityRestrictions() )
3773     {
3774         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3775         return;
3776     }
3777 
3778     rPar.Get(0)->PutEmpty();
3779     int nArgs = (int)rPar.Count();
3780     if ( nArgs != 3 )
3781     {
3782         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3783         return;
3784     }
3785     sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3786     const String& rCommand = rPar.Get(2)->GetString();
3787     SbiDdeControl* pDDE = pINST->GetDdeControl();
3788     SbError nDdeErr = pDDE->Execute( nChannel, rCommand );
3789     if( nDdeErr )
3790         StarBASIC::Error( nDdeErr );
3791 }
3792 
3793 RTLFUNC(DDEPoke)
3794 {
3795     (void)pBasic;
3796     (void)bWrite;
3797 
3798     // No DDE for "virtual" portal users
3799     if( needSecurityRestrictions() )
3800     {
3801         StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
3802         return;
3803     }
3804 
3805     rPar.Get(0)->PutEmpty();
3806     int nArgs = (int)rPar.Count();
3807     if ( nArgs != 4 )
3808     {
3809         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3810         return;
3811     }
3812     sal_Int16 nChannel = rPar.Get(1)->GetInteger();
3813     const String& rItem = rPar.Get(2)->GetString();
3814     const String& rData = rPar.Get(3)->GetString();
3815     SbiDdeControl* pDDE = pINST->GetDdeControl();
3816     SbError nDdeErr = pDDE->Poke( nChannel, rItem, rData );
3817     if( nDdeErr )
3818         StarBASIC::Error( nDdeErr );
3819 }
3820 
3821 
3822 RTLFUNC(FreeFile)
3823 {
3824     (void)pBasic;
3825     (void)bWrite;
3826 
3827     if ( rPar.Count() != 1 )
3828     {
3829         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3830         return;
3831     }
3832     SbiIoSystem* pIO = pINST->GetIoSystem();
3833     short nChannel = 1;
3834     while( nChannel < CHANNELS )
3835     {
3836         SbiStream* pStrm = pIO->GetStream( nChannel );
3837         if( !pStrm )
3838         {
3839             rPar.Get(0)->PutInteger( nChannel );
3840             return;
3841         }
3842         nChannel++;
3843     }
3844     StarBASIC::Error( SbERR_TOO_MANY_FILES );
3845 }
3846 
3847 RTLFUNC(LBound)
3848 {
3849     (void)pBasic;
3850     (void)bWrite;
3851 
3852     sal_uInt16 nParCount = rPar.Count();
3853     if ( nParCount != 3 && nParCount != 2 )
3854     {
3855         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3856         return;
3857     }
3858     SbxBase* pParObj = rPar.Get(1)->GetObject();
3859     SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj);
3860     if( pArr )
3861     {
3862         sal_Int32 nLower, nUpper;
3863         short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1;
3864         if( !pArr->GetDim32( nDim, nLower, nUpper ) )
3865             StarBASIC::Error( SbERR_OUT_OF_RANGE );
3866         else
3867             rPar.Get(0)->PutLong( nLower );
3868     }
3869     else
3870         StarBASIC::Error( SbERR_MUST_HAVE_DIMS );
3871 }
3872 
3873 RTLFUNC(UBound)
3874 {
3875     (void)pBasic;
3876     (void)bWrite;
3877 
3878     sal_uInt16 nParCount = rPar.Count();
3879     if ( nParCount != 3 && nParCount != 2 )
3880     {
3881         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3882         return;
3883     }
3884 
3885     SbxBase* pParObj = rPar.Get(1)->GetObject();
3886     SbxDimArray* pArr = PTR_CAST(SbxDimArray,pParObj);
3887     if( pArr )
3888     {
3889         sal_Int32 nLower, nUpper;
3890         short nDim = (nParCount == 3) ? (short)rPar.Get(2)->GetInteger() : 1;
3891         if( !pArr->GetDim32( nDim, nLower, nUpper ) )
3892             StarBASIC::Error( SbERR_OUT_OF_RANGE );
3893         else
3894             rPar.Get(0)->PutLong( nUpper );
3895     }
3896     else
3897         StarBASIC::Error( SbERR_MUST_HAVE_DIMS );
3898 }
3899 
3900 RTLFUNC(RGB)
3901 {
3902     (void)pBasic;
3903     (void)bWrite;
3904 
3905     if ( rPar.Count() != 4 )
3906     {
3907         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3908         return;
3909     }
3910 
3911     sal_uIntPtr nRed     = rPar.Get(1)->GetInteger() & 0xFF;
3912     sal_uIntPtr nGreen = rPar.Get(2)->GetInteger() & 0xFF;
3913     sal_uIntPtr nBlue  = rPar.Get(3)->GetInteger() & 0xFF;
3914     sal_uIntPtr nRGB;
3915 
3916     SbiInstance* pInst = pINST;
3917     bool bCompatibility = ( pInst && pInst->IsCompatibility() );
3918     if( bCompatibility )
3919     {
3920         nRGB   = (nBlue << 16) | (nGreen << 8) | nRed;
3921     }
3922     else
3923     {
3924         nRGB   = (nRed << 16) | (nGreen << 8) | nBlue;
3925     }
3926     rPar.Get(0)->PutLong( nRGB );
3927 }
3928 
3929 RTLFUNC(QBColor)
3930 {
3931     (void)pBasic;
3932     (void)bWrite;
3933 
3934     static const sal_Int32 pRGB[] =
3935     {
3936         0x000000,
3937         0x800000,
3938         0x008000,
3939         0x808000,
3940         0x000080,
3941         0x800080,
3942         0x008080,
3943         0xC0C0C0,
3944         0x808080,
3945         0xFF0000,
3946         0x00FF00,
3947         0xFFFF00,
3948         0x0000FF,
3949         0xFF00FF,
3950         0x00FFFF,
3951         0xFFFFFF,
3952     };
3953 
3954     if ( rPar.Count() != 2 )
3955     {
3956         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3957         return;
3958     }
3959 
3960     sal_Int16 nCol = rPar.Get(1)->GetInteger();
3961     if( nCol < 0 || nCol > 15 )
3962     {
3963         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3964         return;
3965     }
3966     sal_Int32 nRGB = pRGB[ nCol ];
3967     rPar.Get(0)->PutLong( nRGB );
3968 }
3969 
3970 // StrConv(string, conversion, LCID)
3971 RTLFUNC(StrConv)
3972 {
3973     (void)pBasic;
3974     (void)bWrite;
3975 
3976     sal_uIntPtr nArgCount = rPar.Count()-1;
3977     if( nArgCount < 2 || nArgCount > 3 )
3978     {
3979         StarBASIC::Error( SbERR_BAD_ARGUMENT );
3980         return;
3981     }
3982 
3983     String aOldStr = rPar.Get(1)->GetString();
3984     sal_Int32 nConversion = rPar.Get(2)->GetLong();
3985 
3986     sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
3987     if( nArgCount == 3 )
3988     {
3989         // LCID not supported now
3990         //nLanguage = rPar.Get(3)->GetInteger();
3991     }
3992 
3993     sal_uInt16 nOldLen = aOldStr.Len();
3994     if( nOldLen == 0 )
3995     {
3996         // null string,return
3997         rPar.Get(0)->PutString(aOldStr);
3998         return;
3999     }
4000 
4001     sal_Int32 nType = 0;
4002     if ( (nConversion & 0x03) == 3 ) //  vbProperCase
4003     {
4004         CharClass& rCharClass = GetCharClass();
4005         aOldStr = rCharClass.toTitle( aOldStr.ToLowerAscii(), 0, nOldLen );
4006     }
4007     else if ( (nConversion & 0x01) == 1 ) // vbUpperCase
4008         nType |= ::com::sun::star::i18n::TransliterationModules_LOWERCASE_UPPERCASE;
4009     else if ( (nConversion & 0x02) == 2 ) // vbLowerCase
4010         nType |= ::com::sun::star::i18n::TransliterationModules_UPPERCASE_LOWERCASE;
4011 
4012     if ( (nConversion & 0x04) == 4 ) // vbWide
4013         nType |= ::com::sun::star::i18n::TransliterationModules_HALFWIDTH_FULLWIDTH;
4014     else if ( (nConversion & 0x08) == 8 ) // vbNarrow
4015         nType |= ::com::sun::star::i18n::TransliterationModules_FULLWIDTH_HALFWIDTH;
4016 
4017     if ( (nConversion & 0x10) == 16) // vbKatakana
4018         nType |= ::com::sun::star::i18n::TransliterationModules_HIRAGANA_KATAKANA;
4019     else if ( (nConversion & 0x20) == 32 ) // vbHiragana
4020         nType |= ::com::sun::star::i18n::TransliterationModules_KATAKANA_HIRAGANA;
4021 
4022     String aNewStr( aOldStr );
4023     if( nType != 0 )
4024     {
4025         com::sun::star::uno::Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
4026         ::utl::TransliterationWrapper aTransliterationWrapper( xSMgr,nType );
4027         com::sun::star::uno::Sequence<sal_Int32> aOffsets;
4028         aTransliterationWrapper.loadModuleIfNeeded( nLanguage );
4029         aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
4030     }
4031 
4032     if ( (nConversion & 0x40) == 64 ) // vbUnicode
4033     {
4034         // convert the string to byte string, preserving unicode (2 bytes per character)
4035         sal_uInt16 nSize = aNewStr.Len()*2;
4036         const sal_Unicode* pSrc = aNewStr.GetBuffer();
4037         sal_Char* pChar = new sal_Char[nSize+1];
4038         for( sal_uInt16 i=0; i < nSize; i++ )
4039         {
4040             pChar[i] = static_cast< sal_Char >( i%2 ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff );
4041             if( i%2 )
4042                 pSrc++;
4043         }
4044         pChar[nSize] = '\0';
4045         ::rtl::OString aOStr(pChar);
4046 
4047         // there is no concept about default codepage in unix. so it is incorrectly in unix
4048         ::rtl::OUString aOUStr = ::rtl::OStringToOUString(aOStr, osl_getThreadTextEncoding());
4049         aNewStr = String(aOUStr);
4050         rPar.Get(0)->PutString( aNewStr );
4051         return;
4052     }
4053     else if ( (nConversion & 0x80) == 128 ) // vbFromUnicode
4054     {
4055         ::rtl::OUString aOUStr(aNewStr);
4056         // there is no concept about default codepage in unix. so it is incorrectly in unix
4057         ::rtl::OString aOStr = ::rtl::OUStringToOString(aNewStr,osl_getThreadTextEncoding());
4058         const sal_Char* pChar = aOStr.getStr();
4059         sal_uInt16 nArraySize = static_cast< sal_uInt16 >( aOStr.getLength() );
4060         SbxDimArray* pArray = new SbxDimArray(SbxBYTE);
4061         bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() );
4062         if(nArraySize)
4063         {
4064             if( bIncIndex )
4065                 pArray->AddDim( 1, nArraySize );
4066             else
4067                 pArray->AddDim( 0, nArraySize-1 );
4068         }
4069         else
4070         {
4071             pArray->unoAddDim( 0, -1 );
4072         }
4073 
4074         for( sal_uInt16 i=0; i< nArraySize; i++)
4075         {
4076             SbxVariable* pNew = new SbxVariable( SbxBYTE );
4077             pNew->PutByte(*pChar);
4078             pChar++;
4079             pNew->SetFlag( SBX_WRITE );
4080             short index = i;
4081             if( bIncIndex )
4082                 ++index;
4083             pArray->Put( pNew, &index );
4084         }
4085 
4086         SbxVariableRef refVar = rPar.Get(0);
4087         sal_uInt16 nFlags = refVar->GetFlags();
4088         refVar->ResetFlag( SBX_FIXED );
4089         refVar->PutObject( pArray );
4090         refVar->SetFlags( nFlags );
4091         refVar->SetParameters( NULL );
4092         return;
4093     }
4094 
4095     rPar.Get(0)->PutString(aNewStr);
4096 }
4097 
4098 
4099 RTLFUNC(Beep)
4100 {
4101     (void)pBasic;
4102     (void)bWrite;
4103 
4104     if ( rPar.Count() != 1 )
4105     {
4106         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4107         return;
4108     }
4109     Sound::Beep();
4110 }
4111 
4112 RTLFUNC(Load)
4113 {
4114     (void)pBasic;
4115     (void)bWrite;
4116 
4117     if( rPar.Count() != 2 )
4118     {
4119         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4120         return;
4121     }
4122 
4123     // Diesen Call einfach an das Object weiterreichen
4124     SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject();
4125     if ( pObj )
4126     {
4127         if( pObj->IsA( TYPE( SbUserFormModule ) ) )
4128         {
4129             ((SbUserFormModule*)pObj)->Load();
4130         }
4131         else if( pObj->IsA( TYPE( SbxObject ) ) )
4132         {
4133             SbxVariable* pVar = ((SbxObject*)pObj)->
4134                 Find( String( RTL_CONSTASCII_USTRINGPARAM("Load") ), SbxCLASS_METHOD );
4135             if( pVar )
4136                 pVar->GetInteger();
4137         }
4138     }
4139 }
4140 
4141 RTLFUNC(Unload)
4142 {
4143     (void)pBasic;
4144     (void)bWrite;
4145 
4146     rPar.Get(0)->PutEmpty();
4147     if( rPar.Count() != 2 )
4148     {
4149         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4150         return;
4151     }
4152 
4153     // Diesen Call einfach an das Object weitereichen
4154     SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject();
4155     if ( pObj )
4156     {
4157         if( pObj->IsA( TYPE( SbUserFormModule ) ) )
4158         {
4159             SbUserFormModule* pFormModule = ( SbUserFormModule* )pObj;
4160             pFormModule->Unload();
4161         }
4162         else if( pObj->IsA( TYPE( SbxObject ) ) )
4163         {
4164             SbxVariable* pVar = ((SbxObject*)pObj)->
4165                 Find( String( RTL_CONSTASCII_USTRINGPARAM("Unload") ), SbxCLASS_METHOD );
4166             if( pVar )
4167                 pVar->GetInteger();
4168         }
4169     }
4170 }
4171 
4172 RTLFUNC(LoadPicture)
4173 {
4174     (void)pBasic;
4175     (void)bWrite;
4176 
4177     if( rPar.Count() != 2 )
4178     {
4179         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4180         return;
4181     }
4182 
4183     String aFileURL = getFullPath( rPar.Get(1)->GetString() );
4184     SvStream* pStream = utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_READ );
4185     if( pStream != NULL )
4186     {
4187         Bitmap aBmp;
4188         ReadDIB(aBmp, *pStream, true);
4189         Graphic aGraphic(aBmp);
4190 
4191         SbxObjectRef xRef = new SbStdPicture;
4192         ((SbStdPicture*)(SbxObject*)xRef)->SetGraphic( aGraphic );
4193         rPar.Get(0)->PutObject( xRef );
4194     }
4195     delete pStream;
4196 }
4197 
4198 RTLFUNC(SavePicture)
4199 {
4200     (void)pBasic;
4201     (void)bWrite;
4202 
4203     rPar.Get(0)->PutEmpty();
4204     if( rPar.Count() != 3 )
4205     {
4206         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4207         return;
4208     }
4209 
4210     SbxBase* pObj = (SbxObject*)rPar.Get(1)->GetObject();
4211     if( pObj->IsA( TYPE( SbStdPicture ) ) )
4212     {
4213         SvFileStream aOStream( rPar.Get(2)->GetString(), STREAM_WRITE | STREAM_TRUNC );
4214         Graphic aGraphic = ((SbStdPicture*)pObj)->GetGraphic();
4215         aOStream << aGraphic;
4216     }
4217 }
4218 
4219 
4220 //-----------------------------------------------------------------------------------------
4221 
4222 RTLFUNC(AboutStarBasic)
4223 {
4224     (void)pBasic;
4225     (void)bWrite;
4226     (void)rPar;
4227 }
4228 
4229 RTLFUNC(MsgBox)
4230 {
4231     (void)pBasic;
4232     (void)bWrite;
4233 
4234     static const WinBits nStyleMap[] =
4235     {
4236         WB_OK,              // MB_OK
4237         WB_OK_CANCEL,       // MB_OKCANCEL
4238         WB_ABORT_RETRY_IGNORE,    // MB_ABORTRETRYIGNORE
4239         WB_YES_NO_CANCEL,   // MB_YESNOCANCEL
4240         WB_YES_NO,          // MB_YESNO
4241         WB_RETRY_CANCEL     // MB_RETRYCANCEL
4242     };
4243     static const sal_Int16 nButtonMap[] =
4244     {
4245         2, // #define RET_CANCEL sal_False
4246         1, // #define RET_OK     sal_True
4247         6, // #define RET_YES    2
4248         7, // #define RET_NO     3
4249         4  // #define RET_RETRY  4
4250     };
4251 
4252 
4253     sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
4254     if( nArgCount < 2 || nArgCount > 6 )
4255     {
4256         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4257         return;
4258     }
4259     WinBits nWinBits;
4260     WinBits nType = 0; // MB_OK
4261     if( nArgCount >= 3 )
4262         nType = (WinBits)rPar.Get(2)->GetInteger();
4263     WinBits nStyle = nType;
4264     nStyle &= 15; // Bits 4-16 loeschen
4265     if( nStyle > 5 )
4266         nStyle = 0;
4267 
4268     nWinBits = nStyleMap[ nStyle ];
4269 
4270     WinBits nWinDefBits;
4271     nWinDefBits = (WB_DEF_OK | WB_DEF_RETRY | WB_DEF_YES);
4272     if( nType & 256 )
4273     {
4274         if( nStyle == 5 )
4275             nWinDefBits = WB_DEF_CANCEL;
4276         else if( nStyle == 2 )
4277             nWinDefBits = WB_DEF_RETRY;
4278         else
4279             nWinDefBits = (WB_DEF_CANCEL | WB_DEF_RETRY | WB_DEF_NO);
4280     }
4281     else if( nType & 512 )
4282     {
4283         if( nStyle == 2)
4284             nWinDefBits = WB_DEF_IGNORE;
4285         else
4286             nWinDefBits = WB_DEF_CANCEL;
4287     }
4288     else if( nStyle == 2)
4289         nWinDefBits = WB_DEF_CANCEL;
4290     nWinBits |= nWinDefBits;
4291 
4292     String aMsg = rPar.Get(1)->GetString();
4293     String aTitle;
4294     if( nArgCount >= 4 )
4295         aTitle = rPar.Get(3)->GetString();
4296     else
4297         aTitle = GetpApp()->GetAppName();
4298 
4299     nType &= (16+32+64);
4300     MessBox* pBox = 0;
4301     Window* pParent = GetpApp()->GetDefDialogParent();
4302     switch( nType )
4303     {
4304         case 16:
4305             pBox = new ErrorBox( pParent, nWinBits, aMsg );
4306             break;
4307         case 32:
4308             pBox = new QueryBox( pParent, nWinBits, aMsg );
4309             break;
4310         case 48:
4311             pBox = new WarningBox( pParent, nWinBits, aMsg );
4312             break;
4313         case 64:
4314             pBox = new InfoBox( pParent, aMsg );
4315             break;
4316         default:
4317             pBox = new MessBox( pParent, nWinBits, aTitle, aMsg );
4318     }
4319     pBox->SetText( aTitle );
4320     sal_uInt16 nRet = (sal_uInt16)pBox->Execute();
4321     if( nRet == sal_True )
4322         nRet = 1;
4323 
4324     sal_Int16 nMappedRet;
4325     if( nStyle == 2 )
4326     {
4327         nMappedRet = nRet;
4328         if( nMappedRet == 0 )
4329             nMappedRet = 3; // Abort
4330     }
4331     else
4332         nMappedRet = nButtonMap[ nRet ];
4333 
4334     rPar.Get(0)->PutInteger( nMappedRet );
4335     delete pBox;
4336 }
4337 
4338 RTLFUNC(SetAttr) // JSM
4339 {
4340     (void)pBasic;
4341     (void)bWrite;
4342 
4343     rPar.Get(0)->PutEmpty();
4344     if ( rPar.Count() == 3 )
4345     {
4346         String aStr = rPar.Get(1)->GetString();
4347         sal_Int16 nFlags = rPar.Get(2)->GetInteger();
4348 
4349         // <-- UCB
4350         if( hasUno() )
4351         {
4352             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
4353             if( xSFI.is() )
4354             {
4355                 try
4356                 {
4357                     sal_Bool bReadOnly = (nFlags & 0x0001) != 0; // ATTR_READONLY
4358                     xSFI->setReadOnly( aStr, bReadOnly );
4359                     sal_Bool bHidden   = (nFlags & 0x0002) != 0; // ATTR_HIDDEN
4360                     xSFI->setHidden( aStr, bHidden );
4361                 }
4362                 catch( Exception & )
4363                 {
4364                     StarBASIC::Error( ERRCODE_IO_GENERAL );
4365                 }
4366             }
4367         }
4368         else
4369         // --> UCB
4370         {
4371 #ifdef _OLD_FILE_IMPL
4372             // #57064 Bei virtuellen URLs den Real-Path extrahieren
4373             DirEntry aEntry( aStr );
4374             String aFile = aEntry.GetFull();
4375             ByteString aByteFile( aFile, gsl_getSystemTextEncoding() );
4376     #ifdef WNT
4377             if (!SetFileAttributes (aByteFile.GetBuffer(),(DWORD)nFlags))
4378                 StarBASIC::Error(SbERR_FILE_NOT_FOUND);
4379     #endif
4380     #ifdef OS2
4381             FILESTATUS3 aFileStatus;
4382             APIRET rc = DosQueryPathInfo(aByteFile.GetBuffer(),1,
4383                                          &aFileStatus,sizeof(FILESTATUS3));
4384             if (!rc)
4385             {
4386                 if (aFileStatus.attrFile != nFlags)
4387                 {
4388                     aFileStatus.attrFile = nFlags;
4389                     rc = DosSetPathInfo(aFile.GetStr(),1,
4390                                         &aFileStatus,sizeof(FILESTATUS3),0);
4391                     if (rc)
4392                         StarBASIC::Error( SbERR_FILE_NOT_FOUND );
4393                 }
4394             }
4395             else
4396                 StarBASIC::Error( SbERR_FILE_NOT_FOUND );
4397     #endif
4398 #else
4399             // Not implemented
4400 #endif
4401         }
4402     }
4403     else
4404         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4405 }
4406 
4407 RTLFUNC(Reset)  // JSM
4408 {
4409     (void)pBasic;
4410     (void)bWrite;
4411     (void)rPar;
4412 
4413     SbiIoSystem* pIO = pINST->GetIoSystem();
4414     if (pIO)
4415         pIO->CloseAll();
4416 }
4417 
4418 RTLFUNC(DumpAllObjects)
4419 {
4420     (void)pBasic;
4421     (void)bWrite;
4422 
4423     sal_uInt16 nArgCount = (sal_uInt16)rPar.Count();
4424     if( nArgCount < 2 || nArgCount > 3 )
4425         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4426     else if( !pBasic )
4427         StarBASIC::Error( SbERR_INTERNAL_ERROR );
4428     else
4429     {
4430         SbxObject* p = pBasic;
4431         while( p->GetParent() )
4432             p = p->GetParent();
4433         SvFileStream aStrm( rPar.Get( 1 )->GetString(),
4434                             STREAM_WRITE | STREAM_TRUNC );
4435         p->Dump( aStrm, rPar.Get( 2 )->GetBool() );
4436         aStrm.Close();
4437         if( aStrm.GetError() != SVSTREAM_OK )
4438             StarBASIC::Error( SbERR_IO_ERROR );
4439     }
4440 }
4441 
4442 
4443 RTLFUNC(FileExists)
4444 {
4445     (void)pBasic;
4446     (void)bWrite;
4447 
4448     if ( rPar.Count() == 2 )
4449     {
4450         String aStr = rPar.Get(1)->GetString();
4451         sal_Bool bExists = sal_False;
4452 
4453         // <-- UCB
4454         if( hasUno() )
4455         {
4456             com::sun::star::uno::Reference< XSimpleFileAccess3 > xSFI = getFileAccess();
4457             if( xSFI.is() )
4458             {
4459                 try
4460                 {
4461                     bExists = xSFI->exists( aStr );
4462                 }
4463                 catch( Exception & )
4464                 {
4465                     StarBASIC::Error( ERRCODE_IO_GENERAL );
4466                 }
4467             }
4468         }
4469         else
4470         // --> UCB
4471         {
4472 #ifdef _OLD_FILE_IMPL
4473             DirEntry aEntry( aStr );
4474             bExists = aEntry.Exists();
4475 #else
4476             DirectoryItem aItem;
4477             FileBase::RC nRet = DirectoryItem::get( getFullPathUNC( aStr ), aItem );
4478             bExists = (nRet == FileBase::E_None);
4479 #endif
4480         }
4481         rPar.Get(0)->PutBool( bExists );
4482     }
4483     else
4484         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4485 }
4486 
4487 RTLFUNC(Partition)
4488 {
4489     (void)pBasic;
4490     (void)bWrite;
4491 
4492     if ( rPar.Count() != 5 )
4493     {
4494         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4495         return;
4496     }
4497 
4498     sal_Int32 nNumber = rPar.Get(1)->GetLong();
4499     sal_Int32 nStart = rPar.Get(2)->GetLong();
4500     sal_Int32 nStop = rPar.Get(3)->GetLong();
4501     sal_Int32 nInterval = rPar.Get(4)->GetLong();
4502 
4503     if( nStart < 0 || nStop <= nStart || nInterval < 1 )
4504     {
4505         StarBASIC::Error( SbERR_BAD_ARGUMENT );
4506         return;
4507     }
4508 
4509     // the Partition function inserts leading spaces before lowervalue and uppervalue
4510     // so that they both have the same number of characters as the string
4511     // representation of the value (Stop + 1). This ensures that if you use the output
4512     // of the Partition function with several values of Number, the resulting text
4513     // will be handled properly during any subsequent sort operation.
4514 
4515     // calculate the  maximun number of characters before lowervalue and uppervalue
4516     ::rtl::OUString aBeforeStart = ::rtl::OUString::valueOf( nStart - 1 );
4517     ::rtl::OUString aAfterStop = ::rtl::OUString::valueOf( nStop + 1 );
4518     sal_Int32 nLen1 = aBeforeStart.getLength();
4519     sal_Int32 nLen2 = aAfterStop.getLength();
4520     sal_Int32 nLen = nLen1 >= nLen2 ? nLen1:nLen2;
4521 
4522     ::rtl::OUStringBuffer aRetStr( nLen * 2 + 1);
4523     ::rtl::OUString aLowerValue;
4524     ::rtl::OUString aUpperValue;
4525     if( nNumber < nStart )
4526     {
4527         aUpperValue = aBeforeStart;
4528     }
4529     else if( nNumber > nStop )
4530     {
4531         aLowerValue = aAfterStop;
4532     }
4533     else
4534     {
4535         sal_Int32 nLowerValue = nNumber;
4536         sal_Int32 nUpperValue = nLowerValue;
4537         if( nInterval > 1 )
4538         {
4539             nLowerValue = ((( nNumber - nStart ) / nInterval ) * nInterval ) + nStart;
4540             nUpperValue = nLowerValue + nInterval - 1;
4541         }
4542 
4543         aLowerValue = ::rtl::OUString::valueOf( nLowerValue );
4544         aUpperValue = ::rtl::OUString::valueOf( nUpperValue );
4545     }
4546 
4547     nLen1 = aLowerValue.getLength();
4548     nLen2 = aUpperValue.getLength();
4549 
4550     if( nLen > nLen1 )
4551     {
4552         // appending the leading spaces for the lowervalue
4553         for ( sal_Int32 i= (nLen - nLen1) ; i > 0; --i )
4554             aRetStr.appendAscii(" ");
4555     }
4556     aRetStr.append( aLowerValue ).appendAscii(":");
4557     if( nLen > nLen2 )
4558     {
4559         // appending the leading spaces for the uppervalue
4560         for ( sal_Int32 i= (nLen - nLen2) ; i > 0; --i )
4561             aRetStr.appendAscii(" ");
4562     }
4563     aRetStr.append( aUpperValue );
4564     rPar.Get(0)->PutString( String(aRetStr.makeStringAndClear()) );
4565 }
4566