2017-11-04 07:03:53 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* fstring.cpp - Unicode string class with UTF-8 support *
|
|
|
|
* *
|
2020-07-08 21:32:47 +02:00
|
|
|
* This file is part of the FINAL CUT widget toolkit *
|
2017-11-04 07:03:53 +01:00
|
|
|
* *
|
2021-02-09 22:01:21 +01:00
|
|
|
* Copyright 2012-2021 Markus Gans *
|
2017-11-04 07:03:53 +01:00
|
|
|
* *
|
2020-07-08 21:32:47 +02:00
|
|
|
* FINAL CUT is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU Lesser General Public License as *
|
|
|
|
* published by the Free Software Foundation; either version 3 of *
|
2017-11-04 07:03:53 +01:00
|
|
|
* the License, or (at your option) any later version. *
|
|
|
|
* *
|
2020-07-08 21:32:47 +02:00
|
|
|
* FINAL CUT is distributed in the hope that it will be useful, but *
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
2017-11-04 07:03:53 +01:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU Lesser General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
|
|
* License along with this program. If not, see *
|
|
|
|
* <http://www.gnu.org/licenses/>. *
|
|
|
|
***********************************************************************/
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
#include <algorithm>
|
2017-09-11 03:06:02 +02:00
|
|
|
#include <string>
|
2019-08-06 23:45:28 +02:00
|
|
|
#include <utility>
|
2017-09-11 03:06:02 +02:00
|
|
|
#include <vector>
|
|
|
|
|
2020-05-13 23:47:14 +02:00
|
|
|
#include "final/fapplication.h"
|
|
|
|
#include "final/flog.h"
|
2017-09-17 21:32:46 +02:00
|
|
|
#include "final/fstring.h"
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2018-09-20 23:59:01 +02:00
|
|
|
namespace finalcut
|
|
|
|
{
|
|
|
|
|
2019-09-29 22:28:58 +02:00
|
|
|
// static class attributes
|
|
|
|
wchar_t FString::null_char{L'\0'};
|
|
|
|
const wchar_t FString::const_null_char{L'\0'};
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// class FString
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// constructors and destructor
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::FString (int len)
|
|
|
|
{
|
2015-11-15 19:46:33 +01:00
|
|
|
if ( len > 0 )
|
2020-05-26 21:37:39 +02:00
|
|
|
_initLength(std::size_t(len));
|
2015-05-23 13:35:12 +02:00
|
|
|
else
|
2020-05-26 21:37:39 +02:00
|
|
|
_initLength(0);
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
FString::FString (std::size_t len)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-26 21:37:39 +02:00
|
|
|
_initLength(len);
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
FString::FString (std::size_t len, wchar_t c)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-26 21:37:39 +02:00
|
|
|
_initLength(len);
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* ps = string;
|
|
|
|
wchar_t* pe = string + len;
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
while ( pe != ps )
|
|
|
|
*--pe = c;
|
|
|
|
}
|
|
|
|
|
2020-12-31 20:45:10 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::FString (std::size_t len, const UniChar& c)
|
|
|
|
: FString(len, wchar_t(c))
|
|
|
|
{ }
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-03-12 20:29:10 +01:00
|
|
|
FString::FString (const FString& s) // copy constructor
|
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( ! s.isNull() )
|
2017-04-17 22:49:42 +02:00
|
|
|
_assign (s.string);
|
2017-03-12 20:29:10 +01:00
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2019-07-29 02:34:58 +02:00
|
|
|
//----------------------------------------------------------------------
|
2020-04-13 12:40:11 +02:00
|
|
|
FString::FString (FString&& s) noexcept // move constructor
|
2020-12-03 10:43:20 +01:00
|
|
|
: string{s.string}
|
2020-05-24 23:55:08 +02:00
|
|
|
, length{s.length}
|
|
|
|
, bufsize{s.bufsize}
|
2020-12-03 10:43:20 +01:00
|
|
|
, c_string{s.c_string}
|
2019-07-29 02:34:58 +02:00
|
|
|
{
|
2020-05-24 02:15:43 +02:00
|
|
|
s.string = nullptr;
|
2020-05-02 00:07:35 +02:00
|
|
|
s.length = 0;
|
|
|
|
s.bufsize = 0;
|
2020-05-24 23:55:08 +02:00
|
|
|
s.c_string = nullptr;
|
2019-07-29 02:34:58 +02:00
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::FString (const std::wstring& s)
|
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( ! s.empty() )
|
2018-03-05 03:15:16 +01:00
|
|
|
_assign (s.c_str());
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2017-12-25 21:17:08 +01:00
|
|
|
FString::FString (const wchar_t s[])
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( s )
|
2017-04-17 22:49:42 +02:00
|
|
|
_assign (s);
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::FString (const std::string& s)
|
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( ! s.empty() )
|
2018-03-05 03:15:16 +01:00
|
|
|
{
|
2020-05-26 21:37:39 +02:00
|
|
|
const wchar_t* wc_string = _to_wcstring(s.c_str());
|
2018-10-05 05:15:54 +02:00
|
|
|
_assign(wc_string);
|
|
|
|
delete[] wc_string;
|
2018-03-05 03:15:16 +01:00
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2017-12-25 21:17:08 +01:00
|
|
|
FString::FString (const char s[])
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( s )
|
2018-03-05 03:15:16 +01:00
|
|
|
{
|
2020-05-26 21:37:39 +02:00
|
|
|
const wchar_t* wc_string = _to_wcstring(s);
|
2018-10-05 05:15:54 +02:00
|
|
|
_assign( wc_string );
|
|
|
|
delete[] wc_string;
|
2018-03-05 03:15:16 +01:00
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
2018-12-06 02:28:24 +01:00
|
|
|
//----------------------------------------------------------------------
|
2020-12-31 20:45:10 +01:00
|
|
|
FString::FString (const UniChar& c)
|
2018-12-06 02:28:24 +01:00
|
|
|
{
|
2020-12-31 20:45:10 +01:00
|
|
|
std::array<wchar_t, 2> s{{ static_cast<wchar_t>(c), L'\0' }};
|
|
|
|
_assign (s.data());
|
2018-12-06 02:28:24 +01:00
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::FString (const wchar_t c)
|
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( c )
|
2018-03-05 03:15:16 +01:00
|
|
|
{
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<wchar_t, 2> s{{ c, L'\0' }};
|
|
|
|
_assign (s.data());
|
2018-03-05 03:15:16 +01:00
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::FString (const char c)
|
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
if ( c )
|
2018-03-05 03:15:16 +01:00
|
|
|
{
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<wchar_t, 2> s{{ wchar_t(c & 0xff), L'\0' }};
|
|
|
|
_assign (s.data());
|
2018-03-05 03:15:16 +01:00
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString::~FString() // destructor
|
|
|
|
{
|
|
|
|
if ( string )
|
|
|
|
delete[](string);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( c_string )
|
|
|
|
delete[](c_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
// FString operators
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
2016-11-02 00:37:58 +01:00
|
|
|
FString& FString::operator = (const FString& s)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-24 23:55:08 +02:00
|
|
|
if ( &s != this )
|
|
|
|
_assign (s.string);
|
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
2019-07-29 02:34:58 +02:00
|
|
|
//----------------------------------------------------------------------
|
2020-04-13 12:40:11 +02:00
|
|
|
FString& FString::operator = (FString&& s) noexcept
|
2019-07-29 02:34:58 +02:00
|
|
|
{
|
2020-05-24 23:55:08 +02:00
|
|
|
if ( &s != this )
|
|
|
|
{
|
|
|
|
if ( string )
|
|
|
|
delete[](string);
|
|
|
|
|
|
|
|
if ( c_string )
|
|
|
|
delete[](c_string);
|
|
|
|
|
2020-12-03 10:43:20 +01:00
|
|
|
string = s.string;
|
2020-05-24 23:55:08 +02:00
|
|
|
length = s.length;
|
|
|
|
bufsize = s.bufsize;
|
2020-12-03 10:43:20 +01:00
|
|
|
c_string = s.c_string;
|
2020-05-24 23:55:08 +02:00
|
|
|
|
|
|
|
s.string = nullptr;
|
|
|
|
s.length = 0;
|
|
|
|
s.bufsize = 0;
|
|
|
|
s.c_string = nullptr;
|
|
|
|
}
|
2020-05-24 02:15:43 +02:00
|
|
|
|
2019-07-29 02:34:58 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
const FString& FString::operator += (const FString& s)
|
|
|
|
{
|
|
|
|
_insert (length, s.length, s.string);
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-20 02:51:17 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString& FString::operator << (const FString& s)
|
|
|
|
{
|
|
|
|
_insert (length, s.length, s.string);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-12-06 02:28:24 +01:00
|
|
|
//----------------------------------------------------------------------
|
2020-12-31 20:45:10 +01:00
|
|
|
FString& FString::operator << (const UniChar& c)
|
2018-12-06 02:28:24 +01:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{static_cast<wchar_t>(c)};
|
2018-12-06 02:28:24 +01:00
|
|
|
_insert (length, s.length, s.string);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-09-20 02:51:17 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString& FString::operator << (const wchar_t c)
|
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{c};
|
2017-09-20 02:51:17 +02:00
|
|
|
_insert (length, s.length, s.string);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString& FString::operator << (const char c)
|
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{c};
|
2017-09-20 02:51:17 +02:00
|
|
|
_insert (length, s.length, s.string);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (FString& s) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
s._insert (s.length, length, string);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (std::wstring& s) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
s += std::wstring(string);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-03-03 22:24:57 +01:00
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (std::string& s) const
|
2018-03-03 22:24:57 +01:00
|
|
|
{
|
|
|
|
s += toString();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-09-20 02:51:17 +02:00
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (wchar_t& c) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
c = ( length > 0 ) ? string[0] : L'\0';
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (char& c) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
c = ( length > 0 ) ? char(string[0] & 0xff) : '\0';
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (sInt16& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toShort();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (uInt16& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toUShort();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (sInt32& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toInt();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (uInt32& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toUInt();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (sInt64& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toLong();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (uInt64& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toULong();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (double& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toDouble();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
const FString& FString::operator >> (float& num) const
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
num = toFloat();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 15:25:21 +02:00
|
|
|
FString::operator bool () const
|
|
|
|
{
|
|
|
|
return bool(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
const FString& FString::operator () () const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
// public methods of FString
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString FString::clear()
|
|
|
|
{
|
|
|
|
if ( string )
|
|
|
|
delete[](string);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
length = 0;
|
|
|
|
bufsize = 0;
|
2018-12-10 01:48:26 +01:00
|
|
|
string = nullptr;
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
const wchar_t* FString::wc_str() const
|
|
|
|
{
|
2017-12-17 01:06:53 +01:00
|
|
|
// Returns a constant wide character string
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
wchar_t* FString::wc_str()
|
|
|
|
{
|
|
|
|
// Returns a wide character string
|
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return string;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
const char* FString::c_str() const
|
|
|
|
{
|
2017-12-17 01:06:53 +01:00
|
|
|
// Returns a constant c-string
|
|
|
|
|
|
|
|
if ( length > 0 )
|
2020-05-26 21:37:39 +02:00
|
|
|
return _to_cstring(string);
|
2018-03-10 13:17:57 +01:00
|
|
|
else if ( string )
|
2020-05-26 21:37:39 +02:00
|
|
|
return "";
|
2017-12-17 01:06:53 +01:00
|
|
|
else
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2017-12-17 01:06:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
char* FString::c_str()
|
|
|
|
{
|
|
|
|
// Returns a c-string
|
|
|
|
|
2017-09-11 03:06:02 +02:00
|
|
|
if ( length > 0 )
|
2020-05-26 21:37:39 +02:00
|
|
|
return const_cast<char*>(_to_cstring(string));
|
2018-03-10 13:17:57 +01:00
|
|
|
else if ( string )
|
2020-10-14 17:31:52 +02:00
|
|
|
{
|
2020-10-14 23:43:34 +02:00
|
|
|
static char empty_string{'\0'};
|
|
|
|
return &empty_string;
|
2020-10-14 17:31:52 +02:00
|
|
|
}
|
2017-04-08 02:40:22 +02:00
|
|
|
else
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
std::string FString::toString() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2017-02-24 23:31:56 +01:00
|
|
|
return std::string(c_str(), length);
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::toLower() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2019-09-28 03:13:06 +02:00
|
|
|
auto to_lower = [] (wchar_t& c)
|
|
|
|
{
|
|
|
|
c = wchar_t(std::towlower(std::wint_t(c)));
|
|
|
|
};
|
|
|
|
std::for_each (s.begin(), s.end(), to_lower);
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::toUpper() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2019-09-28 03:13:06 +02:00
|
|
|
auto to_upper = [] (wchar_t& c)
|
|
|
|
{
|
|
|
|
c = wchar_t(std::towupper(std::wint_t(c)));
|
|
|
|
};
|
|
|
|
std::for_each (s.begin(), s.end(), to_upper);
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2015-06-30 09:29:49 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
sInt16 FString::toShort() const
|
|
|
|
{
|
2020-02-02 22:34:27 +01:00
|
|
|
const long num = toLong();
|
2015-06-30 09:29:49 +02:00
|
|
|
|
2018-03-05 00:25:05 +01:00
|
|
|
if ( num > SHRT_MAX )
|
2015-06-30 09:29:49 +02:00
|
|
|
throw std::overflow_error ("overflow");
|
|
|
|
|
2018-03-05 00:25:05 +01:00
|
|
|
if ( num < SHRT_MIN )
|
|
|
|
throw std::underflow_error ("underflow");
|
|
|
|
|
2015-06-30 09:29:49 +02:00
|
|
|
return sInt16(num);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
uInt16 FString::toUShort() const
|
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const uLong num = toULong();
|
2015-06-30 09:29:49 +02:00
|
|
|
|
|
|
|
if ( num > USHRT_MAX )
|
|
|
|
throw std::overflow_error ("overflow");
|
|
|
|
|
|
|
|
return uInt16(num);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FString::toInt() const
|
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const long num = toLong();
|
2015-06-30 09:29:49 +02:00
|
|
|
|
2018-03-05 00:25:05 +01:00
|
|
|
if ( num > INT_MAX )
|
2015-06-30 09:29:49 +02:00
|
|
|
throw std::overflow_error ("overflow");
|
|
|
|
|
2018-03-05 00:25:05 +01:00
|
|
|
if ( num < INT_MIN )
|
|
|
|
throw std::underflow_error ("underflow");
|
|
|
|
|
2015-06-30 09:29:49 +02:00
|
|
|
return int(num);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
uInt FString::toUInt() const
|
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const uLong num = toULong();
|
2015-06-30 09:29:49 +02:00
|
|
|
|
|
|
|
if ( num > UINT_MAX )
|
|
|
|
throw std::overflow_error ("overflow");
|
|
|
|
|
|
|
|
return uInt(num);
|
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
long FString::toLong() const
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
bool neg{false};
|
|
|
|
long num{0};
|
|
|
|
long tenth_limit{LONG_MAX / 10};
|
|
|
|
long tenth_limit_digit{LONG_MAX % 10};
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{trim()};
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* p = s.string;
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2015-06-28 20:23:39 +02:00
|
|
|
if ( ! p )
|
|
|
|
throw std::invalid_argument ("null value");
|
|
|
|
|
|
|
|
if ( ! *p )
|
|
|
|
throw std::invalid_argument ("empty value");
|
|
|
|
|
|
|
|
if ( *p == L'-' )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2015-06-28 20:23:39 +02:00
|
|
|
p++;
|
2017-09-11 22:50:07 +02:00
|
|
|
neg = true;
|
2015-06-28 20:23:39 +02:00
|
|
|
tenth_limit = -(LONG_MIN / 10);
|
|
|
|
tenth_limit_digit += 1;
|
|
|
|
}
|
|
|
|
else if ( *p == L'+' )
|
|
|
|
{
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
while ( std::iswdigit(std::wint_t(*p)) )
|
2015-06-28 20:23:39 +02:00
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
auto d = uChar(*p - L'0');
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-12-18 23:34:11 +01:00
|
|
|
if ( num > tenth_limit
|
2017-11-26 22:37:18 +01:00
|
|
|
|| (num == tenth_limit && d > tenth_limit_digit) )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2018-03-05 00:25:05 +01:00
|
|
|
if ( neg )
|
|
|
|
throw std::underflow_error ("underflow");
|
|
|
|
else
|
|
|
|
throw std::overflow_error ("overflow");
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-11 22:50:07 +02:00
|
|
|
num = (num << 3) + (num << 1) + d; // (10 * num) + d
|
2015-06-28 20:23:39 +02:00
|
|
|
p++;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
2015-06-28 20:23:39 +02:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
if ( *p != L'\0' && ! std::iswdigit(std::wint_t(*p)) )
|
2015-06-28 20:23:39 +02:00
|
|
|
throw std::invalid_argument ("no valid number");
|
|
|
|
|
2017-09-11 22:50:07 +02:00
|
|
|
if ( neg )
|
|
|
|
num = (~num) + 1;
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
uLong FString::toULong() const
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
uLong num{0};
|
2020-02-02 22:34:27 +01:00
|
|
|
const uLong tenth_limit{ULONG_MAX / 10};
|
|
|
|
const uLong tenth_limit_digit{ULONG_MAX % 10};
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{trim()};
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* p = s.string;
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2015-06-28 20:23:39 +02:00
|
|
|
if ( ! p )
|
|
|
|
throw std::invalid_argument ("null value");
|
|
|
|
|
|
|
|
if ( ! *p )
|
|
|
|
throw std::invalid_argument ("empty value");
|
|
|
|
|
2018-03-05 00:25:05 +01:00
|
|
|
if ( *p == L'-' )
|
|
|
|
{
|
|
|
|
throw std::underflow_error ("underflow");
|
|
|
|
}
|
|
|
|
else if ( *p == L'+' )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2015-06-28 20:23:39 +02:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
while ( std::iswdigit(std::wint_t(*p)) )
|
2015-06-28 20:23:39 +02:00
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const auto d = uChar(*p - L'0');
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-12-18 23:34:11 +01:00
|
|
|
if ( num > tenth_limit
|
2017-11-26 22:37:18 +01:00
|
|
|
|| (num == tenth_limit && d > tenth_limit_digit) )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2015-06-30 00:21:50 +02:00
|
|
|
throw std::overflow_error ("overflow");
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-10-02 07:32:33 +02:00
|
|
|
num = (num << 3) + (num << 1) + d; // (10 * num) + d
|
2015-06-28 20:23:39 +02:00
|
|
|
p++;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
2015-06-28 20:23:39 +02:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
if ( *p != L'\0' && ! std::iswdigit(std::wint_t(*p)) )
|
2015-06-28 20:23:39 +02:00
|
|
|
throw std::invalid_argument ("no valid number");
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2015-06-30 00:21:50 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
float FString::toFloat() const
|
|
|
|
{
|
2020-02-02 22:34:27 +01:00
|
|
|
const double num = toDouble();
|
2015-06-30 00:21:50 +02:00
|
|
|
|
2018-03-05 03:15:16 +01:00
|
|
|
if ( num > double(FLT_MAX) || num < double(-FLT_MAX) )
|
2015-06-30 00:21:50 +02:00
|
|
|
throw std::overflow_error ("overflow");
|
|
|
|
|
2018-09-12 22:51:15 +02:00
|
|
|
if ( std::fabs(num) < double(FLT_EPSILON) ) // num == 0.0f
|
2018-03-05 00:25:05 +01:00
|
|
|
throw std::underflow_error ("underflow");
|
|
|
|
|
2015-06-30 09:29:49 +02:00
|
|
|
return float(num);
|
2015-06-30 00:21:50 +02:00
|
|
|
}
|
|
|
|
|
2015-06-27 23:00:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
double FString::toDouble() const
|
|
|
|
{
|
2015-09-22 04:18:20 +02:00
|
|
|
if ( ! string )
|
2015-06-27 23:00:12 +02:00
|
|
|
throw std::invalid_argument ("null value");
|
|
|
|
|
2015-09-22 04:18:20 +02:00
|
|
|
if ( ! *string )
|
2015-06-28 20:23:39 +02:00
|
|
|
throw std::invalid_argument ("empty value");
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* p{};
|
2020-02-02 22:34:27 +01:00
|
|
|
const double ret = std::wcstod(string, &p);
|
2015-06-27 23:00:12 +02:00
|
|
|
|
2020-08-30 22:47:24 +02:00
|
|
|
if ( p != nullptr && *p != L'\0' )
|
2015-06-27 23:00:12 +02:00
|
|
|
throw std::invalid_argument ("no valid floating point value");
|
|
|
|
|
|
|
|
if ( errno == ERANGE )
|
|
|
|
{
|
|
|
|
if ( ret >= HUGE_VAL || ret <= -HUGE_VAL )
|
2015-06-30 00:21:50 +02:00
|
|
|
throw std::overflow_error ("overflow");
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-11 03:06:02 +02:00
|
|
|
if ( std::fabs(ret) < DBL_EPSILON ) // ret == 0.0l
|
2015-06-30 00:21:50 +02:00
|
|
|
throw std::underflow_error ("underflow");
|
2015-06-27 23:00:12 +02:00
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-06-27 23:00:12 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::ltrim() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{*this};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* p = s.string;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
while ( std::iswspace(std::wint_t(*p)) )
|
2015-05-23 13:35:12 +02:00
|
|
|
p++;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2020-05-02 00:07:35 +02:00
|
|
|
return p;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::rtrim() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* p = s.string;
|
|
|
|
wchar_t* last = p + length;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
while ( std::iswspace(std::wint_t(*--last)) && last > p )
|
2017-06-26 23:35:34 +02:00
|
|
|
s.length--;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
if ( last == p && std::iswspace(std::wint_t(*last)) )
|
2018-03-05 03:15:16 +01:00
|
|
|
s = L"";
|
2015-05-23 13:35:12 +02:00
|
|
|
else
|
2017-08-27 09:50:30 +02:00
|
|
|
*(last + 1) = '\0';
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::trim() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{ltrim()};
|
2015-05-23 13:35:12 +02:00
|
|
|
return s.rtrim();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::left (std::size_t len) const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( len > length )
|
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* p = s.string;
|
2017-06-26 23:35:34 +02:00
|
|
|
s.length = len;
|
2017-08-27 09:50:30 +02:00
|
|
|
*(p + len) = '\0';
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::right (std::size_t len) const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{*this};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( len > length )
|
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* p = s.string;
|
2017-08-27 09:50:30 +02:00
|
|
|
p += (length - len);
|
2020-05-02 00:07:35 +02:00
|
|
|
return p;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::mid (std::size_t pos, std::size_t len) const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{*this};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( pos == 0 )
|
|
|
|
pos = 1;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
if ( pos <= length && pos + len > length )
|
2015-05-23 13:35:12 +02:00
|
|
|
len = length - pos + 1;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
if ( pos > length || pos + len - 1 > length || len == 0 )
|
2020-05-02 00:07:35 +02:00
|
|
|
return FString{L""};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* p = s.string;
|
|
|
|
wchar_t* first = p + pos - 1;
|
2017-08-27 09:50:30 +02:00
|
|
|
*(first + len) = '\0';
|
2020-05-02 00:07:35 +02:00
|
|
|
return first;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-07-12 17:00:16 +02:00
|
|
|
FStringList FString::split (const FString& delimiter) const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString s{*this};
|
2019-08-25 22:16:00 +02:00
|
|
|
FStringList string_list{};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2017-09-20 16:56:20 +02:00
|
|
|
return string_list;
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* rest{nullptr};
|
2020-05-26 21:37:39 +02:00
|
|
|
const wchar_t* token = _extractToken(&rest, s.string, delimiter.wc_str());
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
while ( token )
|
|
|
|
{
|
2021-02-09 22:01:21 +01:00
|
|
|
string_list.emplace_back(token);
|
2020-05-26 21:37:39 +02:00
|
|
|
token = _extractToken (&rest, nullptr, delimiter.wc_str());
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-20 16:56:20 +02:00
|
|
|
return string_list;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-05 05:15:54 +02:00
|
|
|
FString& FString::setString (const FString& s)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2018-10-05 05:15:54 +02:00
|
|
|
_assign (s.string);
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-29 22:10:24 +01:00
|
|
|
FString& FString::setNumber (sInt64 num)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<wchar_t, 30> buf{};
|
2020-04-13 12:40:11 +02:00
|
|
|
wchar_t* s = &buf[29]; // Pointer to the last character
|
2020-10-04 00:59:21 +02:00
|
|
|
auto abs_num = static_cast<uInt64>(num);
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
if ( num < 0 )
|
2019-11-18 16:43:07 +01:00
|
|
|
abs_num = static_cast<uInt64>(-num);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
*s = '\0';
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
do
|
|
|
|
{
|
2019-11-17 22:06:07 +01:00
|
|
|
*--s = L"0123456789"[abs_num % 10];
|
|
|
|
abs_num /= 10;
|
2016-07-09 00:01:59 +02:00
|
|
|
}
|
2019-11-17 22:06:07 +01:00
|
|
|
while ( abs_num );
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2019-11-17 22:06:07 +01:00
|
|
|
if ( num < 0 )
|
2015-05-23 13:35:12 +02:00
|
|
|
*--s = '-';
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-04-17 22:49:42 +02:00
|
|
|
_assign (s);
|
2015-05-23 13:35:12 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-29 22:10:24 +01:00
|
|
|
FString& FString::setNumber (uInt64 num)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2019-10-01 23:14:00 +02:00
|
|
|
wchar_t buf[30]{};
|
2020-04-13 12:40:11 +02:00
|
|
|
wchar_t* s = &buf[29]; // Pointer to the last character
|
2015-05-23 13:35:12 +02:00
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2017-04-17 01:03:14 +02:00
|
|
|
*--s = L"0123456789"[num % 10];
|
2015-05-23 13:35:12 +02:00
|
|
|
num /= 10;
|
2016-07-09 00:01:59 +02:00
|
|
|
}
|
|
|
|
while ( num );
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2017-04-17 22:49:42 +02:00
|
|
|
_assign (s);
|
2015-05-23 13:35:12 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-29 22:10:24 +01:00
|
|
|
FString& FString::setNumber (lDouble f_num, int precision)
|
2015-06-27 23:00:12 +02:00
|
|
|
{
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<wchar_t, 20> format{}; // = "%.<precision>Lg"
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* s = &format[0];
|
2015-06-27 23:00:12 +02:00
|
|
|
*s++ = L'%';
|
|
|
|
*s++ = L'.';
|
|
|
|
|
2017-09-20 02:51:17 +02:00
|
|
|
// The precision can not have more than 2 digits
|
2015-06-27 23:00:12 +02:00
|
|
|
if ( precision > 99 )
|
|
|
|
precision = 99;
|
|
|
|
|
|
|
|
if ( precision >= 10 )
|
|
|
|
{
|
2017-09-20 02:51:17 +02:00
|
|
|
// The precision value is 2 digits long
|
2015-06-27 23:00:12 +02:00
|
|
|
*s++ = precision / 10 + L'0';
|
|
|
|
*s++ = precision % 10 + L'0';
|
|
|
|
}
|
|
|
|
else
|
2017-09-20 02:51:17 +02:00
|
|
|
{
|
|
|
|
// The precision value has only 1 digit
|
2015-06-27 23:00:12 +02:00
|
|
|
*s++ = precision + L'0';
|
2017-09-20 02:51:17 +02:00
|
|
|
}
|
2015-06-27 23:00:12 +02:00
|
|
|
|
|
|
|
*s++ = L'L';
|
|
|
|
*s++ = L'g';
|
2017-09-20 02:51:17 +02:00
|
|
|
*s = L'\0';
|
|
|
|
|
2020-10-14 17:31:52 +02:00
|
|
|
return sprintf(format.data(), f_num);
|
2015-06-27 23:00:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-29 22:10:24 +01:00
|
|
|
FString& FString::setFormatedNumber (sInt64 num, char separator)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
int n{0};
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<wchar_t, 30> buf{};
|
2020-04-13 12:40:11 +02:00
|
|
|
wchar_t* s = &buf[29]; // Pointer to the last character
|
2020-10-04 00:59:21 +02:00
|
|
|
auto abs_num = static_cast<uInt64>(num);
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2016-05-24 22:30:01 +02:00
|
|
|
if ( separator == 0 )
|
|
|
|
separator = ' ';
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( num < 0 )
|
2019-11-18 16:43:07 +01:00
|
|
|
abs_num = static_cast<uInt64>(-num);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
*s = L'\0';
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
do
|
|
|
|
{
|
2019-11-17 22:06:07 +01:00
|
|
|
*--s = L"0123456789"[abs_num % 10];
|
|
|
|
abs_num /= 10;
|
2020-04-13 12:40:11 +02:00
|
|
|
n++;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2020-04-13 12:40:11 +02:00
|
|
|
if ( abs_num && n % 3 == 0 )
|
2015-05-23 13:35:12 +02:00
|
|
|
*--s = separator;
|
2016-07-09 00:01:59 +02:00
|
|
|
}
|
2019-11-17 22:06:07 +01:00
|
|
|
while ( abs_num );
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2019-11-17 22:06:07 +01:00
|
|
|
if ( num < 0 )
|
2015-05-23 13:35:12 +02:00
|
|
|
*--s = '-';
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-04-17 22:49:42 +02:00
|
|
|
_assign (s);
|
2015-05-23 13:35:12 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-29 22:10:24 +01:00
|
|
|
FString& FString::setFormatedNumber (uInt64 num, char separator)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
int n{0};
|
2019-10-01 23:14:00 +02:00
|
|
|
wchar_t buf[30]{};
|
2020-04-13 12:40:11 +02:00
|
|
|
wchar_t* s = &buf[29]; // Pointer to the last character
|
2015-05-23 13:35:12 +02:00
|
|
|
*s = L'\0';
|
|
|
|
|
2016-05-24 22:30:01 +02:00
|
|
|
if ( separator == 0 )
|
|
|
|
separator = ' ';
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
do
|
|
|
|
{
|
2017-04-17 01:03:14 +02:00
|
|
|
*--s = L"0123456789"[num % 10];
|
2015-05-23 13:35:12 +02:00
|
|
|
num /= 10;
|
2020-04-13 12:40:11 +02:00
|
|
|
n++;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2020-04-13 12:40:11 +02:00
|
|
|
if ( num && n % 3 == 0 )
|
2015-05-23 13:35:12 +02:00
|
|
|
*--s = separator;
|
2016-07-09 00:01:59 +02:00
|
|
|
}
|
|
|
|
while ( num );
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2017-04-17 22:49:42 +02:00
|
|
|
_assign (s);
|
2015-05-23 13:35:12 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FString operators
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FString::operator < (const FString& s) const
|
|
|
|
{
|
|
|
|
if ( string && ! s.string )
|
|
|
|
return false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! string && s.string )
|
|
|
|
return true;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string || s.string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return ( std::wcscmp(string, s.string) < 0 );
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FString::operator <= (const FString& s) const
|
|
|
|
{
|
2018-02-28 23:52:34 +01:00
|
|
|
if ( ! (string || s.string) )
|
|
|
|
return true;
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( string && ! s.string )
|
|
|
|
return false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! string && s.string )
|
|
|
|
return true;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return ( std::wcscmp(string, s.string) <= 0 );
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FString::operator == (const FString& s) const
|
|
|
|
{
|
2018-02-25 21:42:18 +01:00
|
|
|
if ( ! (string || s.string) )
|
|
|
|
return true;
|
|
|
|
|
2019-02-24 20:21:12 +01:00
|
|
|
if ( bool(string) != bool(s.string) || length != s.length )
|
2015-05-23 13:35:12 +02:00
|
|
|
return false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return ( std::wcscmp(string, s.string) == 0 );
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FString::operator != (const FString& s) const
|
|
|
|
{
|
2020-07-06 19:32:01 +02:00
|
|
|
return ! ( *this == s );
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FString::operator >= (const FString& s) const
|
|
|
|
{
|
|
|
|
if ( string && ! s.string )
|
|
|
|
return true;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! string && s.string )
|
|
|
|
return false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string || s.string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return true;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return ( std::wcscmp(string, s.string) >= 0 );
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FString::operator > (const FString& s) const
|
|
|
|
{
|
2018-03-01 00:00:30 +01:00
|
|
|
if ( ! (string || s.string) )
|
|
|
|
return false;
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( string && ! s.string )
|
|
|
|
return true;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! string && s.string )
|
|
|
|
return false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return ( std::wcscmp(string, s.string) > 0 );
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-05 05:15:54 +02:00
|
|
|
const FString& FString::insert (const FString& s, int pos)
|
2015-12-18 21:47:19 +01:00
|
|
|
{
|
2018-10-26 07:43:23 +02:00
|
|
|
if ( isNegative(pos) || uInt(pos) > length )
|
2015-05-23 13:35:12 +02:00
|
|
|
throw std::out_of_range("");
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2018-10-05 05:15:54 +02:00
|
|
|
_insert (uInt(pos), s.length, s.string);
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
const FString& FString::insert (const FString& s, std::size_t pos)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2018-03-07 00:48:06 +01:00
|
|
|
if ( pos > length )
|
2015-05-23 13:35:12 +02:00
|
|
|
throw std::out_of_range("");
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2018-10-05 05:15:54 +02:00
|
|
|
_insert (pos, s.length, s.string);
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::replace (const FString& from, const FString& to) const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
// handle NULL and empty string
|
2016-08-21 21:27:44 +02:00
|
|
|
if ( ! (string && *string) )
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( from.isNull() || to.isNull() )
|
|
|
|
return s;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2018-03-14 00:53:28 +01:00
|
|
|
if ( from.isEmpty() )
|
2018-03-08 17:57:17 +01:00
|
|
|
return s;
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* p = s.string;
|
2020-02-02 22:34:27 +01:00
|
|
|
const std::size_t from_length = from.getLength();
|
|
|
|
const std::size_t to_length = to.getLength();
|
2019-08-25 22:16:00 +02:00
|
|
|
std::size_t pos{0};
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
while ( *p )
|
|
|
|
{
|
2016-10-06 23:15:09 +02:00
|
|
|
if ( std::wcsncmp(p, from.string, from_length) == 0 )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
|
|
|
s._remove(pos, from_length);
|
|
|
|
s._insert(pos, to_length, to.string);
|
|
|
|
pos += to_length;
|
|
|
|
p = s.string + pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos++;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
2017-06-26 23:35:34 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::replaceControlCodes() const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
for (auto&& c : s)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
if ( c <= L'\x1f' )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
c += L'\x2400';
|
|
|
|
}
|
|
|
|
else if ( c == L'\x7f' )
|
|
|
|
{
|
|
|
|
c = L'\x2421';
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2019-09-28 03:13:06 +02:00
|
|
|
else if ( c >= L'\x80' && c <= L'\x9f' )
|
|
|
|
{
|
|
|
|
c = L' ';
|
|
|
|
}
|
|
|
|
else if ( ! std::iswprint(std::wint_t(c)) )
|
|
|
|
c = L' ';
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString FString::expandTabs (int tabstop) const
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString instr{string};
|
2019-08-25 22:16:00 +02:00
|
|
|
FString outstr{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2017-03-26 20:40:04 +02:00
|
|
|
if ( tabstop <= 0 )
|
|
|
|
return instr;
|
|
|
|
|
2020-02-02 22:34:27 +01:00
|
|
|
const FStringList tab_split = instr.split("\t");
|
|
|
|
const uLong last = tab_split.size();
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
for (std::size_t i{0}; i < last; i++)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const auto len = tab_split[i].getLength();
|
|
|
|
const auto tab_len = std::size_t(tabstop);
|
2018-10-14 06:25:33 +02:00
|
|
|
|
2018-03-08 17:57:17 +01:00
|
|
|
if ( i == last - 1 )
|
|
|
|
outstr += tab_split[i];
|
|
|
|
else
|
|
|
|
outstr += tab_split[i] + FString(tab_len - (len % tab_len), L' ');
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return outstr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString FString::removeDel() const
|
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2019-09-28 03:13:06 +02:00
|
|
|
std::size_t i{0};
|
|
|
|
std::size_t count{0};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
for (auto&& c : s)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
if ( c == 0x7f )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
else if ( count > 0 )
|
|
|
|
{
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
else // count == 0
|
|
|
|
{
|
|
|
|
s.string[i] = c;
|
|
|
|
i++;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
s.string[i] = L'\0';
|
|
|
|
s.length = i;
|
2016-11-02 00:37:58 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString FString::removeBackspaces() const
|
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString s{*this};
|
2019-09-28 03:13:06 +02:00
|
|
|
std::size_t i{0};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
for (auto&& c : s)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
if ( c != L'\b' )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
s.string[i] = c;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else if ( i > 0 )
|
|
|
|
{
|
|
|
|
i--;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
s.string[i] = L'\0';
|
|
|
|
s.length = i;
|
2016-11-02 00:37:58 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2018-03-10 05:27:55 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
const FString& FString::overwrite (const FString& s, int pos)
|
|
|
|
{
|
|
|
|
if ( pos < 0 )
|
|
|
|
return overwrite (s, 0);
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
return overwrite (s, std::size_t(pos));
|
2018-03-10 05:27:55 +01:00
|
|
|
}
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
const FString& FString::overwrite (const FString& s, std::size_t pos)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2018-03-10 05:27:55 +01:00
|
|
|
if ( pos > length )
|
|
|
|
pos = length;
|
|
|
|
|
2017-10-06 12:19:39 +02:00
|
|
|
if ( length >= (pos + s.length) )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
std::wcsncpy (string + pos, s.string, s.length);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::wcsncpy (string + pos, s.string, length - pos);
|
|
|
|
_insert (length, pos + s.length - length, s.string + length - pos);
|
|
|
|
}
|
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
2018-03-10 05:27:55 +01:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
const FString& FString::remove (std::size_t pos, std::size_t len)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2018-03-10 05:27:55 +01:00
|
|
|
if ( pos > length )
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
if ( pos + len > length )
|
|
|
|
len = length - pos;
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
_remove (pos, len);
|
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
return *this;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-03-10 05:27:55 +01:00
|
|
|
bool FString::includes (const FString& s) const
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2018-03-10 05:27:55 +01:00
|
|
|
if ( ! s )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( ! (string && s.string) )
|
2018-02-25 21:42:18 +01:00
|
|
|
return false;
|
|
|
|
|
2020-02-19 21:59:13 +01:00
|
|
|
return ( std::wcsstr(string, s.string) != nullptr );
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// private methods of FString
|
|
|
|
//----------------------------------------------------------------------
|
2020-05-26 21:37:39 +02:00
|
|
|
inline void FString::_initLength (std::size_t len)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
if ( len == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
length = len;
|
|
|
|
bufsize = FWDBUFFER + len + 1;
|
2017-08-12 22:55:29 +02:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
string = new wchar_t[bufsize];
|
2017-08-12 22:55:29 +02:00
|
|
|
std::wmemset (string, L'\0', bufsize);
|
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2017-08-12 22:55:29 +02:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("wchar_t[bufsize]");
|
2017-08-12 22:55:29 +02:00
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-09-28 03:13:06 +02:00
|
|
|
void FString::_assign (const wchar_t s[])
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2018-03-05 22:26:44 +01:00
|
|
|
if ( ! s )
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-10 13:17:57 +01:00
|
|
|
if ( string && std::wcscmp(string, s) == 0 )
|
|
|
|
return; // string == s
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2020-04-25 02:32:33 +02:00
|
|
|
std::size_t new_length{std::wcslen(s)};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2018-10-27 00:13:31 +02:00
|
|
|
if ( ! string || new_length > capacity() )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2017-04-17 22:49:42 +02:00
|
|
|
if ( string )
|
|
|
|
delete[](string);
|
|
|
|
|
|
|
|
bufsize = FWDBUFFER + new_length + 1;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
string = new wchar_t[bufsize];
|
2017-04-17 22:49:42 +02:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2017-04-17 22:49:42 +02:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("wchar_t[bufsize]");
|
2017-04-17 22:49:42 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2017-04-17 22:49:42 +02:00
|
|
|
|
2017-04-11 00:30:27 +02:00
|
|
|
std::wcsncpy (string, s, bufsize);
|
2017-04-17 22:49:42 +02:00
|
|
|
length = new_length;
|
2018-10-27 00:13:31 +02:00
|
|
|
string[capacity()] = L'\0';
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-09-28 03:13:06 +02:00
|
|
|
void FString::_insert (std::size_t len, const wchar_t s[])
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2017-10-15 23:22:13 +02:00
|
|
|
if ( len == 0 ) // String s is a null or a empty string
|
|
|
|
return;
|
|
|
|
|
2018-10-02 01:03:44 +02:00
|
|
|
if ( string )
|
|
|
|
delete[](string);
|
2017-09-20 05:44:41 +02:00
|
|
|
|
2018-10-02 01:03:44 +02:00
|
|
|
length = len;
|
|
|
|
bufsize = FWDBUFFER + length + 1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2018-10-02 01:03:44 +02:00
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
string = new wchar_t[bufsize];
|
2018-10-02 01:03:44 +02:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2018-10-02 01:03:44 +02:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("wchar_t[bufsize]");
|
2018-10-02 01:03:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::wcsncpy (string, s, bufsize);
|
2018-10-27 00:13:31 +02:00
|
|
|
string[capacity()] = L'\0';
|
2018-10-02 01:03:44 +02:00
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2018-10-02 01:03:44 +02:00
|
|
|
//----------------------------------------------------------------------
|
2019-09-28 03:13:06 +02:00
|
|
|
void FString::_insert ( std::size_t pos
|
|
|
|
, std::size_t len
|
|
|
|
, const wchar_t s[] )
|
2018-10-02 01:03:44 +02:00
|
|
|
{
|
|
|
|
if ( len == 0 ) // String s is a null or a empty string
|
2016-11-02 00:37:58 +01:00
|
|
|
return;
|
2018-10-02 01:03:44 +02:00
|
|
|
|
|
|
|
if ( ! string ) // string is null
|
|
|
|
{
|
|
|
|
_insert (len, s);
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
std::size_t x{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2018-10-27 00:13:31 +02:00
|
|
|
if ( length + len <= capacity() )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
// output string <= bufsize
|
2017-10-15 23:22:13 +02:00
|
|
|
for (x = length; x + 1 > pos; x--) // shifting right side + '\0'
|
2017-08-27 09:50:30 +02:00
|
|
|
string[x + len] = string[x];
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
for (x = 0; x < len; x++) // insert string
|
|
|
|
string[x + pos] = s[x];
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
length += len;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// output string > bufsize
|
|
|
|
bufsize = FWDBUFFER + length + len + 1;
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* sptr{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
sptr = new wchar_t[bufsize]; // generate new string
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("wchar_t[bufsize]");
|
2016-11-02 00:37:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
std::size_t y{0};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
for (x = 0; x < pos; x++) // left side
|
2016-11-02 00:37:58 +01:00
|
|
|
sptr[y++] = string[x];
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
for (x = 0 ; x < len; x++) // insert string
|
2016-11-02 00:37:58 +01:00
|
|
|
sptr[y++] = s[x];
|
|
|
|
|
2017-12-02 18:52:51 +01:00
|
|
|
for (x = pos; x < length + 1; x++) // right side + '\0'
|
2016-11-02 00:37:58 +01:00
|
|
|
sptr[y++] = string[x];
|
|
|
|
|
|
|
|
length += len;
|
2017-08-27 09:50:30 +02:00
|
|
|
delete[](string); // delete old string
|
2016-11-02 00:37:58 +01:00
|
|
|
string = sptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-09-28 03:13:06 +02:00
|
|
|
void FString::_remove (std::size_t pos, std::size_t len)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2018-10-27 00:13:31 +02:00
|
|
|
if ( capacity() - length + len <= FWDBUFFER )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
// shifting left side to pos
|
2018-10-14 06:25:33 +02:00
|
|
|
for (std::size_t i = pos; i + len < length + 1; i++)
|
2017-08-27 09:50:30 +02:00
|
|
|
string[i] = string[i + len];
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
length -= len;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bufsize = length + 1 - len + FWDBUFFER;
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* sptr{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
sptr = new wchar_t[bufsize]; // generate new string
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("wchar_t[bufsize]");
|
2016-11-02 00:37:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-13 12:40:11 +02:00
|
|
|
std::size_t x{};
|
|
|
|
std::size_t y{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
for (x = 0; x < pos; x++) // left side
|
2016-11-02 00:37:58 +01:00
|
|
|
sptr[y++] = string[x];
|
|
|
|
|
2017-12-02 18:52:51 +01:00
|
|
|
for (x = pos + len; x < length + 1; x++) // right side + '\0'
|
2016-11-02 00:37:58 +01:00
|
|
|
sptr[y++] = string[x];
|
|
|
|
|
|
|
|
delete[](string); // delete old string
|
|
|
|
string = sptr;
|
|
|
|
length -= len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-05-26 21:37:39 +02:00
|
|
|
inline const char* FString::_to_cstring (const wchar_t s[]) const
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
if ( ! s ) // handle NULL string
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
if ( ! *s ) // handle empty string
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Generate a empty string ("")
|
|
|
|
c_string = new char[1]();
|
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("char[1]");
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return c_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( c_string )
|
|
|
|
delete[](c_string);
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
const wchar_t* src = s;
|
2020-08-12 22:28:02 +02:00
|
|
|
auto state = std::mbstate_t();
|
|
|
|
auto size = std::wcsrtombs(nullptr, &src, 0, &state) + 1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
c_string = new char[size];
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
// pre-initialiaze the whole string with '\0'
|
2020-08-12 22:28:02 +02:00
|
|
|
std::memset (c_string, '\0', size);
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-08-12 22:28:02 +02:00
|
|
|
badAllocOutput ("char[size]");
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
2020-08-12 22:28:02 +02:00
|
|
|
const auto mblength = std::wcsrtombs (c_string, &src, size, &state);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2020-08-12 22:28:02 +02:00
|
|
|
if ( mblength == static_cast<std::size_t>(-1) && errno != EILSEQ )
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
delete[](c_string);
|
2018-12-10 01:48:26 +01:00
|
|
|
c_string = nullptr;
|
2020-05-26 21:37:39 +02:00
|
|
|
return "";
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return c_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-05-26 21:37:39 +02:00
|
|
|
inline const wchar_t* FString::_to_wcstring (const char s[]) const
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
|
|
|
if ( ! s ) // handle NULL string
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
|
|
if ( ! *s ) // handle empty string
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Generate a empty wide string (L"")
|
2017-09-17 21:32:46 +02:00
|
|
|
return new wchar_t[1]();
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-05-13 23:47:14 +02:00
|
|
|
badAllocOutput ("wchar_t[1]");
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
const char* src = s;
|
|
|
|
wchar_t* dest{};
|
2020-08-12 22:28:02 +02:00
|
|
|
auto state = std::mbstate_t();
|
|
|
|
auto size = std::mbsrtowcs(nullptr, &src, 0, &state) + 1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
2020-12-03 10:43:20 +01:00
|
|
|
if ( size == 0 ) // ...malformed UTF-8 string
|
|
|
|
return nullptr;
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
try
|
|
|
|
{
|
2020-09-18 17:13:52 +02:00
|
|
|
dest = new wchar_t[size];
|
2016-11-02 00:37:58 +01:00
|
|
|
// pre-initialiaze the whole string with '\0'
|
2020-08-12 22:28:02 +02:00
|
|
|
std::wmemset (dest, L'\0', size);
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
2020-05-13 23:47:14 +02:00
|
|
|
catch (const std::bad_alloc&)
|
2016-11-02 00:37:58 +01:00
|
|
|
{
|
2020-08-12 22:28:02 +02:00
|
|
|
badAllocOutput ("wchar_t[size]");
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2016-11-02 00:37:58 +01:00
|
|
|
}
|
|
|
|
|
2020-08-12 22:28:02 +02:00
|
|
|
const auto wclength = std::mbsrtowcs (dest, &src, size, &state);
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2020-08-12 22:28:02 +02:00
|
|
|
if ( wclength == static_cast<std::size_t>(-1) )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2016-11-02 00:37:58 +01:00
|
|
|
if ( src != s )
|
|
|
|
return dest;
|
|
|
|
else
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2016-11-02 00:37:58 +01:00
|
|
|
delete[] dest;
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
if ( wclength == size )
|
2017-08-27 09:50:30 +02:00
|
|
|
dest[size - 1] = '\0';
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
if ( wclength )
|
|
|
|
return dest;
|
|
|
|
else
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2016-11-02 00:37:58 +01:00
|
|
|
delete[] dest;
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2020-05-26 21:37:39 +02:00
|
|
|
inline const wchar_t* FString::_extractToken ( wchar_t* rest[]
|
|
|
|
, const wchar_t s[]
|
2020-07-12 15:25:21 +02:00
|
|
|
, const wchar_t delim[] ) const
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
wchar_t* token = ( s ) ? const_cast<wchar_t*>(s) : *rest;
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2018-03-14 00:53:28 +01:00
|
|
|
if ( ! token )
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2018-03-14 00:53:28 +01:00
|
|
|
|
|
|
|
if ( ! token[0] )
|
2020-02-19 21:59:13 +01:00
|
|
|
return nullptr;
|
2015-05-23 13:35:12 +02:00
|
|
|
|
2020-11-01 20:11:36 +01:00
|
|
|
*rest = std::wcspbrk(token, delim);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
if ( *rest )
|
|
|
|
*(*rest)++ = '\0';
|
|
|
|
else
|
|
|
|
*rest = token + std::wcslen(token);
|
|
|
|
return token;
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
// FString non-member operators
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
2020-10-04 00:59:21 +02:00
|
|
|
FString operator + (const FString& s1, const FString& s2)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
FString tmp{s1};
|
2020-09-11 00:08:22 +02:00
|
|
|
tmp._insert (tmp.length, s2.length, s2.wc_str());
|
2017-09-17 21:32:46 +02:00
|
|
|
return tmp;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
2017-09-20 02:51:17 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
std::ostream& operator << (std::ostream& outstr, const FString& s)
|
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const auto width = std::size_t(outstr.width());
|
2019-09-29 22:28:58 +02:00
|
|
|
|
2018-03-10 13:17:57 +01:00
|
|
|
if ( s.length > 0 )
|
2019-09-29 22:28:58 +02:00
|
|
|
{
|
2020-05-26 21:37:39 +02:00
|
|
|
outstr << s._to_cstring(s.string);
|
2019-09-29 22:28:58 +02:00
|
|
|
}
|
|
|
|
else if ( width > 0 )
|
|
|
|
{
|
2020-05-03 13:45:47 +02:00
|
|
|
const FString fill_str{width, wchar_t(outstr.fill())};
|
2020-05-26 21:37:39 +02:00
|
|
|
outstr << s._to_cstring(fill_str.string);
|
2019-09-29 22:28:58 +02:00
|
|
|
}
|
2017-09-20 02:51:17 +02:00
|
|
|
|
|
|
|
return outstr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
std::istream& operator >> (std::istream& instr, FString& s)
|
|
|
|
{
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<char, FString::INPBUFFER + 1> buf{};
|
|
|
|
instr.getline (buf.data(), FString::INPBUFFER);
|
|
|
|
const wchar_t* wc_str = s._to_wcstring(buf.data());
|
2017-09-20 02:51:17 +02:00
|
|
|
|
|
|
|
if ( wc_str )
|
|
|
|
{
|
|
|
|
s._assign (wc_str);
|
|
|
|
delete[] wc_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
return instr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
std::wostream& operator << (std::wostream& outstr, const FString& s)
|
|
|
|
{
|
2020-10-04 00:59:21 +02:00
|
|
|
const auto width = std::size_t(outstr.width());
|
2019-09-29 22:28:58 +02:00
|
|
|
|
2018-03-10 13:17:57 +01:00
|
|
|
if ( s.length > 0 )
|
2019-09-29 22:28:58 +02:00
|
|
|
{
|
2017-09-20 02:51:17 +02:00
|
|
|
outstr << s.string;
|
2019-09-29 22:28:58 +02:00
|
|
|
}
|
|
|
|
else if ( width > 0 )
|
|
|
|
{
|
2020-05-02 00:07:35 +02:00
|
|
|
const FString fill_str{width, outstr.fill()};
|
2019-09-29 22:28:58 +02:00
|
|
|
outstr << fill_str.string;
|
|
|
|
}
|
2017-09-20 02:51:17 +02:00
|
|
|
|
|
|
|
return outstr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
std::wistream& operator >> (std::wistream& instr, FString& s)
|
|
|
|
{
|
2020-10-14 17:31:52 +02:00
|
|
|
std::array<wchar_t, FString::INPBUFFER + 1> buf{};
|
|
|
|
instr.getline (buf.data(), FString::INPBUFFER);
|
|
|
|
s._assign (buf.data());
|
2017-09-20 02:51:17 +02:00
|
|
|
return instr;
|
|
|
|
}
|
2018-09-20 23:59:01 +02:00
|
|
|
|
|
|
|
} // namespace finalcut
|