Change-Id: I4ad1226e5b08fc3abbf94440ea435fc9109005b3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87081 Tested-by: Jenkins Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
4813 lines
138 KiB
C++
4813 lines
138 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <config_features.h>
|
|
|
|
#include <tools/date.hxx>
|
|
#include <basic/sbxvar.hxx>
|
|
#include <basic/sbuno.hxx>
|
|
#include <osl/process.h>
|
|
#include <vcl/dibtools.hxx>
|
|
#include <vcl/window.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/sound.hxx>
|
|
#include <tools/wintypes.hxx>
|
|
#include <vcl/stdtext.hxx>
|
|
#include <vcl/weld.hxx>
|
|
#include <basic/sbx.hxx>
|
|
#include <svl/zforlist.hxx>
|
|
#include <rtl/character.hxx>
|
|
#include <rtl/math.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <osl/time.h>
|
|
#include <unotools/charclass.hxx>
|
|
#include <unotools/ucbstreamhelper.hxx>
|
|
#include <tools/wldcrd.hxx>
|
|
#include <i18nlangtag/lang.h>
|
|
#include <rtl/string.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <comphelper/DirectoryHelper.hxx>
|
|
|
|
#include <runtime.hxx>
|
|
#include <sbunoobj.hxx>
|
|
#include <osl/file.hxx>
|
|
#include <errobject.hxx>
|
|
|
|
#include <comphelper/string.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
#include <com/sun/star/util/DateTime.hpp>
|
|
#include <com/sun/star/lang/Locale.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
|
|
#include <com/sun/star/script/XErrorQuery.hpp>
|
|
#include <ooo/vba/VbTriState.hpp>
|
|
#include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
|
|
#include <memory>
|
|
#include <random>
|
|
#include <o3tl/char16_t2wchar_t.hxx>
|
|
|
|
using namespace comphelper;
|
|
using namespace osl;
|
|
using namespace com::sun::star;
|
|
using namespace com::sun::star::lang;
|
|
using namespace com::sun::star::uno;
|
|
|
|
#include <date.hxx>
|
|
#include <sbstdobj.hxx>
|
|
#include <rtlproto.hxx>
|
|
#include <image.hxx>
|
|
#include <iosys.hxx>
|
|
#include "ddectrl.hxx"
|
|
#include <sbintern.hxx>
|
|
#include <basic/vbahelper.hxx>
|
|
|
|
#include <vector>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include <sbobjmod.hxx>
|
|
#include <sbxmod.hxx>
|
|
|
|
#ifdef _WIN32
|
|
#include <prewin.h>
|
|
#include <direct.h>
|
|
#include <io.h>
|
|
#include <postwin.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if HAVE_FEATURE_SCRIPTING
|
|
|
|
static void FilterWhiteSpace( OUString& rStr )
|
|
{
|
|
if (rStr.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
OUStringBuffer aRet;
|
|
|
|
for (sal_Int32 i = 0; i < rStr.getLength(); ++i)
|
|
{
|
|
sal_Unicode cChar = rStr[i];
|
|
if ((cChar != ' ') && (cChar != '\t') &&
|
|
(cChar != '\n') && (cChar != '\r'))
|
|
{
|
|
aRet.append(cChar);
|
|
}
|
|
}
|
|
|
|
rStr = aRet.makeStringAndClear();
|
|
}
|
|
|
|
static long GetDayDiff( const Date& rDate );
|
|
|
|
static const CharClass& GetCharClass()
|
|
{
|
|
static CharClass aCharClass( Application::GetSettings().GetLanguageTag() );
|
|
return aCharClass;
|
|
}
|
|
|
|
static bool isFolder( FileStatus::Type aType )
|
|
{
|
|
return ( aType == FileStatus::Directory || aType == FileStatus::Volume );
|
|
}
|
|
|
|
|
|
//*** UCB file access ***
|
|
|
|
// Converts possibly relative paths to absolute paths
|
|
// according to the setting done by ChDir/ChDrive
|
|
OUString getFullPath( const OUString& aRelPath )
|
|
{
|
|
OUString aFileURL;
|
|
|
|
// #80204 Try first if it already is a valid URL
|
|
INetURLObject aURLObj( aRelPath );
|
|
aFileURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
|
|
|
|
if( aFileURL.isEmpty() )
|
|
{
|
|
File::getFileURLFromSystemPath( aRelPath, aFileURL );
|
|
}
|
|
|
|
return aFileURL;
|
|
}
|
|
|
|
// TODO: -> SbiGlobals
|
|
static uno::Reference< ucb::XSimpleFileAccess3 > const & getFileAccess()
|
|
{
|
|
static uno::Reference< ucb::XSimpleFileAccess3 > xSFI = ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
|
|
return xSFI;
|
|
}
|
|
|
|
|
|
// Properties and methods lie down the return value at the Get (bPut = sal_False) in the
|
|
// element 0 of the Argv; the value of element 0 is saved at Put (bPut = sal_True)
|
|
|
|
// CreateObject( class )
|
|
|
|
void SbRtl_CreateObject(StarBASIC * pBasic, SbxArray & rPar, bool)
|
|
{
|
|
OUString aClass( rPar.Get32(1)->GetOUString() );
|
|
SbxObjectRef p = SbxBase::CreateObject( aClass );
|
|
if( !p.is() )
|
|
StarBASIC::Error( ERRCODE_BASIC_CANNOT_LOAD );
|
|
else
|
|
{
|
|
// Convenience: enter BASIC as parent
|
|
p->SetParent( pBasic );
|
|
rPar.Get32(0)->PutObject( p.get() );
|
|
}
|
|
}
|
|
|
|
// Error( n )
|
|
|
|
void SbRtl_Error(StarBASIC * pBasic, SbxArray & rPar, bool)
|
|
{
|
|
if( !pBasic )
|
|
StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
|
|
else
|
|
{
|
|
OUString aErrorMsg;
|
|
ErrCode nErr = ERRCODE_NONE;
|
|
sal_Int32 nCode = 0;
|
|
if( rPar.Count32() == 1 )
|
|
{
|
|
nErr = StarBASIC::GetErrBasic();
|
|
aErrorMsg = StarBASIC::GetErrorMsg();
|
|
}
|
|
else
|
|
{
|
|
nCode = rPar.Get32(1)->GetLong();
|
|
if( nCode > 65535 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_CONVERSION );
|
|
}
|
|
else
|
|
{
|
|
nErr = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(nCode) );
|
|
}
|
|
}
|
|
|
|
bool bVBA = SbiRuntime::isVBAEnabled();
|
|
OUString tmpErrMsg;
|
|
if( bVBA && !aErrorMsg.isEmpty())
|
|
{
|
|
tmpErrMsg = aErrorMsg;
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::MakeErrorText( nErr, aErrorMsg );
|
|
tmpErrMsg = StarBASIC::GetErrorText();
|
|
}
|
|
// If this rtlfunc 'Error' passed an errcode the same as the active Err Objects's
|
|
// current err then return the description for the error message if it is set
|
|
// ( complicated isn't it ? )
|
|
if ( bVBA && rPar.Count32() > 1 )
|
|
{
|
|
uno::Reference< ooo::vba::XErrObject > xErrObj( SbxErrObject::getUnoErrObject() );
|
|
if ( xErrObj.is() && xErrObj->getNumber() == nCode && !xErrObj->getDescription().isEmpty() )
|
|
{
|
|
tmpErrMsg = xErrObj->getDescription();
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutString( tmpErrMsg );
|
|
}
|
|
}
|
|
|
|
// Sinus
|
|
|
|
void SbRtl_Sin(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
rPar.Get32(0)->PutDouble( sin( pArg->GetDouble() ) );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Cos(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
rPar.Get32(0)->PutDouble( cos( pArg->GetDouble() ) );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Atn(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
rPar.Get32(0)->PutDouble( atan( pArg->GetDouble() ) );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Abs(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
rPar.Get32(0)->PutDouble( fabs( pArg->GetDouble() ) );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Asc(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
OUString aStr( pArg->GetOUString() );
|
|
if ( aStr.isEmpty())
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
rPar.Get32(0)->PutEmpty();
|
|
}
|
|
else
|
|
{
|
|
sal_Unicode aCh = aStr[0];
|
|
rPar.Get32(0)->PutLong( aCh );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void implChr( SbxArray& rPar, bool bChrW )
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
|
|
OUString aStr;
|
|
if( !bChrW && SbiRuntime::isVBAEnabled() )
|
|
{
|
|
char c = static_cast<char>(pArg->GetByte());
|
|
aStr = OUString(&c, 1, osl_getThreadTextEncoding());
|
|
}
|
|
else
|
|
{
|
|
sal_Unicode aCh = static_cast<sal_Unicode>(pArg->GetUShort());
|
|
aStr = OUString(aCh);
|
|
}
|
|
rPar.Get32(0)->PutString( aStr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Chr(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
implChr( rPar, false/*bChrW*/ );
|
|
}
|
|
|
|
void SbRtl_ChrW(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
implChr( rPar, true/*bChrW*/ );
|
|
}
|
|
|
|
#if defined _WIN32
|
|
|
|
namespace {
|
|
|
|
extern "C" void invalidParameterHandler(
|
|
wchar_t const * expression, wchar_t const * function, wchar_t const * file, unsigned int line,
|
|
uintptr_t)
|
|
{
|
|
SAL_INFO(
|
|
"basic",
|
|
"invalid parameter during _wgetdcwd; \"" << (expression ? o3tl::toU(expression) : u"???")
|
|
<< "\" (" << (function ? o3tl::toU(function) : u"???") << ") at "
|
|
<< (file ? o3tl::toU(file) : u"???") << ":" << line);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
void SbRtl_CurDir(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
|
|
{
|
|
(void)pBasic;
|
|
(void)bWrite;
|
|
|
|
// #57064 Although this function doesn't work with DirEntry, it isn't touched
|
|
// by the adjustment to virtual URLs, as, using the DirEntry-functionality,
|
|
// there's no possibility to detect the current one in a way that a virtual URL
|
|
// could be delivered.
|
|
|
|
#if defined(_WIN32)
|
|
int nCurDir = 0; // Current dir // JSM
|
|
if ( rPar.Count32() == 2 )
|
|
{
|
|
OUString aDrive = rPar.Get32(1)->GetOUString();
|
|
if ( aDrive.getLength() != 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
auto c = rtl::toAsciiUpperCase(aDrive[0]);
|
|
if ( !rtl::isAsciiUpperCase( c ) )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
nCurDir = c - 'A' + 1;
|
|
}
|
|
wchar_t pBuffer[ _MAX_PATH ];
|
|
// _wgetdcwd calls the C runtime's invalid parameter handler (which by default terminates the
|
|
// process) if nCurDir does not correspond to an existing drive, so temporarily set a "harmless"
|
|
// handler:
|
|
auto const handler = _set_thread_local_invalid_parameter_handler(&invalidParameterHandler);
|
|
auto const ok = _wgetdcwd( nCurDir, pBuffer, _MAX_PATH ) != nullptr;
|
|
_set_thread_local_invalid_parameter_handler(handler);
|
|
if ( ok )
|
|
{
|
|
rPar.Get32(0)->PutString( o3tl::toU(pBuffer) );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_NO_DEVICE );
|
|
}
|
|
|
|
#else
|
|
|
|
const int PATH_INCR = 250;
|
|
|
|
int nSize = PATH_INCR;
|
|
std::unique_ptr<char[]> pMem;
|
|
while( true )
|
|
{
|
|
pMem.reset(new char[nSize]);
|
|
if( !pMem )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_NO_MEMORY );
|
|
return;
|
|
}
|
|
if( getcwd( pMem.get(), nSize-1 ) != nullptr )
|
|
{
|
|
rPar.Get32(0)->PutString( OUString::createFromAscii(pMem.get()) );
|
|
return;
|
|
}
|
|
if( errno != ERANGE )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
|
|
return;
|
|
}
|
|
nSize += PATH_INCR;
|
|
};
|
|
|
|
#endif
|
|
}
|
|
|
|
void SbRtl_ChDir(StarBASIC * pBasic, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if (rPar.Count32() == 2)
|
|
{
|
|
// VBA: track current directory per document type (separately for Writer, Calc, Impress, etc.)
|
|
if( SbiRuntime::isVBAEnabled() )
|
|
{
|
|
::basic::vba::registerCurrentDirectory( getDocumentModel( pBasic ), rPar.Get32(1)->GetOUString() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
void SbRtl_ChDrive(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if (rPar.Count32() != 2)
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
|
|
// Implementation of StepRENAME with UCB
|
|
void implStepRenameUCB( const OUString& aSource, const OUString& aDest )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
OUString aSourceFullPath = getFullPath( aSource );
|
|
if( !xSFI->exists( aSourceFullPath ) )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND );
|
|
return;
|
|
}
|
|
|
|
OUString aDestFullPath = getFullPath( aDest );
|
|
if( xSFI->exists( aDestFullPath ) )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_EXISTS );
|
|
}
|
|
else
|
|
{
|
|
xSFI->move( aSourceFullPath, aDestFullPath );
|
|
}
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Implementation of StepRENAME with OSL
|
|
void implStepRenameOSL( const OUString& aSource, const OUString& aDest )
|
|
{
|
|
FileBase::RC nRet = File::move( getFullPath( aSource ), getFullPath( aDest ) );
|
|
if( nRet != FileBase::E_None )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND );
|
|
}
|
|
}
|
|
|
|
void SbRtl_FileCopy(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if (rPar.Count32() == 3)
|
|
{
|
|
OUString aSource = rPar.Get32(1)->GetOUString();
|
|
OUString aDest = rPar.Get32(2)->GetOUString();
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
xSFI->copy( getFullPath( aSource ), getFullPath( aDest ) );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FileBase::RC nRet = File::copy( getFullPath( aSource ), getFullPath( aDest ) );
|
|
if( nRet != FileBase::E_None )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
|
|
void SbRtl_Kill(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if (rPar.Count32() == 2)
|
|
{
|
|
OUString aFileSpec = rPar.Get32(1)->GetOUString();
|
|
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
OUString aFullPath = getFullPath( aFileSpec );
|
|
if( !xSFI->exists( aFullPath ) || xSFI->isFolder( aFullPath ) )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND );
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
xSFI->kill( aFullPath );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
File::remove( getFullPath( aFileSpec ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
void SbRtl_MkDir(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if (rPar.Count32() == 2)
|
|
{
|
|
OUString aPath = rPar.Get32(1)->GetOUString();
|
|
if ( SbiRuntime::isVBAEnabled() )
|
|
{
|
|
// In vba if the full path is not specified then
|
|
// folder is created relative to the curdir
|
|
INetURLObject aURLObj( getFullPath( aPath ) );
|
|
if ( aURLObj.GetProtocol() != INetProtocol::File )
|
|
{
|
|
SbxArrayRef pPar = new SbxArray();
|
|
SbxVariableRef pResult = new SbxVariable();
|
|
SbxVariableRef pParam = new SbxVariable();
|
|
pPar->Insert32( pResult.get(), pPar->Count32() );
|
|
pPar->Insert32( pParam.get(), pPar->Count32() );
|
|
SbRtl_CurDir( pBasic, *pPar, bWrite );
|
|
|
|
OUString sCurPathURL;
|
|
File::getFileURLFromSystemPath( pPar->Get32(0)->GetOUString(), sCurPathURL );
|
|
|
|
aURLObj.SetURL( sCurPathURL );
|
|
aURLObj.Append( aPath );
|
|
File::getSystemPathFromFileURL(aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ),aPath ) ;
|
|
}
|
|
}
|
|
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
xSFI->createFolder( getFullPath( aPath ) );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Directory::create( getFullPath( aPath ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
|
|
static void implRemoveDirRecursive( const OUString& aDirPath )
|
|
{
|
|
DirectoryItem aItem;
|
|
FileBase::RC nRet = DirectoryItem::get( aDirPath, aItem );
|
|
bool bExists = (nRet == FileBase::E_None);
|
|
|
|
FileStatus aFileStatus( osl_FileStatus_Mask_Type );
|
|
nRet = aItem.getFileStatus( aFileStatus );
|
|
bool bFolder = nRet == FileBase::E_None
|
|
&& isFolder( aFileStatus.getFileType() );
|
|
|
|
if( !bExists || !bFolder )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND );
|
|
return;
|
|
}
|
|
|
|
Directory aDir( aDirPath );
|
|
nRet = aDir.open();
|
|
if( nRet != FileBase::E_None )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND );
|
|
return;
|
|
}
|
|
aDir.close();
|
|
|
|
comphelper::DirectoryHelper::deleteDirRecursively(aDirPath);
|
|
}
|
|
|
|
|
|
void SbRtl_RmDir(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if (rPar.Count32() == 2)
|
|
{
|
|
OUString aPath = rPar.Get32(1)->GetOUString();
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
if( !xSFI->isFolder( aPath ) )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PATH_NOT_FOUND );
|
|
return;
|
|
}
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
Sequence< OUString > aContent = xSFI->getFolderContents( aPath, true );
|
|
if( aContent.hasElements() )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_ACCESS_ERROR );
|
|
return;
|
|
}
|
|
}
|
|
|
|
xSFI->kill( getFullPath( aPath ) );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
implRemoveDirRecursive( getFullPath( aPath ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
void SbRtl_SendKeys(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
StarBASIC::Error(ERRCODE_BASIC_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
void SbRtl_Exp(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
double aDouble = rPar.Get32(1)->GetDouble();
|
|
aDouble = exp( aDouble );
|
|
checkArithmeticOverflow( aDouble );
|
|
rPar.Get32(0)->PutDouble( aDouble );
|
|
}
|
|
}
|
|
|
|
void SbRtl_FileLen(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
OUString aStr( pArg->GetOUString() );
|
|
sal_Int32 nLen = 0;
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
nLen = xSFI->getSize( getFullPath( aStr ) );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DirectoryItem aItem;
|
|
(void)DirectoryItem::get( getFullPath( aStr ), aItem );
|
|
FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
|
|
(void)aItem.getFileStatus( aFileStatus );
|
|
nLen = static_cast<sal_Int32>(aFileStatus.getFileSize());
|
|
}
|
|
rPar.Get32(0)->PutLong( static_cast<long>(nLen) );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Hex(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
// converting value to unsigned and limit to 2 or 4 byte representation
|
|
sal_uInt32 nVal = pArg->IsInteger() ?
|
|
static_cast<sal_uInt16>(pArg->GetInteger()) :
|
|
static_cast<sal_uInt32>(pArg->GetLong());
|
|
OUString aStr(OUString::number( nVal, 16 ));
|
|
aStr = aStr.toAsciiUpperCase();
|
|
rPar.Get32(0)->PutString( aStr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_FuncCaller(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( SbiRuntime::isVBAEnabled() && GetSbData()->pInst && GetSbData()->pInst->pRun )
|
|
{
|
|
if ( GetSbData()->pInst->pRun->GetExternalCaller() )
|
|
*rPar.Get32(0) = *GetSbData()->pInst->pRun->GetExternalCaller();
|
|
else
|
|
{
|
|
SbxVariableRef pVar = new SbxVariable(SbxVARIANT);
|
|
*rPar.Get32(0) = *pVar;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_NOT_IMPLEMENTED );
|
|
}
|
|
|
|
}
|
|
// InStr( [start],string,string,[compare] )
|
|
|
|
void SbRtl_InStr(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32()-1;
|
|
if ( nArgCount < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
sal_Int32 nStartPos = 1;
|
|
sal_Int32 nFirstStringPos = 1;
|
|
|
|
if ( nArgCount >= 3 )
|
|
{
|
|
nStartPos = rPar.Get32(1)->GetLong();
|
|
if( nStartPos <= 0 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
nStartPos = 1;
|
|
}
|
|
nFirstStringPos++;
|
|
}
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bTextMode;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
SbiRuntime* pRT = pInst->pRun;
|
|
bTextMode = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT );
|
|
}
|
|
else
|
|
{
|
|
bTextMode = true;
|
|
}
|
|
if ( nArgCount == 4 )
|
|
{
|
|
bTextMode = rPar.Get32(4)->GetInteger();
|
|
}
|
|
sal_Int32 nPos;
|
|
const OUString& rToken = rPar.Get32(nFirstStringPos+1)->GetOUString();
|
|
|
|
// #97545 Always find empty string
|
|
if( rToken.isEmpty() )
|
|
{
|
|
nPos = nStartPos;
|
|
}
|
|
else
|
|
{
|
|
if( !bTextMode )
|
|
{
|
|
const OUString& rStr1 = rPar.Get32(nFirstStringPos)->GetOUString();
|
|
nPos = rStr1.indexOf( rToken, nStartPos - 1 ) + 1;
|
|
}
|
|
else
|
|
{
|
|
OUString aStr1 = rPar.Get32(nFirstStringPos)->GetOUString();
|
|
OUString aToken = rToken;
|
|
|
|
aStr1 = aStr1.toAsciiUpperCase();
|
|
aToken = aToken.toAsciiUpperCase();
|
|
|
|
nPos = aStr1.indexOf( aToken, nStartPos-1 ) + 1;
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutLong( nPos );
|
|
}
|
|
}
|
|
|
|
|
|
// InstrRev(string1, string2[, start[, compare]])
|
|
|
|
void SbRtl_InStrRev(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32()-1;
|
|
if ( nArgCount < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aStr1 = rPar.Get32(1)->GetOUString();
|
|
OUString aToken = rPar.Get32(2)->GetOUString();
|
|
|
|
sal_Int32 nStartPos = -1;
|
|
if ( nArgCount >= 3 )
|
|
{
|
|
nStartPos = rPar.Get32(3)->GetLong();
|
|
if( nStartPos <= 0 && nStartPos != -1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
nStartPos = -1;
|
|
}
|
|
}
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bTextMode;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
SbiRuntime* pRT = pInst->pRun;
|
|
bTextMode = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT );
|
|
}
|
|
else
|
|
{
|
|
bTextMode = true;
|
|
}
|
|
if ( nArgCount == 4 )
|
|
{
|
|
bTextMode = rPar.Get32(4)->GetInteger();
|
|
}
|
|
sal_Int32 nStrLen = aStr1.getLength();
|
|
if( nStartPos == -1 )
|
|
{
|
|
nStartPos = nStrLen;
|
|
}
|
|
|
|
sal_Int32 nPos = 0;
|
|
if( nStartPos <= nStrLen )
|
|
{
|
|
sal_Int32 nTokenLen = aToken.getLength();
|
|
if( !nTokenLen )
|
|
{
|
|
// Always find empty string
|
|
nPos = nStartPos;
|
|
}
|
|
else if( nStrLen > 0 )
|
|
{
|
|
if( !bTextMode )
|
|
{
|
|
nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1;
|
|
}
|
|
else
|
|
{
|
|
aStr1 = aStr1.toAsciiUpperCase();
|
|
aToken = aToken.toAsciiUpperCase();
|
|
|
|
nPos = aStr1.lastIndexOf( aToken, nStartPos ) + 1;
|
|
}
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutLong( nPos );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Int( 2.8 ) = 2.0
|
|
Int( -2.8 ) = -3.0
|
|
Fix( 2.8 ) = 2.0
|
|
Fix( -2.8 ) = -2.0 <- !!
|
|
*/
|
|
|
|
void SbRtl_Int(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
double aDouble= pArg->GetDouble();
|
|
/*
|
|
floor( 2.8 ) = 2.0
|
|
floor( -2.8 ) = -3.0
|
|
*/
|
|
aDouble = floor( aDouble );
|
|
rPar.Get32(0)->PutDouble( aDouble );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Fix(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
double aDouble = pArg->GetDouble();
|
|
if ( aDouble >= 0.0 )
|
|
aDouble = floor( aDouble );
|
|
else
|
|
aDouble = ceil( aDouble );
|
|
rPar.Get32(0)->PutDouble( aDouble );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_LCase(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
const CharClass& rCharClass = GetCharClass();
|
|
OUString aStr( rPar.Get32(1)->GetOUString() );
|
|
aStr = rCharClass.lowercase(aStr);
|
|
rPar.Get32(0)->PutString( aStr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Left(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aStr( rPar.Get32(1)->GetOUString() );
|
|
sal_Int32 nResultLen = rPar.Get32(2)->GetLong();
|
|
if( nResultLen < 0 )
|
|
{
|
|
nResultLen = 0;
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else if(nResultLen > aStr.getLength())
|
|
{
|
|
nResultLen = aStr.getLength();
|
|
}
|
|
aStr = aStr.copy(0, nResultLen );
|
|
rPar.Get32(0)->PutString( aStr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Log(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double aArg = rPar.Get32(1)->GetDouble();
|
|
if ( aArg > 0 )
|
|
{
|
|
double d = log( aArg );
|
|
checkArithmeticOverflow( d );
|
|
rPar.Get32(0)->PutDouble( d );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_LTrim(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aStr(comphelper::string::stripStart(rPar.Get32(1)->GetOUString(), ' '));
|
|
rPar.Get32(0)->PutString(aStr);
|
|
}
|
|
}
|
|
|
|
|
|
// Mid( String, nStart, nLength )
|
|
|
|
void SbRtl_Mid(StarBASIC *, SbxArray & rPar, bool bWrite)
|
|
{
|
|
int nArgCount = rPar.Count32()-1;
|
|
if ( nArgCount < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
// #23178: replicate the functionality of Mid$ as a command
|
|
// by adding a replacement-string as a fourth parameter.
|
|
// In contrast to the original the third parameter (nLength)
|
|
// can't be left out here. That's considered in bWrite already.
|
|
if( nArgCount == 4 )
|
|
{
|
|
bWrite = true;
|
|
}
|
|
OUString aArgStr = rPar.Get32(1)->GetOUString();
|
|
sal_Int32 nStartPos = rPar.Get32(2)->GetLong();
|
|
if ( nStartPos < 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
nStartPos--;
|
|
sal_Int32 nLen = -1;
|
|
bool bWriteNoLenParam = false;
|
|
if ( nArgCount == 3 || bWrite )
|
|
{
|
|
sal_Int32 n = rPar.Get32(3)->GetLong();
|
|
if( bWrite && n == -1 )
|
|
{
|
|
bWriteNoLenParam = true;
|
|
}
|
|
nLen = n;
|
|
}
|
|
if ( bWrite )
|
|
{
|
|
sal_Int32 nArgLen = aArgStr.getLength();
|
|
if( nStartPos > nArgLen )
|
|
{
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
nStartPos = nArgLen;
|
|
}
|
|
|
|
OUString aReplaceStr = rPar.Get32(4)->GetOUString();
|
|
sal_Int32 nReplaceStrLen = aReplaceStr.getLength();
|
|
sal_Int32 nReplaceLen;
|
|
if( bWriteNoLenParam )
|
|
{
|
|
nReplaceLen = nArgLen - nStartPos;
|
|
}
|
|
else
|
|
{
|
|
nReplaceLen = nLen;
|
|
if( nReplaceLen < 0 || nReplaceLen > nArgLen - nStartPos )
|
|
{
|
|
nReplaceLen = nArgLen - nStartPos;
|
|
}
|
|
}
|
|
|
|
OUStringBuffer aResultStr = aArgStr;
|
|
sal_Int32 nErase = nReplaceLen;
|
|
aResultStr.remove( nStartPos, nErase );
|
|
aResultStr.insert(
|
|
nStartPos, aReplaceStr.getStr(), std::min(nReplaceLen, nReplaceStrLen));
|
|
|
|
rPar.Get32(1)->PutString( aResultStr.makeStringAndClear() );
|
|
}
|
|
else
|
|
{
|
|
OUString aResultStr;
|
|
if (nStartPos > aArgStr.getLength())
|
|
{
|
|
// do nothing
|
|
}
|
|
else if(nArgCount == 2)
|
|
{
|
|
aResultStr = aArgStr.copy( nStartPos);
|
|
}
|
|
else
|
|
{
|
|
if (nLen < 0)
|
|
nLen = 0;
|
|
if(nStartPos + nLen > aArgStr.getLength())
|
|
{
|
|
nLen = aArgStr.getLength() - nStartPos;
|
|
}
|
|
if (nLen > 0)
|
|
aResultStr = aArgStr.copy( nStartPos, nLen );
|
|
}
|
|
rPar.Get32(0)->PutString( aResultStr );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_Oct(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
char aBuffer[16];
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
if ( pArg->IsInteger() )
|
|
{
|
|
snprintf( aBuffer, sizeof(aBuffer), "%o", pArg->GetInteger() );
|
|
}
|
|
else
|
|
{
|
|
snprintf( aBuffer, sizeof(aBuffer), "%lo", static_cast<long unsigned int>(pArg->GetLong()) );
|
|
}
|
|
rPar.Get32(0)->PutString( OUString::createFromAscii( aBuffer ) );
|
|
}
|
|
}
|
|
|
|
// Replace(expression, find, replace[, start[, count[, compare]]])
|
|
|
|
void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32()-1;
|
|
if ( nArgCount < 3 || nArgCount > 6 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aExpStr = rPar.Get32(1)->GetOUString();
|
|
OUString aFindStr = rPar.Get32(2)->GetOUString();
|
|
OUString aReplaceStr = rPar.Get32(3)->GetOUString();
|
|
|
|
sal_Int32 lStartPos = 1;
|
|
if ( nArgCount >= 4 )
|
|
{
|
|
if( rPar.Get32(4)->GetType() != SbxEMPTY )
|
|
{
|
|
lStartPos = rPar.Get32(4)->GetLong();
|
|
}
|
|
if( lStartPos < 1)
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
lStartPos = 1;
|
|
}
|
|
}
|
|
|
|
sal_Int32 lCount = -1;
|
|
if( nArgCount >=5 )
|
|
{
|
|
if( rPar.Get32(5)->GetType() != SbxEMPTY )
|
|
{
|
|
lCount = rPar.Get32(5)->GetLong();
|
|
}
|
|
if( lCount < -1)
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
lCount = -1;
|
|
}
|
|
}
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bTextMode;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
SbiRuntime* pRT = pInst->pRun;
|
|
bTextMode = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT );
|
|
}
|
|
else
|
|
{
|
|
bTextMode = true;
|
|
}
|
|
if ( nArgCount == 6 )
|
|
{
|
|
bTextMode = rPar.Get32(6)->GetInteger();
|
|
}
|
|
sal_Int32 nExpStrLen = aExpStr.getLength();
|
|
sal_Int32 nFindStrLen = aFindStr.getLength();
|
|
sal_Int32 nReplaceStrLen = aReplaceStr.getLength();
|
|
|
|
if( lStartPos <= nExpStrLen )
|
|
{
|
|
sal_Int32 nPos = lStartPos - 1;
|
|
sal_Int32 nCounts = 0;
|
|
while( lCount == -1 || lCount > nCounts )
|
|
{
|
|
OUString aSrcStr( aExpStr );
|
|
if( bTextMode )
|
|
{
|
|
aSrcStr = aSrcStr.toAsciiUpperCase();
|
|
aFindStr = aFindStr.toAsciiUpperCase();
|
|
}
|
|
nPos = aSrcStr.indexOf( aFindStr, nPos );
|
|
if( nPos >= 0 )
|
|
{
|
|
aExpStr = aExpStr.replaceAt( nPos, nFindStrLen, aReplaceStr );
|
|
nPos = nPos + nReplaceStrLen;
|
|
nCounts++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutString( aExpStr.copy( lStartPos - 1 ) );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Right(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
const OUString& rStr = rPar.Get32(1)->GetOUString();
|
|
int nResultLen = rPar.Get32(2)->GetLong();
|
|
if( nResultLen < 0 )
|
|
{
|
|
nResultLen = 0;
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
int nStrLen = rStr.getLength();
|
|
if ( nResultLen > nStrLen )
|
|
{
|
|
nResultLen = nStrLen;
|
|
}
|
|
OUString aResultStr = rStr.copy( nStrLen - nResultLen );
|
|
rPar.Get32(0)->PutString( aResultStr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_RTL(StarBASIC * pBasic, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutObject( pBasic->getRTL().get() );
|
|
}
|
|
|
|
void SbRtl_RTrim(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aStr(comphelper::string::stripEnd(rPar.Get32(1)->GetOUString(), ' '));
|
|
rPar.Get32(0)->PutString(aStr);
|
|
}
|
|
}
|
|
|
|
void SbRtl_Sgn(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double aDouble = rPar.Get32(1)->GetDouble();
|
|
sal_Int16 nResult = 0;
|
|
if ( aDouble > 0 )
|
|
{
|
|
nResult = 1;
|
|
}
|
|
else if ( aDouble < 0 )
|
|
{
|
|
nResult = -1;
|
|
}
|
|
rPar.Get32(0)->PutInteger( nResult );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Space(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUStringBuffer aBuf;
|
|
string::padToLength(aBuf, rPar.Get32(1)->GetLong(), ' ');
|
|
rPar.Get32(0)->PutString(aBuf.makeStringAndClear());
|
|
}
|
|
}
|
|
|
|
void SbRtl_Spc(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUStringBuffer aBuf;
|
|
string::padToLength(aBuf, rPar.Get32(1)->GetLong(), ' ');
|
|
rPar.Get32(0)->PutString(aBuf.makeStringAndClear());
|
|
}
|
|
}
|
|
|
|
void SbRtl_Sqr(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double aDouble = rPar.Get32(1)->GetDouble();
|
|
if ( aDouble >= 0 )
|
|
{
|
|
rPar.Get32(0)->PutDouble( sqrt( aDouble ));
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_Str(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aStr;
|
|
OUString aStrNew("");
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
pArg->Format( aStr );
|
|
|
|
// Numbers start with a space
|
|
if( pArg->IsNumericRTL() )
|
|
{
|
|
// replace commas by points so that it's symmetric to Val!
|
|
aStr = aStr.replaceFirst( ",", "." );
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
sal_Int32 nLen = aStr.getLength();
|
|
|
|
const sal_Unicode* pBuf = aStr.getStr();
|
|
|
|
bool bNeg = ( pBuf[0] == '-' );
|
|
sal_Int32 iZeroSearch = 0;
|
|
if( bNeg )
|
|
{
|
|
aStrNew += "-";
|
|
iZeroSearch++;
|
|
}
|
|
else
|
|
{
|
|
if( pBuf[0] != ' ' )
|
|
{
|
|
aStrNew += " ";
|
|
}
|
|
}
|
|
sal_Int32 iNext = iZeroSearch + 1;
|
|
if( pBuf[iZeroSearch] == '0' && nLen > iNext && pBuf[iNext] == '.' )
|
|
{
|
|
iZeroSearch += 1;
|
|
}
|
|
aStrNew += aStr.copy(iZeroSearch);
|
|
}
|
|
else
|
|
{
|
|
aStrNew = " " + aStr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aStrNew = aStr;
|
|
}
|
|
rPar.Get32(0)->PutString( aStrNew );
|
|
}
|
|
}
|
|
|
|
void SbRtl_StrComp(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
rPar.Get32(0)->PutEmpty();
|
|
return;
|
|
}
|
|
const OUString& rStr1 = rPar.Get32(1)->GetOUString();
|
|
const OUString& rStr2 = rPar.Get32(2)->GetOUString();
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bTextCompare;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
SbiRuntime* pRT = pInst->pRun;
|
|
bTextCompare = pRT && pRT->IsImageFlag( SbiImageFlags::COMPARETEXT );
|
|
}
|
|
else
|
|
{
|
|
bTextCompare = true;
|
|
}
|
|
if ( rPar.Count32() == 4 )
|
|
bTextCompare = rPar.Get32(3)->GetInteger();
|
|
|
|
if( !bCompatibility )
|
|
{
|
|
bTextCompare = !bTextCompare;
|
|
}
|
|
sal_Int32 nRetValue = 0;
|
|
if( bTextCompare )
|
|
{
|
|
::utl::TransliterationWrapper* pTransliterationWrapper = GetSbData()->pTransliterationWrapper.get();
|
|
if( !pTransliterationWrapper )
|
|
{
|
|
uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
|
|
GetSbData()->pTransliterationWrapper.reset(
|
|
new ::utl::TransliterationWrapper( xContext,
|
|
TransliterationFlags::IGNORE_CASE |
|
|
TransliterationFlags::IGNORE_KANA |
|
|
TransliterationFlags::IGNORE_WIDTH ) );
|
|
pTransliterationWrapper = GetSbData()->pTransliterationWrapper.get();
|
|
}
|
|
|
|
LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
|
|
pTransliterationWrapper->loadModuleIfNeeded( eLangType );
|
|
nRetValue = pTransliterationWrapper->compareString( rStr1, rStr2 );
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 aResult;
|
|
aResult = rStr1.compareTo( rStr2 );
|
|
if ( aResult < 0 )
|
|
{
|
|
nRetValue = -1;
|
|
}
|
|
else if ( aResult > 0)
|
|
{
|
|
nRetValue = 1;
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutInteger( sal::static_int_cast< sal_Int16 >( nRetValue ) );
|
|
}
|
|
|
|
void SbRtl_String(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Unicode aFiller;
|
|
sal_Int32 lCount = rPar.Get32(1)->GetLong();
|
|
if( lCount < 0 || lCount > 0xffff )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
if( rPar.Get32(2)->GetType() == SbxINTEGER )
|
|
{
|
|
aFiller = static_cast<sal_Unicode>(rPar.Get32(2)->GetInteger());
|
|
}
|
|
else
|
|
{
|
|
const OUString& rStr = rPar.Get32(2)->GetOUString();
|
|
aFiller = rStr[0];
|
|
}
|
|
OUStringBuffer aBuf(lCount);
|
|
string::padToLength(aBuf, lCount, aFiller);
|
|
rPar.Get32(0)->PutString(aBuf.makeStringAndClear());
|
|
}
|
|
}
|
|
|
|
void SbRtl_Tab(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
else
|
|
{
|
|
OUStringBuffer aStr;
|
|
comphelper::string::padToLength(aStr, rPar.Get32(1)->GetLong(), '\t');
|
|
rPar.Get32(0)->PutString(aStr.makeStringAndClear());
|
|
}
|
|
}
|
|
|
|
void SbRtl_Tan(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
rPar.Get32(0)->PutDouble( tan( pArg->GetDouble() ) );
|
|
}
|
|
}
|
|
|
|
void SbRtl_UCase(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
const CharClass& rCharClass = GetCharClass();
|
|
OUString aStr( rPar.Get32(1)->GetOUString() );
|
|
aStr = rCharClass.uppercase( aStr );
|
|
rPar.Get32(0)->PutString( aStr );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Val(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
|
|
{
|
|
(void)pBasic;
|
|
(void)bWrite;
|
|
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double nResult = 0.0;
|
|
char* pEndPtr;
|
|
|
|
OUString aStr( rPar.Get32(1)->GetOUString() );
|
|
|
|
FilterWhiteSpace( aStr );
|
|
if ( aStr.getLength() > 1 && aStr[0] == '&' )
|
|
{
|
|
int nRadix = 10;
|
|
char aChar = static_cast<char>(aStr[1]);
|
|
if ( aChar == 'h' || aChar == 'H' )
|
|
{
|
|
nRadix = 16;
|
|
}
|
|
else if ( aChar == 'o' || aChar == 'O' )
|
|
{
|
|
nRadix = 8;
|
|
}
|
|
if ( nRadix != 10 )
|
|
{
|
|
OString aByteStr(OUStringToOString(aStr, osl_getThreadTextEncoding()));
|
|
sal_Int16 nlResult = static_cast<sal_Int16>(strtol( aByteStr.getStr()+2, &pEndPtr, nRadix));
|
|
nResult = static_cast<double>(nlResult);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
|
|
sal_Int32 nParseEnd = 0;
|
|
nResult = ::rtl::math::stringToDouble( aStr, '.', ',', &eStatus, &nParseEnd );
|
|
if ( eStatus != rtl_math_ConversionStatus_Ok )
|
|
StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
|
|
/* TODO: we should check whether all characters were parsed here,
|
|
* but earlier code silently ignored trailing nonsense such as "1x"
|
|
* resulting in 1 with the side effect that any alpha-only-string
|
|
* like "x" resulted in 0. Not changing that now (2013-03-22) as
|
|
* user macros may rely on it. */
|
|
#if 0
|
|
else if ( nParseEnd != aStr.getLength() )
|
|
StarBASIC::Error( ERRCODE_BASIC_CONVERSION );
|
|
#endif
|
|
}
|
|
|
|
rPar.Get32(0)->PutDouble( nResult );
|
|
}
|
|
}
|
|
|
|
|
|
// Helper functions for date conversion
|
|
sal_Int16 implGetDateDay( double aDate )
|
|
{
|
|
aDate -= 2.0; // standardize: 1.1.1900 => 0.0
|
|
aDate = floor( aDate );
|
|
Date aRefDate( 1, 1, 1900 );
|
|
aRefDate.AddDays( aDate );
|
|
|
|
sal_Int16 nRet = static_cast<sal_Int16>( aRefDate.GetDay() );
|
|
return nRet;
|
|
}
|
|
|
|
sal_Int16 implGetDateMonth( double aDate )
|
|
{
|
|
Date aRefDate( 1,1,1900 );
|
|
sal_Int32 nDays = static_cast<sal_Int32>(aDate);
|
|
nDays -= 2; // standardize: 1.1.1900 => 0.0
|
|
aRefDate.AddDays( nDays );
|
|
sal_Int16 nRet = static_cast<sal_Int16>( aRefDate.GetMonth() );
|
|
return nRet;
|
|
}
|
|
|
|
css::util::Date SbxDateToUNODate( const SbxValue* const pVal )
|
|
{
|
|
double aDate = pVal->GetDate();
|
|
|
|
css::util::Date aUnoDate;
|
|
aUnoDate.Day = implGetDateDay ( aDate );
|
|
aUnoDate.Month = implGetDateMonth( aDate );
|
|
aUnoDate.Year = implGetDateYear ( aDate );
|
|
|
|
return aUnoDate;
|
|
}
|
|
|
|
void SbxDateFromUNODate( SbxValue *pVal, const css::util::Date& aUnoDate)
|
|
{
|
|
double dDate;
|
|
if( implDateSerial( aUnoDate.Year, aUnoDate.Month, aUnoDate.Day, false, SbDateCorrection::None, dDate ) )
|
|
{
|
|
pVal->PutDate( dDate );
|
|
}
|
|
}
|
|
|
|
// Function to convert date to UNO date (com.sun.star.util.Date)
|
|
void SbRtl_CDateToUnoDate(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
unoToSbxValue(rPar.Get32(0), Any(SbxDateToUNODate(rPar.Get32(1))));
|
|
}
|
|
|
|
// Function to convert date from UNO date (com.sun.star.util.Date)
|
|
void SbRtl_CDateFromUnoDate(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 || rPar.Get32(1)->GetType() != SbxOBJECT )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
Any aAny (sbxToUnoValue(rPar.Get32(1), cppu::UnoType<css::util::Date>::get()));
|
|
css::util::Date aUnoDate;
|
|
if(aAny >>= aUnoDate)
|
|
SbxDateFromUNODate(rPar.Get32(0), aUnoDate);
|
|
else
|
|
SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
|
|
}
|
|
|
|
css::util::Time SbxDateToUNOTime( const SbxValue* const pVal )
|
|
{
|
|
double aDate = pVal->GetDate();
|
|
|
|
css::util::Time aUnoTime;
|
|
aUnoTime.Hours = implGetHour ( aDate );
|
|
aUnoTime.Minutes = implGetMinute ( aDate );
|
|
aUnoTime.Seconds = implGetSecond ( aDate );
|
|
aUnoTime.NanoSeconds = 0;
|
|
|
|
return aUnoTime;
|
|
}
|
|
|
|
void SbxDateFromUNOTime( SbxValue *pVal, const css::util::Time& aUnoTime)
|
|
{
|
|
pVal->PutDate( implTimeSerial(aUnoTime.Hours, aUnoTime.Minutes, aUnoTime.Seconds) );
|
|
}
|
|
|
|
// Function to convert date to UNO time (com.sun.star.util.Time)
|
|
void SbRtl_CDateToUnoTime(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
unoToSbxValue(rPar.Get32(0), Any(SbxDateToUNOTime(rPar.Get32(1))));
|
|
}
|
|
|
|
// Function to convert date from UNO time (com.sun.star.util.Time)
|
|
void SbRtl_CDateFromUnoTime(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 || rPar.Get32(1)->GetType() != SbxOBJECT )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
Any aAny (sbxToUnoValue(rPar.Get32(1), cppu::UnoType<css::util::Time>::get()));
|
|
css::util::Time aUnoTime;
|
|
if(aAny >>= aUnoTime)
|
|
SbxDateFromUNOTime(rPar.Get32(0), aUnoTime);
|
|
else
|
|
SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
|
|
}
|
|
|
|
css::util::DateTime SbxDateToUNODateTime( const SbxValue* const pVal )
|
|
{
|
|
double aDate = pVal->GetDate();
|
|
|
|
css::util::DateTime aUnoDT;
|
|
aUnoDT.Day = implGetDateDay ( aDate );
|
|
aUnoDT.Month = implGetDateMonth( aDate );
|
|
aUnoDT.Year = implGetDateYear ( aDate );
|
|
aUnoDT.Hours = implGetHour ( aDate );
|
|
aUnoDT.Minutes = implGetMinute ( aDate );
|
|
aUnoDT.Seconds = implGetSecond ( aDate );
|
|
aUnoDT.NanoSeconds = 0;
|
|
|
|
return aUnoDT;
|
|
}
|
|
|
|
void SbxDateFromUNODateTime( SbxValue *pVal, const css::util::DateTime& aUnoDT)
|
|
{
|
|
double dDate(0.0);
|
|
if( implDateTimeSerial( aUnoDT.Year, aUnoDT.Month, aUnoDT.Day,
|
|
aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds,
|
|
dDate ) )
|
|
{
|
|
pVal->PutDate( dDate );
|
|
}
|
|
}
|
|
|
|
// Function to convert date to UNO date (com.sun.star.util.Date)
|
|
void SbRtl_CDateToUnoDateTime(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
unoToSbxValue(rPar.Get32(0), Any(SbxDateToUNODateTime(rPar.Get32(1))));
|
|
}
|
|
|
|
// Function to convert date from UNO date (com.sun.star.util.Date)
|
|
void SbRtl_CDateFromUnoDateTime(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 || rPar.Get32(1)->GetType() != SbxOBJECT )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
Any aAny (sbxToUnoValue(rPar.Get32(1), cppu::UnoType<css::util::DateTime>::get()));
|
|
css::util::DateTime aUnoDT;
|
|
if(aAny >>= aUnoDT)
|
|
SbxDateFromUNODateTime(rPar.Get32(0), aUnoDT);
|
|
else
|
|
SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
|
|
}
|
|
|
|
// Function to convert date to ISO 8601 date format YYYYMMDD
|
|
void SbRtl_CDateToIso(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() == 2 )
|
|
{
|
|
double aDate = rPar.Get32(1)->GetDate();
|
|
|
|
// Date may actually even be -YYYYYMMDD
|
|
char Buffer[11];
|
|
sal_Int16 nYear = implGetDateYear( aDate );
|
|
snprintf( Buffer, sizeof( Buffer ), (nYear < 0 ? "%05d%02d%02d" : "%04d%02d%02d"),
|
|
static_cast<int>(nYear),
|
|
static_cast<int>(implGetDateMonth( aDate )),
|
|
static_cast<int>(implGetDateDay( aDate )) );
|
|
OUString aRetStr = OUString::createFromAscii( Buffer );
|
|
rPar.Get32(0)->PutString( aRetStr );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
// Function to convert date from ISO 8601 date format YYYYMMDD or YYYY-MM-DD
|
|
// And even YYMMDD for compatibility, sigh...
|
|
void SbRtl_CDateFromIso(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() == 2 )
|
|
{
|
|
do
|
|
{
|
|
OUString aStr = rPar.Get32(1)->GetOUString();
|
|
if (aStr.isEmpty())
|
|
break;
|
|
|
|
// Valid formats are
|
|
// YYYYMMDD -YYYMMDD YYYYYMMDD -YYYYYMMDD YYMMDD
|
|
// YYYY-MM-DD -YYYY-MM-DD YYYYY-MM-DD -YYYYY-MM-DD
|
|
|
|
sal_Int32 nSign = 1;
|
|
if (aStr[0] == '-')
|
|
{
|
|
nSign = -1;
|
|
aStr = aStr.copy(1);
|
|
}
|
|
const sal_Int32 nLen = aStr.getLength();
|
|
|
|
// Signed YYMMDD two digit year is invalid.
|
|
if (nLen == 6 && nSign == -1)
|
|
break;
|
|
|
|
// Now valid
|
|
// YYYYMMDD YYYYYMMDD YYMMDD
|
|
// YYYY-MM-DD YYYYY-MM-DD
|
|
if (nLen != 6 && (nLen < 8 || 11 < nLen))
|
|
break;
|
|
|
|
bool bUseTwoDigitYear = false;
|
|
OUString aYearStr, aMonthStr, aDayStr;
|
|
if (nLen == 6 || nLen == 8 || nLen == 9)
|
|
{
|
|
// ((Y)YY)YYMMDD
|
|
if (!comphelper::string::isdigitAsciiString(aStr))
|
|
break;
|
|
|
|
const sal_Int32 nMonthPos = (nLen == 8 ? 4 : (nLen == 6 ? 2 : 5));
|
|
if (nMonthPos == 2)
|
|
bUseTwoDigitYear = true;
|
|
aYearStr = aStr.copy( 0, nMonthPos );
|
|
aMonthStr = aStr.copy( nMonthPos, 2 );
|
|
aDayStr = aStr.copy( nMonthPos + 2, 2 );
|
|
}
|
|
else
|
|
{
|
|
// (Y)YYYY-MM-DD
|
|
const sal_Int32 nMonthSep = (nLen == 11 ? 5 : 4);
|
|
if (aStr.indexOf('-') != nMonthSep)
|
|
break;
|
|
if (aStr.indexOf('-', nMonthSep + 1) != nMonthSep + 3)
|
|
break;
|
|
|
|
aYearStr = aStr.copy( 0, nMonthSep );
|
|
aMonthStr = aStr.copy( nMonthSep + 1, 2 );
|
|
aDayStr = aStr.copy( nMonthSep + 4, 2 );
|
|
if ( !comphelper::string::isdigitAsciiString(aYearStr) ||
|
|
!comphelper::string::isdigitAsciiString(aMonthStr) ||
|
|
!comphelper::string::isdigitAsciiString(aDayStr))
|
|
break;
|
|
}
|
|
|
|
double dDate;
|
|
if (!implDateSerial( static_cast<sal_Int16>(nSign * aYearStr.toInt32()),
|
|
static_cast<sal_Int16>(aMonthStr.toInt32()), static_cast<sal_Int16>(aDayStr.toInt32()),
|
|
bUseTwoDigitYear, SbDateCorrection::None, dDate ))
|
|
break;
|
|
|
|
rPar.Get32(0)->PutDate( dDate );
|
|
|
|
return;
|
|
}
|
|
while (false);
|
|
|
|
SbxBase::SetError( ERRCODE_BASIC_BAD_PARAMETER );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DateSerial(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 4 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
sal_Int16 nYear = rPar.Get32(1)->GetInteger();
|
|
sal_Int16 nMonth = rPar.Get32(2)->GetInteger();
|
|
sal_Int16 nDay = rPar.Get32(3)->GetInteger();
|
|
|
|
double dDate;
|
|
if( implDateSerial( nYear, nMonth, nDay, true, SbDateCorrection::RollOver, dDate ) )
|
|
{
|
|
rPar.Get32(0)->PutDate( dDate );
|
|
}
|
|
}
|
|
|
|
void SbRtl_TimeSerial(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 4 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
sal_Int16 nHour = rPar.Get32(1)->GetInteger();
|
|
if ( nHour == 24 )
|
|
{
|
|
nHour = 0; // because of UNO DateTimes, which go till 24 o'clock
|
|
}
|
|
sal_Int16 nMinute = rPar.Get32(2)->GetInteger();
|
|
sal_Int16 nSecond = rPar.Get32(3)->GetInteger();
|
|
if ((nHour < 0 || nHour > 23) ||
|
|
(nMinute < 0 || nMinute > 59 ) ||
|
|
(nSecond < 0 || nSecond > 59 ))
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
rPar.Get32(0)->PutDate( implTimeSerial(nHour, nMinute, nSecond) ); // JSM
|
|
}
|
|
|
|
void SbRtl_DateValue(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
// #39629 check GetSbData()->pInst, can be called from the URL line
|
|
std::shared_ptr<SvNumberFormatter> pFormatter;
|
|
if( GetSbData()->pInst )
|
|
{
|
|
pFormatter = GetSbData()->pInst->GetNumberFormatter();
|
|
}
|
|
else
|
|
{
|
|
sal_uInt32 n; // Dummy
|
|
pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
|
|
}
|
|
|
|
LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
|
|
sal_uInt32 nIndex = pFormatter->GetStandardIndex( eLangType);
|
|
double fResult;
|
|
OUString aStr( rPar.Get32(1)->GetOUString() );
|
|
bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult );
|
|
SvNumFormatType nType = pFormatter->GetType( nIndex );
|
|
|
|
// DateValue("February 12, 1969") raises error if the system locale is not en_US
|
|
// It seems that both locale number formatter and English number
|
|
// formatter are supported in Visual Basic.
|
|
if( !bSuccess && ( eLangType != LANGUAGE_ENGLISH_US ) )
|
|
{
|
|
// Try using LANGUAGE_ENGLISH_US to get the date value.
|
|
nIndex = pFormatter->GetStandardIndex( LANGUAGE_ENGLISH_US);
|
|
bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, fResult );
|
|
nType = pFormatter->GetType( nIndex );
|
|
}
|
|
|
|
if(bSuccess && (nType==SvNumFormatType::DATE || nType==SvNumFormatType::DATETIME))
|
|
{
|
|
if ( nType == SvNumFormatType::DATETIME )
|
|
{
|
|
// cut time
|
|
if ( fResult > 0.0 )
|
|
{
|
|
fResult = floor( fResult );
|
|
}
|
|
else
|
|
{
|
|
fResult = ceil( fResult );
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutDate( fResult );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_CONVERSION );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_TimeValue(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
std::shared_ptr<SvNumberFormatter> pFormatter;
|
|
if( GetSbData()->pInst )
|
|
pFormatter = GetSbData()->pInst->GetNumberFormatter();
|
|
else
|
|
{
|
|
sal_uInt32 n;
|
|
pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
|
|
}
|
|
|
|
sal_uInt32 nIndex = 0;
|
|
double fResult;
|
|
bool bSuccess = pFormatter->IsNumberFormat( rPar.Get32(1)->GetOUString(),
|
|
nIndex, fResult );
|
|
SvNumFormatType nType = pFormatter->GetType(nIndex);
|
|
if(bSuccess && (nType==SvNumFormatType::TIME||nType==SvNumFormatType::DATETIME))
|
|
{
|
|
if ( nType == SvNumFormatType::DATETIME )
|
|
{
|
|
// cut days
|
|
fResult = fmod( fResult, 1 );
|
|
}
|
|
rPar.Get32(0)->PutDate( fResult );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_CONVERSION );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_Day(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
double aDate = pArg->GetDate();
|
|
|
|
sal_Int16 nDay = implGetDateDay( aDate );
|
|
rPar.Get32(0)->PutInteger( nDay );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Year(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Int16 nYear = implGetDateYear( rPar.Get32(1)->GetDate() );
|
|
rPar.Get32(0)->PutInteger( nYear );
|
|
}
|
|
}
|
|
|
|
sal_Int16 implGetHour( double dDate )
|
|
{
|
|
double nFrac = dDate - floor( dDate );
|
|
nFrac *= 86400.0;
|
|
sal_Int32 nSeconds = static_cast<sal_Int32>(nFrac + 0.5);
|
|
sal_Int16 nHour = static_cast<sal_Int16>(nSeconds / 3600);
|
|
return nHour;
|
|
}
|
|
|
|
void SbRtl_Hour(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double nArg = rPar.Get32(1)->GetDate();
|
|
sal_Int16 nHour = implGetHour( nArg );
|
|
rPar.Get32(0)->PutInteger( nHour );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Minute(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double nArg = rPar.Get32(1)->GetDate();
|
|
sal_Int16 nMin = implGetMinute( nArg );
|
|
rPar.Get32(0)->PutInteger( nMin );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Month(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Int16 nMonth = implGetDateMonth( rPar.Get32(1)->GetDate() );
|
|
rPar.Get32(0)->PutInteger( nMonth );
|
|
}
|
|
}
|
|
|
|
sal_Int16 implGetSecond( double dDate )
|
|
{
|
|
double nFrac = dDate - floor( dDate );
|
|
nFrac *= 86400.0;
|
|
sal_Int32 nSeconds = static_cast<sal_Int32>(nFrac + 0.5);
|
|
sal_Int16 nTemp = static_cast<sal_Int16>(nSeconds / 3600);
|
|
nSeconds -= nTemp * 3600;
|
|
nTemp = static_cast<sal_Int16>(nSeconds / 60);
|
|
nSeconds -= nTemp * 60;
|
|
|
|
sal_Int16 nRet = static_cast<sal_Int16>(nSeconds);
|
|
return nRet;
|
|
}
|
|
|
|
void SbRtl_Second(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
double nArg = rPar.Get32(1)->GetDate();
|
|
sal_Int16 nSecond = implGetSecond( nArg );
|
|
rPar.Get32(0)->PutInteger( nSecond );
|
|
}
|
|
}
|
|
|
|
double Now_Impl()
|
|
{
|
|
DateTime aDateTime( DateTime::SYSTEM );
|
|
double aSerial = static_cast<double>(GetDayDiff( aDateTime ));
|
|
long nSeconds = aDateTime.GetHour();
|
|
nSeconds *= 3600;
|
|
nSeconds += aDateTime.GetMin() * 60;
|
|
nSeconds += aDateTime.GetSec();
|
|
double nDays = static_cast<double>(nSeconds) / (24.0*3600.0);
|
|
aSerial += nDays;
|
|
return aSerial;
|
|
}
|
|
|
|
// Date Now()
|
|
|
|
void SbRtl_Now(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutDate( Now_Impl() );
|
|
}
|
|
|
|
// Date Time()
|
|
|
|
void SbRtl_Time(StarBASIC *, SbxArray & rPar, bool bWrite)
|
|
{
|
|
if ( !bWrite )
|
|
{
|
|
tools::Time aTime( tools::Time::SYSTEM );
|
|
SbxVariable* pMeth = rPar.Get32(0);
|
|
OUString aRes;
|
|
if( pMeth->IsFixed() )
|
|
{
|
|
// Time$: hh:mm:ss
|
|
char buf[ 20 ];
|
|
snprintf( buf, sizeof(buf), "%02d:%02d:%02d",
|
|
aTime.GetHour(), aTime.GetMin(), aTime.GetSec() );
|
|
aRes = OUString::createFromAscii( buf );
|
|
}
|
|
else
|
|
{
|
|
// Time: system dependent
|
|
long nSeconds=aTime.GetHour();
|
|
nSeconds *= 3600;
|
|
nSeconds += aTime.GetMin() * 60;
|
|
nSeconds += aTime.GetSec();
|
|
double nDays = static_cast<double>(nSeconds) * ( 1.0 / (24.0*3600.0) );
|
|
Color* pCol;
|
|
|
|
std::shared_ptr<SvNumberFormatter> pFormatter;
|
|
sal_uInt32 nIndex;
|
|
if( GetSbData()->pInst )
|
|
{
|
|
pFormatter = GetSbData()->pInst->GetNumberFormatter();
|
|
nIndex = GetSbData()->pInst->GetStdTimeIdx();
|
|
}
|
|
else
|
|
{
|
|
sal_uInt32 n; // Dummy
|
|
pFormatter = SbiInstance::PrepareNumberFormatter( n, nIndex, n );
|
|
}
|
|
|
|
pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
|
|
}
|
|
pMeth->PutString( aRes );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_NOT_IMPLEMENTED );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Timer(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
tools::Time aTime( tools::Time::SYSTEM );
|
|
long nSeconds = aTime.GetHour();
|
|
nSeconds *= 3600;
|
|
nSeconds += aTime.GetMin() * 60;
|
|
nSeconds += aTime.GetSec();
|
|
rPar.Get32(0)->PutDate( static_cast<double>(nSeconds) );
|
|
}
|
|
|
|
|
|
void SbRtl_Date(StarBASIC *, SbxArray & rPar, bool bWrite)
|
|
{
|
|
if ( !bWrite )
|
|
{
|
|
Date aToday( Date::SYSTEM );
|
|
double nDays = static_cast<double>(GetDayDiff( aToday ));
|
|
SbxVariable* pMeth = rPar.Get32(0);
|
|
if( pMeth->IsString() )
|
|
{
|
|
OUString aRes;
|
|
Color* pCol;
|
|
|
|
std::shared_ptr<SvNumberFormatter> pFormatter;
|
|
sal_uInt32 nIndex;
|
|
if( GetSbData()->pInst )
|
|
{
|
|
pFormatter = GetSbData()->pInst->GetNumberFormatter();
|
|
nIndex = GetSbData()->pInst->GetStdDateIdx();
|
|
}
|
|
else
|
|
{
|
|
sal_uInt32 n;
|
|
pFormatter = SbiInstance::PrepareNumberFormatter( nIndex, n, n );
|
|
}
|
|
|
|
pFormatter->GetOutputString( nDays, nIndex, aRes, &pCol );
|
|
pMeth->PutString( aRes );
|
|
}
|
|
else
|
|
{
|
|
pMeth->PutDate( nDays );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_NOT_IMPLEMENTED );
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsArray(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutBool((rPar.Get32(1)->GetType() & SbxARRAY) != 0);
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsObject(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariable* pVar = rPar.Get32(1);
|
|
bool bObject = pVar->IsObject();
|
|
SbxBase* pObj = (bObject ? pVar->GetObject() : nullptr);
|
|
|
|
if( auto pUnoClass = dynamic_cast<SbUnoClass*>( pObj) )
|
|
{
|
|
bObject = pUnoClass->getUnoClass().is();
|
|
}
|
|
rPar.Get32(0)->PutBool( bObject );
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsDate(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
// #46134 only string is converted, all other types result in sal_False
|
|
SbxVariableRef xArg = rPar.Get32(1);
|
|
SbxDataType eType = xArg->GetType();
|
|
bool bDate = false;
|
|
|
|
if( eType == SbxDATE )
|
|
{
|
|
bDate = true;
|
|
}
|
|
else if( eType == SbxSTRING )
|
|
{
|
|
ErrCode nPrevError = SbxBase::GetError();
|
|
SbxBase::ResetError();
|
|
|
|
// force conversion of the parameter to SbxDATE
|
|
xArg->SbxValue::GetDate();
|
|
|
|
bDate = !SbxBase::IsError();
|
|
|
|
SbxBase::ResetError();
|
|
SbxBase::SetError( nPrevError );
|
|
}
|
|
rPar.Get32(0)->PutBool( bDate );
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsEmpty(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariable* pVar = nullptr;
|
|
if( SbiRuntime::isVBAEnabled() )
|
|
{
|
|
pVar = getDefaultProp( rPar.Get32(1) );
|
|
}
|
|
if ( pVar )
|
|
{
|
|
pVar->Broadcast( SfxHintId::BasicDataWanted );
|
|
rPar.Get32(0)->PutBool( pVar->IsEmpty() );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutBool( rPar.Get32(1)->IsEmpty() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsError(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxVariable* pVar =rPar.Get32(1);
|
|
SbUnoObject* pObj = dynamic_cast<SbUnoObject*>( pVar );
|
|
if ( !pObj )
|
|
{
|
|
if ( SbxBase* pBaseObj = (pVar->IsObject() ? pVar->GetObject() : nullptr) )
|
|
{
|
|
pObj = dynamic_cast<SbUnoObject*>( pBaseObj );
|
|
}
|
|
}
|
|
uno::Reference< script::XErrorQuery > xError;
|
|
if ( pObj )
|
|
{
|
|
xError.set( pObj->getUnoAny(), uno::UNO_QUERY );
|
|
}
|
|
if ( xError.is() )
|
|
{
|
|
rPar.Get32(0)->PutBool( xError->hasError() );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutBool( rPar.Get32(1)->IsErr() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsNull(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
// #51475 because of Uno-objects return true
|
|
// even if the pObj value is NULL
|
|
SbxVariableRef pArg = rPar.Get32(1);
|
|
bool bNull = rPar.Get32(1)->IsNull();
|
|
if( !bNull && pArg->GetType() == SbxOBJECT )
|
|
{
|
|
SbxBase* pObj = pArg->GetObject();
|
|
if( !pObj )
|
|
{
|
|
bNull = true;
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutBool( bNull );
|
|
}
|
|
}
|
|
|
|
void SbRtl_IsNumeric(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutBool( rPar.Get32(1)->IsNumericRTL() );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_IsMissing(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
// #57915 Missing is reported by an error
|
|
rPar.Get32(0)->PutBool( rPar.Get32(1)->IsErr() );
|
|
}
|
|
}
|
|
|
|
// Function looks for wildcards, removes them and always returns the pure path
|
|
static OUString implSetupWildcard(const OUString& rFileParam, SbiRTLData& rRTLData)
|
|
{
|
|
static const char cDelim1 = '/';
|
|
static const char cDelim2 = '\\';
|
|
static const char cWild1 = '*';
|
|
static const char cWild2 = '?';
|
|
|
|
rRTLData.pWildCard.reset();
|
|
rRTLData.sFullNameToBeChecked.clear();
|
|
|
|
OUString aFileParam = rFileParam;
|
|
sal_Int32 nLastWild = aFileParam.lastIndexOf( cWild1 );
|
|
if( nLastWild < 0 )
|
|
{
|
|
nLastWild = aFileParam.lastIndexOf( cWild2 );
|
|
}
|
|
bool bHasWildcards = ( nLastWild >= 0 );
|
|
|
|
|
|
sal_Int32 nLastDelim = aFileParam.lastIndexOf( cDelim1 );
|
|
if( nLastDelim < 0 )
|
|
{
|
|
nLastDelim = aFileParam.lastIndexOf( cDelim2 );
|
|
}
|
|
if( bHasWildcards )
|
|
{
|
|
// Wildcards in path?
|
|
if( nLastDelim >= 0 && nLastDelim > nLastWild )
|
|
{
|
|
return aFileParam;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OUString aPathStr = getFullPath( aFileParam );
|
|
if( nLastDelim != aFileParam.getLength() - 1 )
|
|
{
|
|
rRTLData.sFullNameToBeChecked = aPathStr;
|
|
}
|
|
return aPathStr;
|
|
}
|
|
|
|
OUString aPureFileName;
|
|
if( nLastDelim < 0 )
|
|
{
|
|
aPureFileName = aFileParam;
|
|
aFileParam.clear();
|
|
}
|
|
else
|
|
{
|
|
aPureFileName = aFileParam.copy( nLastDelim + 1 );
|
|
aFileParam = aFileParam.copy( 0, nLastDelim );
|
|
}
|
|
|
|
// Try again to get a valid URL/UNC-path with only the path
|
|
OUString aPathStr = getFullPath( aFileParam );
|
|
|
|
// Is there a pure file name left? Otherwise the path is
|
|
// invalid anyway because it was not accepted by OSL before
|
|
if (aPureFileName != "*")
|
|
{
|
|
rRTLData.pWildCard = std::make_unique<WildCard>(aPureFileName);
|
|
}
|
|
return aPathStr;
|
|
}
|
|
|
|
static bool implCheckWildcard(const OUString& rName, SbiRTLData const& rRTLData)
|
|
{
|
|
bool bMatch = true;
|
|
|
|
if (rRTLData.pWildCard)
|
|
{
|
|
bMatch = rRTLData.pWildCard->Matches(rName);
|
|
}
|
|
return bMatch;
|
|
}
|
|
|
|
|
|
static bool isRootDir( const OUString& aDirURLStr )
|
|
{
|
|
INetURLObject aDirURLObj( aDirURLStr );
|
|
bool bRoot = false;
|
|
|
|
// Check if it's a root directory
|
|
sal_Int32 nCount = aDirURLObj.getSegmentCount();
|
|
|
|
// No segment means Unix root directory "file:///"
|
|
if( nCount == 0 )
|
|
{
|
|
bRoot = true;
|
|
}
|
|
// Exactly one segment needs further checking, because it
|
|
// can be Unix "file:///foo/" -> no root
|
|
// or Windows "file:///c:/" -> root
|
|
else if( nCount == 1 )
|
|
{
|
|
OUString aSeg1 = aDirURLObj.getName( 0, true,
|
|
INetURLObject::DecodeMechanism::WithCharset );
|
|
if( aSeg1[1] == ':' )
|
|
{
|
|
bRoot = true;
|
|
}
|
|
}
|
|
// More than one segments can never be root
|
|
// so bRoot remains false
|
|
|
|
return bRoot;
|
|
}
|
|
|
|
void SbRtl_Dir(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
OUString aPath;
|
|
|
|
const sal_uInt32 nParCount = rPar.Count32();
|
|
if( nParCount > 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbiRTLData& rRTLData = GetSbData()->pInst->GetRTLData();
|
|
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
if ( nParCount >= 2 )
|
|
{
|
|
OUString aFileParam = rPar.Get32(1)->GetOUString();
|
|
|
|
OUString aFileURLStr = implSetupWildcard(aFileParam, rRTLData);
|
|
if (!rRTLData.sFullNameToBeChecked.isEmpty())
|
|
{
|
|
bool bExists = false;
|
|
try { bExists = xSFI->exists( aFileURLStr ); }
|
|
catch(const Exception & ) {}
|
|
|
|
OUString aNameOnlyStr;
|
|
if( bExists )
|
|
{
|
|
INetURLObject aFileURL( aFileURLStr );
|
|
aNameOnlyStr = aFileURL.getName( INetURLObject::LAST_SEGMENT,
|
|
true, INetURLObject::DecodeMechanism::WithCharset );
|
|
}
|
|
rPar.Get32(0)->PutString( aNameOnlyStr );
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
OUString aDirURLStr;
|
|
bool bFolder = xSFI->isFolder( aFileURLStr );
|
|
|
|
if( bFolder )
|
|
{
|
|
aDirURLStr = aFileURLStr;
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutString( "" );
|
|
}
|
|
|
|
SbAttributes nFlags = SbAttributes::NONE;
|
|
if ( nParCount > 2 )
|
|
{
|
|
rRTLData.nDirFlags = nFlags
|
|
= static_cast<SbAttributes>(rPar.Get32(2)->GetInteger());
|
|
}
|
|
else
|
|
{
|
|
rRTLData.nDirFlags = SbAttributes::NONE;
|
|
}
|
|
// Read directory
|
|
bool bIncludeFolders = bool(nFlags & SbAttributes::DIRECTORY);
|
|
rRTLData.aDirSeq = xSFI->getFolderContents(aDirURLStr, bIncludeFolders);
|
|
rRTLData.nCurDirPos = 0;
|
|
|
|
// #78651 Add "." and ".." directories for VB compatibility
|
|
if( bIncludeFolders )
|
|
{
|
|
bool bRoot = isRootDir( aDirURLStr );
|
|
|
|
// If it's no root directory we flag the need for
|
|
// the "." and ".." directories by the value -2
|
|
// for the actual position. Later for -2 will be
|
|
// returned "." and for -1 ".."
|
|
if( !bRoot )
|
|
{
|
|
rRTLData.nCurDirPos = -2;
|
|
}
|
|
}
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
if (rRTLData.aDirSeq.hasElements())
|
|
{
|
|
bool bFolderFlag = bool(rRTLData.nDirFlags & SbAttributes::DIRECTORY);
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
for( ;; )
|
|
{
|
|
if (rRTLData.nCurDirPos < 0)
|
|
{
|
|
if (rRTLData.nCurDirPos == -2)
|
|
{
|
|
aPath = ".";
|
|
}
|
|
else if (rRTLData.nCurDirPos == -1)
|
|
{
|
|
aPath = "..";
|
|
}
|
|
rRTLData.nCurDirPos++;
|
|
}
|
|
else if (rRTLData.nCurDirPos >= rRTLData.aDirSeq.getLength())
|
|
{
|
|
rRTLData.aDirSeq.realloc(0);
|
|
aPath.clear();
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
OUString aFile
|
|
= rRTLData.aDirSeq.getConstArray()[rRTLData.nCurDirPos++];
|
|
|
|
if( bCompatibility )
|
|
{
|
|
if( !bFolderFlag )
|
|
{
|
|
bool bFolder = xSFI->isFolder( aFile );
|
|
if( bFolder )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Only directories
|
|
if( bFolderFlag )
|
|
{
|
|
bool bFolder = xSFI->isFolder( aFile );
|
|
if( !bFolder )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
INetURLObject aURL( aFile );
|
|
aPath = aURL.getName( INetURLObject::LAST_SEGMENT, true,
|
|
INetURLObject::DecodeMechanism::WithCharset );
|
|
}
|
|
|
|
bool bMatch = implCheckWildcard(aPath, rRTLData);
|
|
if( !bMatch )
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutString( aPath );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: OSL
|
|
if ( nParCount >= 2 )
|
|
{
|
|
OUString aFileParam = rPar.Get32(1)->GetOUString();
|
|
|
|
OUString aDirURL = implSetupWildcard(aFileParam, rRTLData);
|
|
|
|
SbAttributes nFlags = SbAttributes::NONE;
|
|
if ( nParCount > 2 )
|
|
{
|
|
rRTLData.nDirFlags = nFlags
|
|
= static_cast<SbAttributes>(rPar.Get32(2)->GetInteger());
|
|
}
|
|
else
|
|
{
|
|
rRTLData.nDirFlags = SbAttributes::NONE;
|
|
}
|
|
|
|
// Read directory
|
|
bool bIncludeFolders = bool(nFlags & SbAttributes::DIRECTORY);
|
|
rRTLData.pDir = std::make_unique<Directory>(aDirURL);
|
|
FileBase::RC nRet = rRTLData.pDir->open();
|
|
if( nRet != FileBase::E_None )
|
|
{
|
|
rRTLData.pDir.reset();
|
|
rPar.Get32(0)->PutString( OUString() );
|
|
return;
|
|
}
|
|
|
|
// #86950 Add "." and ".." directories for VB compatibility
|
|
rRTLData.nCurDirPos = 0;
|
|
if( bIncludeFolders )
|
|
{
|
|
bool bRoot = isRootDir( aDirURL );
|
|
|
|
// If it's no root directory we flag the need for
|
|
// the "." and ".." directories by the value -2
|
|
// for the actual position. Later for -2 will be
|
|
// returned "." and for -1 ".."
|
|
if( !bRoot )
|
|
{
|
|
rRTLData.nCurDirPos = -2;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (rRTLData.pDir)
|
|
{
|
|
bool bFolderFlag = bool(rRTLData.nDirFlags & SbAttributes::DIRECTORY);
|
|
for( ;; )
|
|
{
|
|
if (rRTLData.nCurDirPos < 0)
|
|
{
|
|
if (rRTLData.nCurDirPos == -2)
|
|
{
|
|
aPath = ".";
|
|
}
|
|
else if (rRTLData.nCurDirPos == -1)
|
|
{
|
|
aPath = "..";
|
|
}
|
|
rRTLData.nCurDirPos++;
|
|
}
|
|
else
|
|
{
|
|
DirectoryItem aItem;
|
|
FileBase::RC nRet = rRTLData.pDir->getNextItem(aItem);
|
|
if( nRet != FileBase::E_None )
|
|
{
|
|
rRTLData.pDir.reset();
|
|
aPath.clear();
|
|
break;
|
|
}
|
|
|
|
// Handle flags
|
|
FileStatus aFileStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName );
|
|
nRet = aItem.getFileStatus( aFileStatus );
|
|
if( nRet != FileBase::E_None )
|
|
{
|
|
SAL_WARN("basic", "getFileStatus failed");
|
|
continue;
|
|
}
|
|
|
|
// Only directories?
|
|
if( bFolderFlag )
|
|
{
|
|
FileStatus::Type aType = aFileStatus.getFileType();
|
|
bool bFolder = isFolder( aType );
|
|
if( !bFolder )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
aPath = aFileStatus.getFileName();
|
|
}
|
|
|
|
bool bMatch = implCheckWildcard(aPath, rRTLData);
|
|
if( !bMatch )
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutString( aPath );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_GetAttr(StarBASIC * pBasic, SbxArray & rPar, bool bWrite)
|
|
{
|
|
(void)pBasic;
|
|
(void)bWrite;
|
|
|
|
if ( rPar.Count32() == 2 )
|
|
{
|
|
sal_Int16 nFlags = 0;
|
|
|
|
// In Windows, we want to use Windows API to get the file attributes
|
|
// for VBA interoperability.
|
|
#if defined(_WIN32)
|
|
if( SbiRuntime::isVBAEnabled() )
|
|
{
|
|
OUString aPathURL = getFullPath( rPar.Get32(1)->GetOUString() );
|
|
OUString aPath;
|
|
FileBase::getSystemPathFromFileURL( aPathURL, aPath );
|
|
DWORD nRealFlags = GetFileAttributesW (o3tl::toW(aPath.getStr()));
|
|
if (nRealFlags != 0xffffffff)
|
|
{
|
|
if (nRealFlags == FILE_ATTRIBUTE_NORMAL)
|
|
{
|
|
nRealFlags = 0;
|
|
}
|
|
nFlags = static_cast<sal_Int16>(nRealFlags);
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND );
|
|
}
|
|
rPar.Get32(0)->PutInteger( nFlags );
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
OUString aPath = getFullPath( rPar.Get32(1)->GetOUString() );
|
|
bool bExists = false;
|
|
try { bExists = xSFI->exists( aPath ); }
|
|
catch(const Exception & ) {}
|
|
if( !bExists )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND );
|
|
return;
|
|
}
|
|
|
|
bool bReadOnly = xSFI->isReadOnly( aPath );
|
|
bool bHidden = xSFI->isHidden( aPath );
|
|
bool bDirectory = xSFI->isFolder( aPath );
|
|
if( bReadOnly )
|
|
{
|
|
nFlags |= sal_uInt16(SbAttributes::READONLY);
|
|
}
|
|
if( bHidden )
|
|
{
|
|
nFlags |= sal_uInt16(SbAttributes::HIDDEN);
|
|
}
|
|
if( bDirectory )
|
|
{
|
|
nFlags |= sal_uInt16(SbAttributes::DIRECTORY);
|
|
}
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DirectoryItem aItem;
|
|
(void)DirectoryItem::get( getFullPath( rPar.Get32(1)->GetOUString() ), aItem );
|
|
FileStatus aFileStatus( osl_FileStatus_Mask_Attributes | osl_FileStatus_Mask_Type );
|
|
(void)aItem.getFileStatus( aFileStatus );
|
|
sal_uInt64 nAttributes = aFileStatus.getAttributes();
|
|
bool bReadOnly = (nAttributes & osl_File_Attribute_ReadOnly) != 0;
|
|
|
|
FileStatus::Type aType = aFileStatus.getFileType();
|
|
bool bDirectory = isFolder( aType );
|
|
if( bReadOnly )
|
|
{
|
|
nFlags |= sal_uInt16(SbAttributes::READONLY);
|
|
}
|
|
if( bDirectory )
|
|
{
|
|
nFlags |= sal_uInt16(SbAttributes::DIRECTORY);
|
|
}
|
|
}
|
|
rPar.Get32(0)->PutInteger( nFlags );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_FileDateTime(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aPath = rPar.Get32(1)->GetOUString();
|
|
tools::Time aTime( tools::Time::EMPTY );
|
|
Date aDate( Date::EMPTY );
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
util::DateTime aUnoDT = xSFI->getDateTimeModified( aPath );
|
|
aTime = tools::Time( aUnoDT );
|
|
aDate = Date( aUnoDT );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bSuccess = false;
|
|
do
|
|
{
|
|
DirectoryItem aItem;
|
|
if (DirectoryItem::get( getFullPath( aPath ), aItem ) != FileBase::E_None)
|
|
break;
|
|
|
|
FileStatus aFileStatus( osl_FileStatus_Mask_ModifyTime );
|
|
if (aItem.getFileStatus( aFileStatus ) != FileBase::E_None)
|
|
break;
|
|
|
|
TimeValue aTimeVal = aFileStatus.getModifyTime();
|
|
oslDateTime aDT;
|
|
if (!osl_getDateTimeFromTimeValue( &aTimeVal, &aDT ))
|
|
// Strictly spoken this is not an i/o error but some other failure.
|
|
break;
|
|
|
|
aTime = tools::Time( aDT.Hours, aDT.Minutes, aDT.Seconds, aDT.NanoSeconds );
|
|
aDate = Date( aDT.Day, aDT.Month, aDT.Year );
|
|
bSuccess = true;
|
|
}
|
|
while(false);
|
|
|
|
if (!bSuccess)
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
|
|
// An empty date shall not result in a formatted null-date (1899-12-30
|
|
// or 1900-01-01) or even worse -0001-12-03 or some such due to how
|
|
// GetDayDiff() treats things. There should be an error set in this
|
|
// case anyway because of a missing file or other error above, but... so
|
|
// do not even bother to use the number formatter.
|
|
OUString aRes;
|
|
if (aDate.IsEmpty())
|
|
{
|
|
aRes = "0000-00-00 00:00:00";
|
|
}
|
|
else
|
|
{
|
|
double fSerial = static_cast<double>(GetDayDiff( aDate ));
|
|
long nSeconds = aTime.GetHour();
|
|
nSeconds *= 3600;
|
|
nSeconds += aTime.GetMin() * 60;
|
|
nSeconds += aTime.GetSec();
|
|
double nDays = static_cast<double>(nSeconds) / (24.0*3600.0);
|
|
fSerial += nDays;
|
|
|
|
Color* pCol;
|
|
|
|
std::shared_ptr<SvNumberFormatter> pFormatter;
|
|
sal_uInt32 nIndex;
|
|
if( GetSbData()->pInst )
|
|
{
|
|
pFormatter = GetSbData()->pInst->GetNumberFormatter();
|
|
nIndex = GetSbData()->pInst->GetStdDateTimeIdx();
|
|
}
|
|
else
|
|
{
|
|
sal_uInt32 n;
|
|
pFormatter = SbiInstance::PrepareNumberFormatter( n, n, nIndex );
|
|
}
|
|
|
|
pFormatter->GetOutputString( fSerial, nIndex, aRes, &pCol );
|
|
}
|
|
rPar.Get32(0)->PutString( aRes );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_EOF(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
// No changes for UCB
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Int16 nChannel = rPar.Get32(1)->GetInteger();
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
SbiStream* pSbStrm = pIO->GetStream( nChannel );
|
|
if ( !pSbStrm )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
|
|
return;
|
|
}
|
|
bool beof;
|
|
SvStream* pSvStrm = pSbStrm->GetStrm();
|
|
if ( pSbStrm->IsText() )
|
|
{
|
|
char cBla;
|
|
(*pSvStrm).ReadChar( cBla ); // can we read another character?
|
|
beof = pSvStrm->eof();
|
|
if ( !beof )
|
|
{
|
|
pSvStrm->SeekRel( -1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
beof = pSvStrm->eof(); // for binary data!
|
|
}
|
|
rPar.Get32(0)->PutBool( beof );
|
|
}
|
|
}
|
|
|
|
void SbRtl_FileAttr(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
// No changes for UCB
|
|
// #57064 Although this function doesn't operate with DirEntry, it is
|
|
// not touched by the adjustment to virtual URLs, as it only works on
|
|
// already opened files and the name doesn't matter there.
|
|
|
|
if ( rPar.Count32() != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Int16 nChannel = rPar.Get32(1)->GetInteger();
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
SbiStream* pSbStrm = pIO->GetStream( nChannel );
|
|
if ( !pSbStrm )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
|
|
return;
|
|
}
|
|
sal_Int16 nRet;
|
|
if ( rPar.Get32(2)->GetInteger() == 1 )
|
|
{
|
|
nRet = static_cast<sal_Int16>(pSbStrm->GetMode());
|
|
}
|
|
else
|
|
{
|
|
nRet = 0; // System file handle not supported
|
|
}
|
|
rPar.Get32(0)->PutInteger( nRet );
|
|
}
|
|
}
|
|
void SbRtl_Loc(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
// No changes for UCB
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Int16 nChannel = rPar.Get32(1)->GetInteger();
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
SbiStream* pSbStrm = pIO->GetStream( nChannel );
|
|
if ( !pSbStrm )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
|
|
return;
|
|
}
|
|
SvStream* pSvStrm = pSbStrm->GetStrm();
|
|
std::size_t nPos;
|
|
if( pSbStrm->IsRandom())
|
|
{
|
|
short nBlockLen = pSbStrm->GetBlockLen();
|
|
nPos = nBlockLen ? (pSvStrm->Tell() / nBlockLen) : 0;
|
|
nPos++; // block positions starting at 1
|
|
}
|
|
else if ( pSbStrm->IsText() )
|
|
{
|
|
nPos = pSbStrm->GetLine();
|
|
}
|
|
else if( pSbStrm->IsBinary() )
|
|
{
|
|
nPos = pSvStrm->Tell();
|
|
}
|
|
else if ( pSbStrm->IsSeq() )
|
|
{
|
|
nPos = ( pSvStrm->Tell()+1 ) / 128;
|
|
}
|
|
else
|
|
{
|
|
nPos = pSvStrm->Tell();
|
|
}
|
|
rPar.Get32(0)->PutLong( static_cast<sal_Int32>(nPos) );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Lof(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
// No changes for UCB
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
sal_Int16 nChannel = rPar.Get32(1)->GetInteger();
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
SbiStream* pSbStrm = pIO->GetStream( nChannel );
|
|
if ( !pSbStrm )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
|
|
return;
|
|
}
|
|
SvStream* pSvStrm = pSbStrm->GetStrm();
|
|
sal_uInt64 const nLen = pSvStrm->TellEnd();
|
|
rPar.Get32(0)->PutLong( static_cast<sal_Int32>(nLen) );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_Seek(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
// No changes for UCB
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs < 2 || nArgs > 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
sal_Int16 nChannel = rPar.Get32(1)->GetInteger();
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
SbiStream* pSbStrm = pIO->GetStream( nChannel );
|
|
if ( !pSbStrm )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_CHANNEL );
|
|
return;
|
|
}
|
|
SvStream* pStrm = pSbStrm->GetStrm();
|
|
|
|
if ( nArgs == 2 ) // Seek-Function
|
|
{
|
|
sal_uInt64 nPos = pStrm->Tell();
|
|
if( pSbStrm->IsRandom() )
|
|
{
|
|
nPos = nPos / pSbStrm->GetBlockLen();
|
|
}
|
|
nPos++; // Basic counts from 1
|
|
rPar.Get32(0)->PutLong( static_cast<sal_Int32>(nPos) );
|
|
}
|
|
else // Seek-Statement
|
|
{
|
|
sal_Int32 nPos = rPar.Get32(2)->GetLong();
|
|
if ( nPos < 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
nPos--; // Basic counts from 1, SvStreams count from 0
|
|
pSbStrm->SetExpandOnWriteTo( 0 );
|
|
if ( pSbStrm->IsRandom() )
|
|
{
|
|
nPos *= pSbStrm->GetBlockLen();
|
|
}
|
|
pStrm->Seek( static_cast<sal_uInt64>(nPos) );
|
|
pSbStrm->SetExpandOnWriteTo( nPos );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Format(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32();
|
|
if ( nArgCount < 2 || nArgCount > 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
OUString aResult;
|
|
if( nArgCount == 2 )
|
|
{
|
|
rPar.Get32(1)->Format( aResult );
|
|
}
|
|
else
|
|
{
|
|
OUString aFmt( rPar.Get32(2)->GetOUString() );
|
|
rPar.Get32(1)->Format( aResult, &aFmt );
|
|
}
|
|
rPar.Get32(0)->PutString( aResult );
|
|
}
|
|
}
|
|
|
|
// https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/formatnumber-function
|
|
void SbRtl_FormatNumber(StarBASIC*, SbxArray& rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32();
|
|
if (nArgCount < 2 || nArgCount > 6)
|
|
{
|
|
StarBASIC::Error(ERRCODE_BASIC_BAD_ARGUMENT);
|
|
return;
|
|
}
|
|
|
|
// The UI locale never changes -> we can use static value here
|
|
static const LocaleDataWrapper localeData(Application::GetSettings().GetUILanguageTag());
|
|
sal_Int16 nNumDigitsAfterDecimal = -1;
|
|
if (nArgCount > 2 && !rPar.Get32(2)->IsEmpty())
|
|
{
|
|
nNumDigitsAfterDecimal = rPar.Get32(2)->GetInteger();
|
|
if (nNumDigitsAfterDecimal < -1)
|
|
{
|
|
StarBASIC::Error(ERRCODE_BASIC_BAD_ARGUMENT);
|
|
return;
|
|
}
|
|
else if (nNumDigitsAfterDecimal > 255)
|
|
nNumDigitsAfterDecimal %= 256;
|
|
}
|
|
if (nNumDigitsAfterDecimal == -1)
|
|
nNumDigitsAfterDecimal = LocaleDataWrapper::getNumDigits();
|
|
|
|
bool bIncludeLeadingDigit = LocaleDataWrapper::isNumLeadingZero();
|
|
if (nArgCount > 3 && !rPar.Get32(3)->IsEmpty())
|
|
{
|
|
switch (rPar.Get32(3)->GetInteger())
|
|
{
|
|
case ooo::vba::VbTriState::vbFalse:
|
|
bIncludeLeadingDigit = false;
|
|
break;
|
|
case ooo::vba::VbTriState::vbTrue:
|
|
bIncludeLeadingDigit = true;
|
|
break;
|
|
case ooo::vba::VbTriState::vbUseDefault:
|
|
// do nothing;
|
|
break;
|
|
default:
|
|
StarBASIC::Error(ERRCODE_BASIC_BAD_ARGUMENT);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool bUseParensForNegativeNumbers = false;
|
|
if (nArgCount > 4 && !rPar.Get32(4)->IsEmpty())
|
|
{
|
|
switch (rPar.Get32(4)->GetInteger())
|
|
{
|
|
case ooo::vba::VbTriState::vbFalse:
|
|
case ooo::vba::VbTriState::vbUseDefault:
|
|
// do nothing
|
|
break;
|
|
case ooo::vba::VbTriState::vbTrue:
|
|
bUseParensForNegativeNumbers = true;
|
|
break;
|
|
default:
|
|
StarBASIC::Error(ERRCODE_BASIC_BAD_ARGUMENT);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool bGroupDigits = false;
|
|
if (nArgCount > 5 && !rPar.Get32(5)->IsEmpty())
|
|
{
|
|
switch (rPar.Get32(5)->GetInteger())
|
|
{
|
|
case ooo::vba::VbTriState::vbFalse:
|
|
case ooo::vba::VbTriState::vbUseDefault:
|
|
// do nothing
|
|
break;
|
|
case ooo::vba::VbTriState::vbTrue:
|
|
bGroupDigits = true;
|
|
break;
|
|
default:
|
|
StarBASIC::Error(ERRCODE_BASIC_BAD_ARGUMENT);
|
|
return;
|
|
}
|
|
}
|
|
|
|
double fVal = rPar.Get32(1)->GetDouble();
|
|
const bool bNegative = fVal < 0;
|
|
if (bNegative)
|
|
fVal = fabs(fVal); // Always work with non-negatives, to easily handle leading zero
|
|
|
|
static const sal_Unicode decSep = localeData.getNumDecimalSep().toChar();
|
|
OUString aResult = rtl::math::doubleToUString(
|
|
fVal, rtl_math_StringFormat_F, nNumDigitsAfterDecimal, decSep,
|
|
bGroupDigits ? localeData.getDigitGrouping().getConstArray() : nullptr,
|
|
localeData.getNumThousandSep().toChar());
|
|
|
|
if (!bIncludeLeadingDigit && aResult.getLength() > 1 && aResult.startsWith("0"))
|
|
aResult = aResult.copy(1);
|
|
|
|
if (nNumDigitsAfterDecimal > 0)
|
|
{
|
|
sal_Int32 nActualDigits = nNumDigitsAfterDecimal;
|
|
const sal_Int32 nSepPos = aResult.indexOf(decSep);
|
|
if (nSepPos == -1)
|
|
nActualDigits = 0;
|
|
else
|
|
nActualDigits = aResult.getLength() - nSepPos - 1;
|
|
|
|
// VBA allows up to 255 digits; rtl::math::doubleToUString outputs up to 15 digits
|
|
// for ~small numbers, so pad them as appropriate.
|
|
if (nActualDigits < nNumDigitsAfterDecimal)
|
|
{
|
|
OUStringBuffer sBuf;
|
|
comphelper::string::padToLength(sBuf, nNumDigitsAfterDecimal - nActualDigits, '0');
|
|
aResult += sBuf;
|
|
}
|
|
}
|
|
|
|
if (bNegative)
|
|
{
|
|
if (bUseParensForNegativeNumbers)
|
|
aResult = "(" + aResult + ")";
|
|
else
|
|
aResult = "-" + aResult;
|
|
}
|
|
|
|
rPar.Get32(0)->PutString(aResult);
|
|
}
|
|
|
|
namespace {
|
|
|
|
// note: BASIC does not use comphelper::random, because
|
|
// Randomize(int) must be supported and should not affect non-BASIC random use
|
|
struct RandomNumberGenerator
|
|
{
|
|
std::mt19937 global_rng;
|
|
|
|
RandomNumberGenerator()
|
|
{
|
|
try
|
|
{
|
|
std::random_device rd;
|
|
// initialises the state of the global random number generator
|
|
// should only be called once.
|
|
// (note, a few std::variate_generator<> (like normal) have their
|
|
// own state which would need a reset as well to guarantee identical
|
|
// sequence of numbers, e.g. via myrand.distribution().reset())
|
|
global_rng.seed(rd() ^ time(nullptr));
|
|
}
|
|
catch (std::runtime_error& e)
|
|
{
|
|
SAL_WARN("basic", "Using std::random_device failed: " << e.what());
|
|
global_rng.seed(time(nullptr));
|
|
}
|
|
}
|
|
};
|
|
|
|
class theRandomNumberGenerator : public rtl::Static<RandomNumberGenerator, theRandomNumberGenerator> {};
|
|
|
|
}
|
|
|
|
void SbRtl_Randomize(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() > 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
if( rPar.Count32() == 2 )
|
|
{
|
|
int nSeed = static_cast<int>(rPar.Get32(1)->GetInteger());
|
|
theRandomNumberGenerator::get().global_rng.seed(nSeed);
|
|
}
|
|
// without parameter, no need to do anything - RNG is seeded at first use
|
|
}
|
|
|
|
void SbRtl_Rnd(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() > 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
std::uniform_real_distribution<double> dist(0.0, 1.0);
|
|
double const tmp(dist(theRandomNumberGenerator::get().global_rng));
|
|
rPar.Get32(0)->PutDouble(tmp);
|
|
}
|
|
}
|
|
|
|
|
|
// Syntax: Shell("Path",[ Window-Style,[ "Params", [ bSync = sal_False ]]])
|
|
// WindowStyles (VBA compatible):
|
|
// 2 == Minimized
|
|
// 3 == Maximized
|
|
// 10 == Full-Screen (text mode applications OS/2, WIN95, WNT)
|
|
// HACK: The WindowStyle will be passed to
|
|
// Application::StartApp in Creator. Format: "xxxx2"
|
|
|
|
|
|
void SbRtl_Shell(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32();
|
|
if ( nArgCount < 2 || nArgCount > 5 )
|
|
{
|
|
rPar.Get32(0)->PutLong(0);
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
oslProcessOption nOptions = osl_Process_SEARCHPATH | osl_Process_DETACHED;
|
|
|
|
OUString aCmdLine = rPar.Get32(1)->GetOUString();
|
|
// attach additional parameters - everything must be parsed anyway
|
|
if( nArgCount >= 4 )
|
|
{
|
|
OUString tmp = rPar.Get32(3)->GetOUString().trim();
|
|
if (!tmp.isEmpty())
|
|
{
|
|
aCmdLine += " " + tmp;
|
|
}
|
|
}
|
|
else if( aCmdLine.isEmpty() )
|
|
{
|
|
// avoid special treatment (empty list)
|
|
aCmdLine += " ";
|
|
}
|
|
sal_Int32 nLen = aCmdLine.getLength();
|
|
|
|
// #55735 if there are parameters, they have to be separated
|
|
// #72471 also separate the single parameters
|
|
std::vector<OUString> aTokenVector;
|
|
OUString aToken;
|
|
sal_Int32 i = 0;
|
|
sal_Unicode c;
|
|
while( i < nLen )
|
|
{
|
|
for ( ;; ++i )
|
|
{
|
|
c = aCmdLine[ i ];
|
|
if ( c != ' ' && c != '\t' )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( c == '\"' || c == '\'' )
|
|
{
|
|
sal_Int32 iFoundPos = aCmdLine.indexOf( c, i + 1 );
|
|
|
|
if( iFoundPos < 0 )
|
|
{
|
|
aToken = aCmdLine.copy( i);
|
|
i = nLen;
|
|
}
|
|
else
|
|
{
|
|
aToken = aCmdLine.copy( i + 1, (iFoundPos - i - 1) );
|
|
i = iFoundPos + 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 iFoundSpacePos = aCmdLine.indexOf( ' ', i );
|
|
sal_Int32 iFoundTabPos = aCmdLine.indexOf( '\t', i );
|
|
sal_Int32 iFoundPos = iFoundSpacePos >= 0 ? iFoundTabPos >= 0 ? std::min( iFoundSpacePos, iFoundTabPos ) : iFoundSpacePos : -1;
|
|
|
|
if( iFoundPos < 0 )
|
|
{
|
|
aToken = aCmdLine.copy( i );
|
|
i = nLen;
|
|
}
|
|
else
|
|
{
|
|
aToken = aCmdLine.copy( i, (iFoundPos - i) );
|
|
i = iFoundPos;
|
|
}
|
|
}
|
|
|
|
// insert into the list
|
|
aTokenVector.push_back( aToken );
|
|
}
|
|
// #55735 / #72471 end
|
|
|
|
sal_Int16 nWinStyle = 0;
|
|
if( nArgCount >= 3 )
|
|
{
|
|
nWinStyle = rPar.Get32(2)->GetInteger();
|
|
switch( nWinStyle )
|
|
{
|
|
case 2:
|
|
nOptions |= osl_Process_MINIMIZED;
|
|
break;
|
|
case 3:
|
|
nOptions |= osl_Process_MAXIMIZED;
|
|
break;
|
|
case 10:
|
|
nOptions |= osl_Process_FULLSCREEN;
|
|
break;
|
|
}
|
|
|
|
bool bSync = false;
|
|
if( nArgCount >= 5 )
|
|
{
|
|
bSync = rPar.Get32(4)->GetBool();
|
|
}
|
|
if( bSync )
|
|
{
|
|
nOptions |= osl_Process_WAIT;
|
|
}
|
|
}
|
|
|
|
// #72471 work parameter(s) up
|
|
std::vector<OUString>::const_iterator iter = aTokenVector.begin();
|
|
OUString aOUStrProgURL = getFullPath( *iter );
|
|
|
|
++iter;
|
|
|
|
sal_uInt16 nParamCount = sal::static_int_cast< sal_uInt16 >(aTokenVector.size() - 1 );
|
|
std::unique_ptr<rtl_uString*[]> pParamList;
|
|
if( nParamCount )
|
|
{
|
|
pParamList.reset( new rtl_uString*[nParamCount]);
|
|
for(int iVector = 0; iter != aTokenVector.end(); ++iVector, ++iter)
|
|
{
|
|
const OUString& rParamStr = *iter;
|
|
pParamList[iVector] = nullptr;
|
|
rtl_uString_assign(&(pParamList[iVector]), rParamStr.pData);
|
|
}
|
|
}
|
|
|
|
oslProcess pApp;
|
|
bool bSucc = osl_executeProcess(
|
|
aOUStrProgURL.pData,
|
|
pParamList.get(),
|
|
nParamCount,
|
|
nOptions,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr, 0,
|
|
&pApp ) == osl_Process_E_None;
|
|
|
|
// 53521 only free process handle on success
|
|
if (bSucc)
|
|
{
|
|
osl_freeProcessHandle( pApp );
|
|
}
|
|
|
|
for(int j = 0; j < nParamCount; ++j)
|
|
{
|
|
rtl_uString_release(pParamList[j]);
|
|
}
|
|
|
|
if( !bSucc )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_FILE_NOT_FOUND );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutLong( 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_VarType(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxDataType eType = rPar.Get32(1)->GetType();
|
|
rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(eType) );
|
|
}
|
|
}
|
|
|
|
// Exported function
|
|
OUString getBasicTypeName( SbxDataType eType )
|
|
{
|
|
static const char* pTypeNames[] =
|
|
{
|
|
"Empty", // SbxEMPTY
|
|
"Null", // SbxNULL
|
|
"Integer", // SbxINTEGER
|
|
"Long", // SbxLONG
|
|
"Single", // SbxSINGLE
|
|
"Double", // SbxDOUBLE
|
|
"Currency", // SbxCURRENCY
|
|
"Date", // SbxDATE
|
|
"String", // SbxSTRING
|
|
"Object", // SbxOBJECT
|
|
"Error", // SbxERROR
|
|
"Boolean", // SbxBOOL
|
|
"Variant", // SbxVARIANT
|
|
"DataObject", // SbxDATAOBJECT
|
|
"Unknown Type",
|
|
"Unknown Type",
|
|
"Char", // SbxCHAR
|
|
"Byte", // SbxBYTE
|
|
"UShort", // SbxUSHORT
|
|
"ULong", // SbxULONG
|
|
"Long64", // SbxLONG64
|
|
"ULong64", // SbxULONG64
|
|
"Int", // SbxINT
|
|
"UInt", // SbxUINT
|
|
"Void", // SbxVOID
|
|
"HResult", // SbxHRESULT
|
|
"Pointer", // SbxPOINTER
|
|
"DimArray", // SbxDIMARRAY
|
|
"CArray", // SbxCARRAY
|
|
"Userdef", // SbxUSERDEF
|
|
"Lpstr", // SbxLPSTR
|
|
"Lpwstr", // SbxLPWSTR
|
|
"Unknown Type", // SbxCoreSTRING
|
|
"WString", // SbxWSTRING
|
|
"WChar", // SbxWCHAR
|
|
"Int64", // SbxSALINT64
|
|
"UInt64", // SbxSALUINT64
|
|
"Decimal", // SbxDECIMAL
|
|
};
|
|
|
|
size_t nPos = static_cast<size_t>(eType) & 0x0FFF;
|
|
const size_t nTypeNameCount = SAL_N_ELEMENTS( pTypeNames );
|
|
if ( nPos >= nTypeNameCount )
|
|
{
|
|
nPos = nTypeNameCount - 1;
|
|
}
|
|
return OUString::createFromAscii(pTypeNames[nPos]);
|
|
}
|
|
|
|
static OUString getObjectTypeName( SbxVariable* pVar )
|
|
{
|
|
OUString sRet( "Object" );
|
|
if ( pVar )
|
|
{
|
|
SbxBase* pBaseObj = pVar->GetObject();
|
|
if( !pBaseObj )
|
|
{
|
|
sRet = "Nothing";
|
|
}
|
|
else
|
|
{
|
|
SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pVar );
|
|
if ( !pUnoObj )
|
|
{
|
|
pUnoObj = dynamic_cast<SbUnoObject*>( pBaseObj );
|
|
}
|
|
if ( pUnoObj )
|
|
{
|
|
Any aObj = pUnoObj->getUnoAny();
|
|
// For upstreaming unless we start to build oovbaapi by default
|
|
// we need to get detect the vba-ness of the object in some
|
|
// other way
|
|
// note: Automation objects do not support XServiceInfo
|
|
uno::Reference< XServiceInfo > xServInfo( aObj, uno::UNO_QUERY );
|
|
if ( xServInfo.is() )
|
|
{
|
|
// is this a VBA object ?
|
|
Sequence< OUString > sServices = xServInfo->getSupportedServiceNames();
|
|
if ( sServices.hasElements() )
|
|
{
|
|
sRet = sServices[ 0 ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uno::Reference< bridge::oleautomation::XAutomationObject > xAutoMation( aObj, uno::UNO_QUERY );
|
|
if ( xAutoMation.is() )
|
|
{
|
|
uno::Reference< script::XInvocation > xInv( aObj, uno::UNO_QUERY );
|
|
if ( xInv.is() )
|
|
{
|
|
try
|
|
{
|
|
xInv->getValue( "$GetTypeName" ) >>= sRet;
|
|
}
|
|
catch(const Exception& )
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sal_Int32 nDot = sRet.lastIndexOf( '.' );
|
|
if ( nDot != -1 && nDot < sRet.getLength() )
|
|
{
|
|
sRet = sRet.copy( nDot + 1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return sRet;
|
|
}
|
|
|
|
void SbRtl_TypeName(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
SbxDataType eType = rPar.Get32(1)->GetType();
|
|
bool bIsArray = ( ( eType & SbxARRAY ) != 0 );
|
|
|
|
OUString aRetStr;
|
|
if ( SbiRuntime::isVBAEnabled() && eType == SbxOBJECT )
|
|
{
|
|
aRetStr = getObjectTypeName( rPar.Get32(1) );
|
|
}
|
|
else
|
|
{
|
|
aRetStr = getBasicTypeName( eType );
|
|
}
|
|
if( bIsArray )
|
|
{
|
|
aRetStr += "()";
|
|
}
|
|
rPar.Get32(0)->PutString( aRetStr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Len(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else
|
|
{
|
|
const OUString& rStr = rPar.Get32(1)->GetOUString();
|
|
rPar.Get32(0)->PutLong( rStr.getLength() );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DDEInitiate(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
const OUString& rApp = rPar.Get32(1)->GetOUString();
|
|
const OUString& rTopic = rPar.Get32(2)->GetOUString();
|
|
|
|
SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
|
|
size_t nChannel;
|
|
ErrCode nDdeErr = pDDE->Initiate( rApp, rTopic, nChannel );
|
|
if( nDdeErr )
|
|
{
|
|
StarBASIC::Error( nDdeErr );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutInteger( static_cast<sal_Int16>(nChannel) );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DDETerminate(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
size_t nChannel = rPar.Get32(1)->GetInteger();
|
|
SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
|
|
ErrCode nDdeErr = pDDE->Terminate( nChannel );
|
|
if( nDdeErr )
|
|
{
|
|
StarBASIC::Error( nDdeErr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DDETerminateAll(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs != 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
|
|
ErrCode nDdeErr = pDDE->TerminateAll();
|
|
if( nDdeErr )
|
|
{
|
|
StarBASIC::Error( nDdeErr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DDERequest(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
size_t nChannel = rPar.Get32(1)->GetInteger();
|
|
const OUString& rItem = rPar.Get32(2)->GetOUString();
|
|
SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
|
|
OUString aResult;
|
|
ErrCode nDdeErr = pDDE->Request( nChannel, rItem, aResult );
|
|
if( nDdeErr )
|
|
{
|
|
StarBASIC::Error( nDdeErr );
|
|
}
|
|
else
|
|
{
|
|
rPar.Get32(0)->PutString( aResult );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DDEExecute(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
size_t nChannel = rPar.Get32(1)->GetInteger();
|
|
const OUString& rCommand = rPar.Get32(2)->GetOUString();
|
|
SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
|
|
ErrCode nDdeErr = pDDE->Execute( nChannel, rCommand );
|
|
if( nDdeErr )
|
|
{
|
|
StarBASIC::Error( nDdeErr );
|
|
}
|
|
}
|
|
|
|
void SbRtl_DDEPoke(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
int nArgs = static_cast<int>(rPar.Count32());
|
|
if ( nArgs != 4 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
size_t nChannel = rPar.Get32(1)->GetInteger();
|
|
const OUString& rItem = rPar.Get32(2)->GetOUString();
|
|
const OUString& rData = rPar.Get32(3)->GetOUString();
|
|
SbiDdeControl* pDDE = GetSbData()->pInst->GetDdeControl();
|
|
ErrCode nDdeErr = pDDE->Poke( nChannel, rItem, rData );
|
|
if( nDdeErr )
|
|
{
|
|
StarBASIC::Error( nDdeErr );
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_FreeFile(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
short nChannel = 1;
|
|
while( nChannel < CHANNELS )
|
|
{
|
|
SbiStream* pStrm = pIO->GetStream( nChannel );
|
|
if( !pStrm )
|
|
{
|
|
rPar.Get32(0)->PutInteger( nChannel );
|
|
return;
|
|
}
|
|
nChannel++;
|
|
}
|
|
StarBASIC::Error( ERRCODE_BASIC_TOO_MANY_FILES );
|
|
}
|
|
|
|
void SbRtl_LBound(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nParCount = rPar.Count32();
|
|
if ( nParCount != 3 && nParCount != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
SbxBase* pParObj = rPar.Get32(1)->GetObject();
|
|
SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
|
|
if( pArr )
|
|
{
|
|
sal_Int32 nLower, nUpper;
|
|
short nDim = (nParCount == 3) ? static_cast<short>(rPar.Get32(2)->GetInteger()) : 1;
|
|
if( !pArr->GetDim32( nDim, nLower, nUpper ) )
|
|
StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
|
|
else
|
|
rPar.Get32(0)->PutLong( nLower );
|
|
}
|
|
else
|
|
StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );
|
|
}
|
|
|
|
void SbRtl_UBound(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nParCount = rPar.Count32();
|
|
if ( nParCount != 3 && nParCount != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
SbxBase* pParObj = rPar.Get32(1)->GetObject();
|
|
SbxDimArray* pArr = dynamic_cast<SbxDimArray*>( pParObj );
|
|
if( pArr )
|
|
{
|
|
sal_Int32 nLower, nUpper;
|
|
short nDim = (nParCount == 3) ? static_cast<short>(rPar.Get32(2)->GetInteger()) : 1;
|
|
if( !pArr->GetDim32( nDim, nLower, nUpper ) )
|
|
StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
|
|
else
|
|
rPar.Get32(0)->PutLong( nUpper );
|
|
}
|
|
else
|
|
StarBASIC::Error( ERRCODE_BASIC_MUST_HAVE_DIMS );
|
|
}
|
|
|
|
void SbRtl_RGB(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 4 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
sal_Int32 nRed = rPar.Get32(1)->GetInteger() & 0xFF;
|
|
sal_Int32 nGreen = rPar.Get32(2)->GetInteger() & 0xFF;
|
|
sal_Int32 nBlue = rPar.Get32(3)->GetInteger() & 0xFF;
|
|
sal_Int32 nRGB;
|
|
|
|
SbiInstance* pInst = GetSbData()->pInst;
|
|
bool bCompatibility = ( pInst && pInst->IsCompatibility() );
|
|
if( bCompatibility )
|
|
{
|
|
nRGB = (nBlue << 16) | (nGreen << 8) | nRed;
|
|
}
|
|
else
|
|
{
|
|
nRGB = (nRed << 16) | (nGreen << 8) | nBlue;
|
|
}
|
|
rPar.Get32(0)->PutLong( nRGB );
|
|
}
|
|
|
|
void SbRtl_QBColor(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
static const sal_Int32 pRGB[] =
|
|
{
|
|
0x000000,
|
|
0x800000,
|
|
0x008000,
|
|
0x808000,
|
|
0x000080,
|
|
0x800080,
|
|
0x008080,
|
|
0xC0C0C0,
|
|
0x808080,
|
|
0xFF0000,
|
|
0x00FF00,
|
|
0xFFFF00,
|
|
0x0000FF,
|
|
0xFF00FF,
|
|
0x00FFFF,
|
|
0xFFFFFF,
|
|
};
|
|
|
|
if ( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
sal_Int16 nCol = rPar.Get32(1)->GetInteger();
|
|
if( nCol < 0 || nCol > 15 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
sal_Int32 nRGB = pRGB[ nCol ];
|
|
rPar.Get32(0)->PutLong( nRGB );
|
|
}
|
|
|
|
// StrConv(string, conversion, LCID)
|
|
void SbRtl_StrConv(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32()-1;
|
|
if( nArgCount < 2 || nArgCount > 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
OUString aOldStr = rPar.Get32(1)->GetOUString();
|
|
sal_Int32 nConversion = rPar.Get32(2)->GetLong();
|
|
|
|
LanguageType nLanguage = LANGUAGE_SYSTEM;
|
|
|
|
sal_Int32 nOldLen = aOldStr.getLength();
|
|
if( nOldLen == 0 )
|
|
{
|
|
// null string,return
|
|
rPar.Get32(0)->PutString(aOldStr);
|
|
return;
|
|
}
|
|
|
|
TransliterationFlags nType = TransliterationFlags::NONE;
|
|
if ( (nConversion & 0x03) == 3 ) // vbProperCase
|
|
{
|
|
const CharClass& rCharClass = GetCharClass();
|
|
aOldStr = rCharClass.titlecase( aOldStr.toAsciiLowerCase(), 0, nOldLen );
|
|
}
|
|
else if ( (nConversion & 0x01) == 1 ) // vbUpperCase
|
|
{
|
|
nType |= TransliterationFlags::LOWERCASE_UPPERCASE;
|
|
}
|
|
else if ( (nConversion & 0x02) == 2 ) // vbLowerCase
|
|
{
|
|
nType |= TransliterationFlags::UPPERCASE_LOWERCASE;
|
|
}
|
|
if ( (nConversion & 0x04) == 4 ) // vbWide
|
|
{
|
|
nType |= TransliterationFlags::HALFWIDTH_FULLWIDTH;
|
|
}
|
|
else if ( (nConversion & 0x08) == 8 ) // vbNarrow
|
|
{
|
|
nType |= TransliterationFlags::FULLWIDTH_HALFWIDTH;
|
|
}
|
|
if ( (nConversion & 0x10) == 16) // vbKatakana
|
|
{
|
|
nType |= TransliterationFlags::HIRAGANA_KATAKANA;
|
|
}
|
|
else if ( (nConversion & 0x20) == 32 ) // vbHiragana
|
|
{
|
|
nType |= TransliterationFlags::KATAKANA_HIRAGANA;
|
|
}
|
|
OUString aNewStr( aOldStr );
|
|
if( nType != TransliterationFlags::NONE )
|
|
{
|
|
uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
|
|
::utl::TransliterationWrapper aTransliterationWrapper( xContext, nType );
|
|
uno::Sequence<sal_Int32> aOffsets;
|
|
aTransliterationWrapper.loadModuleIfNeeded( nLanguage );
|
|
aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
|
|
}
|
|
|
|
if ( (nConversion & 0x40) == 64 ) // vbUnicode
|
|
{
|
|
// convert the string to byte string, preserving unicode (2 bytes per character)
|
|
sal_Int32 nSize = aNewStr.getLength()*2;
|
|
const sal_Unicode* pSrc = aNewStr.getStr();
|
|
std::unique_ptr<char[]> pChar(new char[nSize+1]);
|
|
for( sal_Int32 i=0; i < nSize; i++ )
|
|
{
|
|
pChar[i] = static_cast< char >( (i%2) ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff );
|
|
if( i%2 )
|
|
{
|
|
pSrc++;
|
|
}
|
|
}
|
|
pChar[nSize] = '\0';
|
|
OString aOStr(pChar.get());
|
|
|
|
// there is no concept about default codepage in unix. so it is incorrectly in unix
|
|
OUString aOUStr = OStringToOUString(aOStr, osl_getThreadTextEncoding());
|
|
rPar.Get32(0)->PutString( aOUStr );
|
|
return;
|
|
}
|
|
else if ( (nConversion & 0x80) == 128 ) // vbFromUnicode
|
|
{
|
|
// there is no concept about default codepage in unix. so it is incorrectly in unix
|
|
OString aOStr = OUStringToOString(aNewStr,osl_getThreadTextEncoding());
|
|
const char* pChar = aOStr.getStr();
|
|
sal_Int32 nArraySize = aOStr.getLength();
|
|
SbxDimArray* pArray = new SbxDimArray(SbxBYTE);
|
|
bool bIncIndex = (IsBaseIndexOne() && SbiRuntime::isVBAEnabled() );
|
|
if(nArraySize)
|
|
{
|
|
if( bIncIndex )
|
|
{
|
|
pArray->AddDim32( 1, nArraySize );
|
|
}
|
|
else
|
|
{
|
|
pArray->AddDim32( 0, nArraySize-1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pArray->unoAddDim32( 0, -1 );
|
|
}
|
|
|
|
for( sal_Int32 i=0; i< nArraySize; i++)
|
|
{
|
|
SbxVariable* pNew = new SbxVariable( SbxBYTE );
|
|
pNew->PutByte(*pChar);
|
|
pChar++;
|
|
pNew->SetFlag( SbxFlagBits::Write );
|
|
sal_Int32 aIdx[1];
|
|
aIdx[0] = i;
|
|
if( bIncIndex )
|
|
{
|
|
++aIdx[0];
|
|
}
|
|
pArray->Put32(pNew, aIdx);
|
|
}
|
|
|
|
SbxVariableRef refVar = rPar.Get32(0);
|
|
SbxFlagBits nFlags = refVar->GetFlags();
|
|
refVar->ResetFlag( SbxFlagBits::Fixed );
|
|
refVar->PutObject( pArray );
|
|
refVar->SetFlags( nFlags );
|
|
refVar->SetParameters( nullptr );
|
|
return;
|
|
}
|
|
rPar.Get32(0)->PutString(aNewStr);
|
|
}
|
|
|
|
|
|
void SbRtl_Beep(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
Sound::Beep();
|
|
}
|
|
|
|
void SbRtl_Load(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
|
|
SbxBase* pObj = rPar.Get32(1)->GetObject();
|
|
if ( pObj )
|
|
{
|
|
if (SbUserFormModule* pModule = dynamic_cast<SbUserFormModule*>(pObj))
|
|
{
|
|
pModule->Load();
|
|
}
|
|
else if (SbxObject* pSbxObj = dynamic_cast<SbxObject*>(pObj))
|
|
{
|
|
SbxVariable* pVar = pSbxObj->Find("Load", SbxClassType::Method);
|
|
if( pVar )
|
|
{
|
|
pVar->GetInteger();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_Unload(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
|
|
SbxBase* pObj = rPar.Get32(1)->GetObject();
|
|
if ( pObj )
|
|
{
|
|
if (SbUserFormModule* pFormModule = dynamic_cast<SbUserFormModule*>(pObj))
|
|
{
|
|
pFormModule->Unload();
|
|
}
|
|
else if (SbxObject *pSbxObj = dynamic_cast<SbxObject*>(pObj))
|
|
{
|
|
SbxVariable* pVar = pSbxObj->Find("Unload", SbxClassType::Method);
|
|
if( pVar )
|
|
{
|
|
pVar->GetInteger();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SbRtl_LoadPicture(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if( rPar.Count32() != 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
OUString aFileURL = getFullPath( rPar.Get32(1)->GetOUString() );
|
|
std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aFileURL, StreamMode::READ ));
|
|
if( pStream )
|
|
{
|
|
Bitmap aBmp;
|
|
ReadDIB(aBmp, *pStream, true);
|
|
Graphic aGraphic(aBmp);
|
|
|
|
SbxObjectRef xRef = new SbStdPicture;
|
|
static_cast<SbStdPicture*>(xRef.get())->SetGraphic( aGraphic );
|
|
rPar.Get32(0)->PutObject( xRef.get() );
|
|
}
|
|
}
|
|
|
|
void SbRtl_SavePicture(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if( rPar.Count32() != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
SbxBase* pObj = rPar.Get32(1)->GetObject();
|
|
if (SbStdPicture *pPicture = dynamic_cast<SbStdPicture*>(pObj))
|
|
{
|
|
SvFileStream aOStream( rPar.Get32(2)->GetOUString(), StreamMode::WRITE | StreamMode::TRUNC );
|
|
const Graphic& aGraphic = pPicture->GetGraphic();
|
|
WriteGraphic( aOStream, aGraphic );
|
|
}
|
|
}
|
|
|
|
void SbRtl_MsgBox(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32();
|
|
if( nArgCount < 2 || nArgCount > 6 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
WinBits nType = 0; // MB_OK
|
|
if( nArgCount >= 3 )
|
|
nType = static_cast<WinBits>(rPar.Get32(2)->GetInteger());
|
|
WinBits nStyle = nType;
|
|
nStyle &= 15; // delete bits 4-16
|
|
if (nStyle > 5)
|
|
nStyle = 0;
|
|
|
|
enum BasicResponse
|
|
{
|
|
Ok = 1,
|
|
Cancel = 2,
|
|
Abort = 3,
|
|
Retry = 4,
|
|
Ignore = 5,
|
|
Yes = 6,
|
|
No = 7
|
|
};
|
|
|
|
OUString aMsg = rPar.Get32(1)->GetOUString();
|
|
OUString aTitle;
|
|
if( nArgCount >= 4 )
|
|
{
|
|
aTitle = rPar.Get32(3)->GetOUString();
|
|
}
|
|
else
|
|
{
|
|
aTitle = Application::GetDisplayName();
|
|
}
|
|
|
|
WinBits nDialogType = nType & (16+32+64);
|
|
|
|
SolarMutexGuard aSolarGuard;
|
|
vcl::Window* pParentWin = Application::GetDefDialogParent();
|
|
weld::Widget* pParent = pParentWin ? pParentWin->GetFrameWeld() : nullptr;
|
|
|
|
VclMessageType eType = VclMessageType::Info;
|
|
|
|
switch (nDialogType)
|
|
{
|
|
case 16:
|
|
eType = VclMessageType::Error;
|
|
break;
|
|
case 32:
|
|
eType = VclMessageType::Question;
|
|
break;
|
|
case 48:
|
|
eType = VclMessageType::Warning;
|
|
break;
|
|
case 64:
|
|
default:
|
|
eType = VclMessageType::Info;
|
|
break;
|
|
}
|
|
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
|
|
eType, VclButtonsType::NONE, aMsg));
|
|
|
|
switch (nStyle)
|
|
{
|
|
case 0: // MB_OK
|
|
default:
|
|
xBox->add_button(GetStandardText(StandardButtonType::OK), BasicResponse::Ok);
|
|
break;
|
|
case 1: // MB_OKCANCEL
|
|
xBox->add_button(GetStandardText(StandardButtonType::OK), BasicResponse::Ok);
|
|
xBox->add_button(GetStandardText(StandardButtonType::Cancel), BasicResponse::Cancel);
|
|
|
|
if (nType & 256 || nType & 512)
|
|
xBox->set_default_response(BasicResponse::Cancel);
|
|
else
|
|
xBox->set_default_response(BasicResponse::Ok);
|
|
|
|
break;
|
|
case 2: // MB_ABORTRETRYIGNORE
|
|
xBox->add_button(GetStandardText(StandardButtonType::Abort), BasicResponse::Abort);
|
|
xBox->add_button(GetStandardText(StandardButtonType::Retry), BasicResponse::Retry);
|
|
xBox->add_button(GetStandardText(StandardButtonType::Ignore), BasicResponse::Ignore);
|
|
|
|
if (nType & 256)
|
|
xBox->set_default_response(BasicResponse::Retry);
|
|
else if (nType & 512)
|
|
xBox->set_default_response(BasicResponse::Ignore);
|
|
else
|
|
xBox->set_default_response(BasicResponse::Cancel);
|
|
|
|
break;
|
|
case 3: // MB_YESNOCANCEL
|
|
xBox->add_button(GetStandardText(StandardButtonType::Yes), BasicResponse::Yes);
|
|
xBox->add_button(GetStandardText(StandardButtonType::No), BasicResponse::No);
|
|
xBox->add_button(GetStandardText(StandardButtonType::Cancel), BasicResponse::Cancel);
|
|
|
|
if (nType & 256 || nType & 512)
|
|
xBox->set_default_response(BasicResponse::Cancel);
|
|
else
|
|
xBox->set_default_response(BasicResponse::Yes);
|
|
|
|
break;
|
|
case 4: // MB_YESNO
|
|
xBox->add_button(GetStandardText(StandardButtonType::Yes), BasicResponse::Yes);
|
|
xBox->add_button(GetStandardText(StandardButtonType::No), BasicResponse::No);
|
|
|
|
if (nType & 256 || nType & 512)
|
|
xBox->set_default_response(BasicResponse::No);
|
|
else
|
|
xBox->set_default_response(BasicResponse::Yes);
|
|
|
|
break;
|
|
case 5: // MB_RETRYCANCEL
|
|
xBox->add_button(GetStandardText(StandardButtonType::Retry), BasicResponse::Retry);
|
|
xBox->add_button(GetStandardText(StandardButtonType::Cancel), BasicResponse::Cancel);
|
|
|
|
if (nType & 256 || nType & 512)
|
|
xBox->set_default_response(BasicResponse::Cancel);
|
|
else
|
|
xBox->set_default_response(BasicResponse::Retry);
|
|
|
|
break;
|
|
}
|
|
|
|
xBox->set_title(aTitle);
|
|
sal_Int16 nRet = xBox->run();
|
|
rPar.Get32(0)->PutInteger(nRet);
|
|
}
|
|
|
|
void SbRtl_SetAttr(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
rPar.Get32(0)->PutEmpty();
|
|
if ( rPar.Count32() == 3 )
|
|
{
|
|
OUString aStr = rPar.Get32(1)->GetOUString();
|
|
SbAttributes nFlags = static_cast<SbAttributes>( rPar.Get32(2)->GetInteger() );
|
|
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
bool bReadOnly = bool(nFlags & SbAttributes::READONLY);
|
|
xSFI->setReadOnly( aStr, bReadOnly );
|
|
bool bHidden = bool(nFlags & SbAttributes::HIDDEN);
|
|
xSFI->setHidden( aStr, bHidden );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Reset(StarBASIC *, SbxArray &, bool)
|
|
{
|
|
SbiIoSystem* pIO = GetSbData()->pInst->GetIoSystem();
|
|
if (pIO)
|
|
{
|
|
pIO->CloseAll();
|
|
}
|
|
}
|
|
|
|
void SbRtl_DumpAllObjects(StarBASIC * pBasic, SbxArray & rPar, bool)
|
|
{
|
|
const sal_uInt32 nArgCount = rPar.Count32();
|
|
if( nArgCount < 2 || nArgCount > 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
else if( !pBasic )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_INTERNAL_ERROR );
|
|
}
|
|
else
|
|
{
|
|
SbxObject* p = pBasic;
|
|
while( p->GetParent() )
|
|
{
|
|
p = p->GetParent();
|
|
}
|
|
SvFileStream aStrm( rPar.Get32(1)->GetOUString(),
|
|
StreamMode::WRITE | StreamMode::TRUNC );
|
|
p->Dump( aStrm, rPar.Get32(2)->GetBool() );
|
|
aStrm.Close();
|
|
if( aStrm.GetError() != ERRCODE_NONE )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_IO_ERROR );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SbRtl_FileExists(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() == 2 )
|
|
{
|
|
OUString aStr = rPar.Get32(1)->GetOUString();
|
|
bool bExists = false;
|
|
|
|
if( hasUno() )
|
|
{
|
|
const uno::Reference< ucb::XSimpleFileAccess3 >& xSFI = getFileAccess();
|
|
if( xSFI.is() )
|
|
{
|
|
try
|
|
{
|
|
bExists = xSFI->exists( aStr );
|
|
}
|
|
catch(const Exception & )
|
|
{
|
|
StarBASIC::Error( ERRCODE_IO_GENERAL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DirectoryItem aItem;
|
|
FileBase::RC nRet = DirectoryItem::get( getFullPath( aStr ), aItem );
|
|
bExists = (nRet == FileBase::E_None);
|
|
}
|
|
rPar.Get32(0)->PutBool( bExists );
|
|
}
|
|
else
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
}
|
|
}
|
|
|
|
void SbRtl_Partition(StarBASIC *, SbxArray & rPar, bool)
|
|
{
|
|
if ( rPar.Count32() != 5 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
sal_Int32 nNumber = rPar.Get32(1)->GetLong();
|
|
sal_Int32 nStart = rPar.Get32(2)->GetLong();
|
|
sal_Int32 nStop = rPar.Get32(3)->GetLong();
|
|
sal_Int32 nInterval = rPar.Get32(4)->GetLong();
|
|
|
|
if( nStart < 0 || nStop <= nStart || nInterval < 1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
// the Partition function inserts leading spaces before lowervalue and uppervalue
|
|
// so that they both have the same number of characters as the string
|
|
// representation of the value (Stop + 1). This ensures that if you use the output
|
|
// of the Partition function with several values of Number, the resulting text
|
|
// will be handled properly during any subsequent sort operation.
|
|
|
|
// calculate the maximum number of characters before lowervalue and uppervalue
|
|
OUString aBeforeStart = OUString::number( nStart - 1 );
|
|
OUString aAfterStop = OUString::number( nStop + 1 );
|
|
sal_Int32 nLen1 = aBeforeStart.getLength();
|
|
sal_Int32 nLen2 = aAfterStop.getLength();
|
|
sal_Int32 nLen = nLen1 >= nLen2 ? nLen1:nLen2;
|
|
|
|
OUStringBuffer aRetStr( nLen * 2 + 1);
|
|
OUString aLowerValue;
|
|
OUString aUpperValue;
|
|
if( nNumber < nStart )
|
|
{
|
|
aUpperValue = aBeforeStart;
|
|
}
|
|
else if( nNumber > nStop )
|
|
{
|
|
aLowerValue = aAfterStop;
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 nLowerValue = nNumber;
|
|
sal_Int32 nUpperValue = nLowerValue;
|
|
if( nInterval > 1 )
|
|
{
|
|
nLowerValue = ((( nNumber - nStart ) / nInterval ) * nInterval ) + nStart;
|
|
nUpperValue = nLowerValue + nInterval - 1;
|
|
}
|
|
aLowerValue = OUString::number( nLowerValue );
|
|
aUpperValue = OUString::number( nUpperValue );
|
|
}
|
|
|
|
nLen1 = aLowerValue.getLength();
|
|
nLen2 = aUpperValue.getLength();
|
|
|
|
if( nLen > nLen1 )
|
|
{
|
|
// appending the leading spaces for the lowervalue
|
|
for ( sal_Int32 i= nLen - nLen1; i > 0; --i )
|
|
{
|
|
aRetStr.append(" ");
|
|
}
|
|
}
|
|
aRetStr.append( aLowerValue ).append(":");
|
|
if( nLen > nLen2 )
|
|
{
|
|
// appending the leading spaces for the uppervalue
|
|
for ( sal_Int32 i= nLen - nLen2; i > 0; --i )
|
|
{
|
|
aRetStr.append(" ");
|
|
}
|
|
}
|
|
aRetStr.append( aUpperValue );
|
|
rPar.Get32(0)->PutString( aRetStr.makeStringAndClear());
|
|
}
|
|
|
|
#endif
|
|
|
|
static long GetDayDiff( const Date& rDate )
|
|
{
|
|
Date aRefDate( 1,1,1900 );
|
|
long nDiffDays;
|
|
if ( aRefDate > rDate )
|
|
{
|
|
nDiffDays = aRefDate - rDate;
|
|
nDiffDays *= -1;
|
|
}
|
|
else
|
|
{
|
|
nDiffDays = rDate - aRefDate;
|
|
}
|
|
nDiffDays += 2; // adjustment VisualBasic: 1.Jan.1900 == 2
|
|
return nDiffDays;
|
|
}
|
|
|
|
sal_Int16 implGetDateYear( double aDate )
|
|
{
|
|
Date aRefDate( 1,1,1900 );
|
|
long nDays = static_cast<long>(aDate);
|
|
nDays -= 2; // standardize: 1.1.1900 => 0.0
|
|
aRefDate.AddDays( nDays );
|
|
sal_Int16 nRet = aRefDate.GetYear();
|
|
return nRet;
|
|
}
|
|
|
|
bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
|
|
bool bUseTwoDigitYear, SbDateCorrection eCorr, double& rdRet )
|
|
{
|
|
// XXX NOTE: For VBA years<0 are invalid and years in the range 0..29 and
|
|
// 30..99 can not be input as they are 2-digit for 2000..2029 and
|
|
// 1930..1999, VBA mode overrides bUseTwoDigitYear (as if that was always
|
|
// true). For VBA years > 9999 are invalid.
|
|
// For StarBASIC, if bUseTwoDigitYear==true then years in the range 0..99
|
|
// can not be input as they are 2-digit for 1900..1999, years<0 are
|
|
// accepted. If bUseTwoDigitYear==false then all years are accepted, but
|
|
// year 0 is invalid (last day BCE -0001-12-31, first day CE 0001-01-01).
|
|
#if HAVE_FEATURE_SCRIPTING
|
|
if ( (nYear < 0 || 9999 < nYear) && SbiRuntime::isVBAEnabled() )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return false;
|
|
}
|
|
else if ( nYear < 30 && SbiRuntime::isVBAEnabled() )
|
|
{
|
|
nYear += 2000;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if ( 0 <= nYear && nYear < 100 && (bUseTwoDigitYear
|
|
#if HAVE_FEATURE_SCRIPTING
|
|
|| SbiRuntime::isVBAEnabled()
|
|
#endif
|
|
) )
|
|
{
|
|
nYear += 1900;
|
|
}
|
|
}
|
|
|
|
sal_Int32 nAddMonths = 0;
|
|
sal_Int32 nAddDays = 0;
|
|
// Always sanitize values to set date and to use for validity detection.
|
|
if (nMonth < 1 || 12 < nMonth)
|
|
{
|
|
sal_Int16 nM = ((nMonth < 1) ? (12 + (nMonth % 12)) : (nMonth % 12));
|
|
nAddMonths = nMonth - nM;
|
|
nMonth = nM;
|
|
}
|
|
// Day 0 would already be normalized during Date::Normalize(), include
|
|
// it in negative days, also to detect non-validity. The actual day of
|
|
// month is 1+(nDay-1)
|
|
if (nDay < 1)
|
|
{
|
|
nAddDays = nDay - 1;
|
|
nDay = 1;
|
|
}
|
|
else if (nDay > 31)
|
|
{
|
|
nAddDays = nDay - 31;
|
|
nDay = 31;
|
|
}
|
|
|
|
Date aCurDate( nDay, nMonth, nYear );
|
|
|
|
/* TODO: we could enable the same rollover mechanism for StarBASIC to be
|
|
* compatible with VBA (just with our wider supported date range), then
|
|
* documentation would need to be adapted. As is, the DateSerial() runtime
|
|
* function works as dumb as documented... (except that the resulting date
|
|
* is checked for validity now and not just day<=31 and month<=12).
|
|
* If change wanted then simply remove overriding RollOver here and adapt
|
|
* documentation.*/
|
|
#if HAVE_FEATURE_SCRIPTING
|
|
if (eCorr == SbDateCorrection::RollOver && !SbiRuntime::isVBAEnabled())
|
|
eCorr = SbDateCorrection::None;
|
|
#endif
|
|
|
|
if (nYear == 0 || (eCorr == SbDateCorrection::None && (nAddMonths || nAddDays || !aCurDate.IsValidDate())))
|
|
{
|
|
#if HAVE_FEATURE_SCRIPTING
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
if (eCorr != SbDateCorrection::None)
|
|
{
|
|
aCurDate.Normalize();
|
|
if (nAddMonths)
|
|
aCurDate.AddMonths( nAddMonths);
|
|
if (nAddDays)
|
|
aCurDate.AddDays( nAddDays);
|
|
if (eCorr == SbDateCorrection::TruncateToMonth && aCurDate.GetMonth() != nMonth)
|
|
{
|
|
if (aCurDate.GetYear() == SAL_MAX_INT16 && nMonth == 12)
|
|
{
|
|
// Roll over and back not possible, hard max.
|
|
aCurDate.SetMonth(12);
|
|
aCurDate.SetDay(31);
|
|
}
|
|
else
|
|
{
|
|
aCurDate.SetMonth(nMonth);
|
|
aCurDate.SetDay(1);
|
|
aCurDate.AddMonths(1);
|
|
aCurDate.AddDays(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
long nDiffDays = GetDayDiff( aCurDate );
|
|
rdRet = static_cast<double>(nDiffDays);
|
|
return true;
|
|
}
|
|
|
|
double implTimeSerial( sal_Int16 nHours, sal_Int16 nMinutes, sal_Int16 nSeconds )
|
|
{
|
|
return
|
|
static_cast<double>( nHours * ::tools::Time::secondPerHour +
|
|
nMinutes * ::tools::Time::secondPerMinute +
|
|
nSeconds)
|
|
/
|
|
static_cast<double>( ::tools::Time::secondPerDay );
|
|
}
|
|
|
|
bool implDateTimeSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
|
|
sal_Int16 nHour, sal_Int16 nMinute, sal_Int16 nSecond,
|
|
double& rdRet )
|
|
{
|
|
double dDate;
|
|
if(!implDateSerial(nYear, nMonth, nDay, false/*bUseTwoDigitYear*/, SbDateCorrection::None, dDate))
|
|
return false;
|
|
rdRet += dDate + implTimeSerial(nHour, nMinute, nSecond);
|
|
return true;
|
|
}
|
|
|
|
sal_Int16 implGetMinute( double dDate )
|
|
{
|
|
double nFrac = dDate - floor( dDate );
|
|
nFrac *= 86400.0;
|
|
sal_Int32 nSeconds = static_cast<sal_Int32>(nFrac + 0.5);
|
|
sal_Int16 nTemp = static_cast<sal_Int16>(nSeconds % 3600);
|
|
sal_Int16 nMin = nTemp / 60;
|
|
return nMin;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|