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
97 wstring Characters::CString::FormatV (
const wchar_t* format, va_list argsList)
101 const wchar_t* useFormat = format;
102 wchar_t newFormat[5 * 1024];
104 size_t origFormatLen = ::wcslen (format);
105 Require (origFormatLen < std::size (newFormat) / 2);
107 bool lookingAtFmtCvt =
false;
108 size_t newFormatIdx = 0;
109 for (
size_t i = 0; i < origFormatLen; ++i) {
110 if (lookingAtFmtCvt) {
113 lookingAtFmtCvt =
false;
116 newFormat[newFormatIdx] =
'l';
123 if (isdigit (format[i])) {
127 lookingAtFmtCvt =
false;
133 if (format[i] ==
'%') {
134 lookingAtFmtCvt =
true;
137 newFormat[newFormatIdx] = format[i];
140 Assert (newFormatIdx >= origFormatLen);
141 if (newFormatIdx > origFormatLen) {
142 newFormat[newFormatIdx] =
'\0';
143 useFormat = newFormat;
151 va_copy (argListCopy, argsList);
153#if qCompilerAndStdLib_vswprintf_errantDependencyOnLocale_Buggy
154 locale_t tmpLocale{};
155 locale_t prevLocale{};
156 [[maybe_unused]]
auto&& cleanup = Execution::Finally ([&tmpLocale, &prevLocale] ()
noexcept {
157 if (prevLocale !=
nullptr) {
158 ::uselocale (prevLocale);
160 if (tmpLocale !=
nullptr) {
161 ::freelocale (tmpLocale);
168 while (::vswprintf (msgBuf.data (), msgBuf.GetSize (), useFormat, argListCopy) < 0) {
169#if qCompilerAndStdLib_vswprintf_errantDependencyOnLocale_Buggy
170 if (errno == EILSEQ and tmpLocale ==
nullptr) {
171 tmpLocale = ::newlocale (LC_CTYPE,
"en_US.UTF-8", NULL);
172 prevLocale = ::uselocale (tmpLocale);
176 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
177 va_end (argListCopy);
178 va_copy (argListCopy, argsList);
180 va_end (argListCopy);
181 Assert (::wcslen (msgBuf.data ()) < msgBuf.GetSize ());
182 return wstring{msgBuf.data ()};
184DISABLE_COMPILER_MSC_WARNING_END (6262)
191string Characters::CString::Format (const
char* format, ...)
194 va_start (argsList, format);
195 string tmp = FormatV (format, argsList);
200u8string Characters::CString::Format (
const char8_t* format, ...)
203 va_start (argsList, format);
204 u8string tmp = FormatV (format, argsList);
209wstring Characters::CString::Format (
const wchar_t* format, ...)
212 va_start (argsList, format);
213 wstring tmp = FormatV (format, argsList);
224 template <
typename STRING>
225 inline STRING LimitLength_HLPR_ (
const STRING& str,
size_t maxLen,
bool keepLeft,
const STRING& kELIPSIS)
227 if (str.length () <= maxLen) {
230 size_t useLen = maxLen;
231 if (useLen > kELIPSIS.length ()) {
232 useLen -= kELIPSIS.length ();
238 return str.substr (0, useLen) + kELIPSIS;
241 return kELIPSIS + str.substr (str.length () - useLen);
245string Characters::CString::LimitLength (
const string& str,
size_t maxLen,
bool keepLeft)
247 return LimitLength_HLPR_<string> (str, maxLen, keepLeft,
"...");
250wstring Characters::CString::LimitLength (
const wstring& str,
size_t maxLen,
bool keepLeft)
252 return LimitLength_HLPR_<wstring> (str, maxLen, keepLeft, L
"...");
261 template <
typename STRING>
262 inline STRING StripTrailingCharIfAny_HLPR_ (
const STRING& str,
typename STRING::value_type c)
264 if (str.size () > 0 and str[str.size () - 1] == c) {
266 tmp.erase (tmp.size () - 1);
273string Characters::CString::StripTrailingCharIfAny (
const string& s,
char c)
275 return StripTrailingCharIfAny_HLPR_ (s, c);
278wstring Characters::CString::StripTrailingCharIfAny (
const wstring& s,
wchar_t c)
280 return StripTrailingCharIfAny_HLPR_ (s, c);
288unsigned int Characters::CString::HexString2Int (
const string& s)
290 unsigned long l = strtoul (s.c_str (),
nullptr, 16);
291 if (l >= numeric_limits<unsigned int>::max ()) {
292 return numeric_limits<unsigned int>::max ();
297unsigned int Characters::CString::HexString2Int (
const wchar_t* s)
300 unsigned long l = wcstoul (s,
nullptr, 16);
301 if (l >= numeric_limits<unsigned int>::max ()) {
302 return numeric_limits<unsigned int>::max ();
307unsigned int Characters::CString::HexString2Int (
const wstring& s)
309 unsigned long l = wcstoul (s.c_str (),
nullptr, 16);
310 if (l >= numeric_limits<unsigned int>::max ()) {
311 return numeric_limits<unsigned int>::max ();
321long long int Characters::CString::Private_::String2Int_ (
const string& s)
324 return strtoll (s.c_str (),
nullptr, 10);
327long long int Characters::CString::Private_::String2Int_ (
const wstring& s)
329 unsigned long long int l = wcstoll (s.c_str (),
nullptr, 10);
338unsigned long long int Characters::CString::Private_::String2UInt_ (
const string& s)
341 unsigned long long int l = strtoull (s.c_str (),
nullptr, 10);
345unsigned long long int Characters::CString::Private_::String2UInt_ (
const wstring& s)
347 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)