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