Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Characters/Format.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#include <cstdarg>
7#include <cstdio>
8#include <cstdlib>
9#include <iomanip>
10#include <limits>
11#include <sstream>
12
13#include "Stroika/Foundation/Containers/Common.h"
16#include "Stroika/Foundation/Math/Common.h"
18
19#include "Format.h"
20
21using namespace Stroika::Foundation;
23using namespace Stroika::Foundation::Memory;
24
25/*
26 ********************************************************************************
27 ************************************* Format ***********************************
28 ********************************************************************************
29 */
31String Characters::FormatV (const wchar_t* format, va_list argsList)
32{
33 RequireNotNull (format);
34 StackBuffer<wchar_t, 10 * 1024> msgBuf{Memory::eUninitialized, 10 * 1024};
35 const wchar_t* useFormat = format;
36 wchar_t newFormat[5 * 1024];
37 {
38 size_t origFormatLen = wcslen (format);
39 Require (origFormatLen < NEltsOf (newFormat) / 2); // just to be sure safe - this is already crazy-big for format string...
40 // Could use Memory::StackBuffer<> but I doubt this will ever get triggered
41 bool lookingAtFmtCvt = false;
42 size_t newFormatIdx = 0;
43 for (size_t i = 0; i < origFormatLen; ++i) {
44 if (lookingAtFmtCvt) {
45 switch (format[i]) {
46 case '%': {
47 lookingAtFmtCvt = false;
48 } break;
49 case 's': {
50 newFormat[newFormatIdx] = 'l';
51 ++newFormatIdx;
52 lookingAtFmtCvt = false; // DONE
53 } break;
54 case '.': {
55 // could still be part for format string
56 } break;
57 default: {
58 if (isdigit (format[i])) {
59 // could still be part for format string
60 }
61 else {
62 lookingAtFmtCvt = false; // DONE
63 }
64 } break;
65 }
66 }
67 else {
68 if (format[i] == '%') {
69 lookingAtFmtCvt = true;
70 }
71 }
72 newFormat[newFormatIdx] = format[i];
73 ++newFormatIdx;
74 }
75 Assert (newFormatIdx >= origFormatLen);
76 if (newFormatIdx > origFormatLen) {
77 newFormat[newFormatIdx] = '\0';
78 useFormat = newFormat;
79 }
80 }
81
82 // SUBTLE: va_list looks like it is passed by value, but its not really,
83 // and vswprintf, at least on GCC munges it. So we must use va_copy() to do this safely
84 // @see http://en.cppreference.com/w/cpp/utility/variadic/va_copy
85 va_list argListCopy;
86 va_copy (argListCopy, argsList);
87 // Assume only reason for failure is not enuf bytes, so allocate more.
88 // If I'm wrong, we'll just runout of memory and throw out...
89 while (::vswprintf (msgBuf.data (), msgBuf.GetSize (), useFormat, argListCopy) < 0) {
90 msgBuf.GrowToSize_uninitialized (msgBuf.GetSize () * 2);
91 va_end (argListCopy);
92 va_copy (argListCopy, argsList);
93 }
94 va_end (argListCopy);
95 Assert (::wcslen (msgBuf.data ()) < msgBuf.GetSize ());
96 return String{msgBuf.data ()};
97}
98DISABLE_COMPILER_MSC_WARNING_END (6262)
99
100/*
101 ********************************************************************************
102 ************************************* Format ***********************************
103 ********************************************************************************
104 */
105String Characters::Format (const wchar_t* format, ...)
106{
107 va_list argsList;
108 va_start (argsList, format);
109 String tmp = FormatV (format, argsList);
110 va_end (argsList);
111 return tmp;
112}
#define RequireNotNull(p)
Definition Assertions.h:347
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...