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