4#include "Stroika/Foundation/StroikaPreComp.h"
7DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wformat-truncation\"");
9DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wformat-truncation\"");
13#if qCompilerAndStdLib_vswprintf_errantDependencyOnLocale_Buggy
18#if qCompilerAndStdLib_vswprintf_errantDependencyOnLocale_Buggy
22#include "Stroika/Foundation/Math/Common.h"
29using namespace Stroika::Foundation::Characters::CString;
36string Characters::CString::FormatV (
const char* format, va_list argsList)
44 va_copy (argListCopy, argsList);
46#if __STDC_WANT_SECURE_LIB__
47 while (::vsnprintf_s (msgBuf.data (), msgBuf.GetSize (), msgBuf.GetSize () - 1, format, argListCopy) < 0) {
48 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
50 va_copy (argListCopy, argsList);
53 while (vsnprintf (msgBuf.data (), msgBuf.GetSize (), format, argListCopy) < 0) {
54 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
56 va_copy (argListCopy, argsList);
60 Assert (::strlen (msgBuf.data ()) < msgBuf.GetSize ());
61 return string{msgBuf.data ()};
64u8string Characters::CString::FormatV (
const char8_t* format, va_list argsList)
72 va_copy (argListCopy, argsList);
74#if __STDC_WANT_SECURE_LIB__
75 while (::vsnprintf_s (
reinterpret_cast<char*
> (msgBuf.data ()), msgBuf.GetSize (), msgBuf.GetSize () - 1,
76 reinterpret_cast<const char*
> (format), argListCopy) < 0) {
77 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
79 va_copy (argListCopy, argsList);
82 while (vsnprintf (
reinterpret_cast<char*
> (msgBuf.data ()), msgBuf.GetSize (),
reinterpret_cast<const char*
> (format), argListCopy) < 0) {
83 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
85 va_copy (argListCopy, argsList);
89 Assert (::strlen (
reinterpret_cast<char*
> (msgBuf.data ())) < msgBuf.GetSize ());
90 return u8string{msgBuf.data ()};
94#if qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
95Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
98 Characters::CString::FormatV (
const wchar_t* format, va_list argsList)
102 const wchar_t* useFormat = format;
103 wchar_t newFormat[5 * 1024];
105 size_t origFormatLen = ::wcslen (format);
106 Require (origFormatLen < Memory::NEltsOf (newFormat) / 2);
108 bool lookingAtFmtCvt =
false;
109 size_t newFormatIdx = 0;
110 for (
size_t i = 0; i < origFormatLen; ++i) {
111 if (lookingAtFmtCvt) {
114 lookingAtFmtCvt =
false;
117 newFormat[newFormatIdx] =
'l';
124 if (isdigit (format[i])) {
128 lookingAtFmtCvt =
false;
134 if (format[i] ==
'%') {
135 lookingAtFmtCvt =
true;
138 newFormat[newFormatIdx] = format[i];
141 Assert (newFormatIdx >= origFormatLen);
142 if (newFormatIdx > origFormatLen) {
143 newFormat[newFormatIdx] =
'\0';
144 useFormat = newFormat;
152 va_copy (argListCopy, argsList);
154#if qCompilerAndStdLib_vswprintf_errantDependencyOnLocale_Buggy
155 locale_t tmpLocale{};
156 locale_t prevLocale{};
157 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([&tmpLocale, &prevLocale] ()
noexcept {
158 if (prevLocale !=
nullptr) {
159 ::uselocale (prevLocale);
161 if (tmpLocale !=
nullptr) {
162 ::freelocale (tmpLocale);
169 while (::vswprintf (msgBuf.data (), msgBuf.GetSize (), useFormat, argListCopy) < 0) {
170#if qCompilerAndStdLib_vswprintf_errantDependencyOnLocale_Buggy
171 if (errno == EILSEQ and tmpLocale ==
nullptr) {
172 tmpLocale = ::newlocale (LC_CTYPE,
"en_US.UTF-8", NULL);
173 prevLocale = ::uselocale (tmpLocale);
177 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
178 va_end (argListCopy);
179 va_copy (argListCopy, argsList);
181 va_end (argListCopy);
182 Assert (::wcslen (msgBuf.data ()) < msgBuf.GetSize ());
183 return wstring{msgBuf.data ()};
185DISABLE_COMPILER_MSC_WARNING_END (6262)
192string Characters::CString::Format (const
char* format, ...)
195 va_start (argsList, format);
196 string tmp = FormatV (format, argsList);
201u8string Characters::CString::Format (
const char8_t* format, ...)
204 va_start (argsList, format);
205 u8string tmp = FormatV (format, argsList);
210wstring Characters::CString::Format (
const wchar_t* format, ...)
213 va_start (argsList, format);
214 wstring tmp = FormatV (format, argsList);
225 template <
typename STRING>
226 inline STRING LimitLength_HLPR_ (
const STRING& str,
size_t maxLen,
bool keepLeft,
const STRING& kELIPSIS)
228 if (str.length () <= maxLen) {
231 size_t useLen = maxLen;
232 if (useLen > kELIPSIS.length ()) {
233 useLen -= kELIPSIS.length ();
239 return str.substr (0, useLen) + kELIPSIS;
242 return kELIPSIS + str.substr (str.length () - useLen);
246string Characters::CString::LimitLength (
const string& str,
size_t maxLen,
bool keepLeft)
248 return LimitLength_HLPR_<string> (str, maxLen, keepLeft,
"...");
251wstring Characters::CString::LimitLength (
const wstring& str,
size_t maxLen,
bool keepLeft)
253 return LimitLength_HLPR_<wstring> (str, maxLen, keepLeft, L
"...");
262 template <
typename STRING>
263 inline STRING StripTrailingCharIfAny_HLPR_ (
const STRING& str,
typename STRING::value_type c)
265 if (str.size () > 0 and str[str.size () - 1] == c) {
267 tmp.erase (tmp.size () - 1);
274string Characters::CString::StripTrailingCharIfAny (
const string& s,
char c)
276 return StripTrailingCharIfAny_HLPR_ (s, c);
279wstring Characters::CString::StripTrailingCharIfAny (
const wstring& s,
wchar_t c)
281 return StripTrailingCharIfAny_HLPR_ (s, c);
289unsigned int Characters::CString::HexString2Int (
const string& s)
291 unsigned long l = strtoul (s.c_str (),
nullptr, 16);
292 if (l >= numeric_limits<unsigned int>::max ()) {
293 return numeric_limits<unsigned int>::max ();
298unsigned int Characters::CString::HexString2Int (
const wchar_t* s)
301 unsigned long l = wcstoul (s,
nullptr, 16);
302 if (l >= numeric_limits<unsigned int>::max ()) {
303 return numeric_limits<unsigned int>::max ();
308unsigned int Characters::CString::HexString2Int (
const wstring& s)
310 unsigned long l = wcstoul (s.c_str (),
nullptr, 16);
311 if (l >= numeric_limits<unsigned int>::max ()) {
312 return numeric_limits<unsigned int>::max ();
322long long int Characters::CString::Private_::String2Int_ (
const string& s)
325 return strtoll (s.c_str (),
nullptr, 10);
328long long int Characters::CString::Private_::String2Int_ (
const wstring& s)
330 unsigned long long int l = wcstoll (s.c_str (),
nullptr, 10);
339unsigned long long int Characters::CString::Private_::String2UInt_ (
const string& s)
342 unsigned long long int l = strtoull (s.c_str (),
nullptr, 10);
346unsigned long long int Characters::CString::Private_::String2UInt_ (
const wstring& s)
348 long long int l = wcstoull (s.c_str (),
nullptr, 10);
#define RequireNotNull(p)
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
DISABLE_COMPILER_MSC_WARNING_START(4996)
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >