1+ module ;
2+ #ifdef _WIN32
3+ #include < Windows.h>
4+ #else
5+ // no includes here
6+ #endif
7+
8+ #include < cstddef>
9+ #include < utility>
10+ #include < memory>
11+
12+ module print;
13+
14+ import :internal;
15+ import nativeAPI;
16+
17+ using starlib::detail::NativeHandle;
18+
19+ static NativeHandle g_hStandardOutput{};
20+
21+ void starlib::detail::InitialisePrintBuffers (void )
22+ {
23+ if (g_hStandardOutput != NativeHandle::Null)
24+ return ;
25+
26+ #ifdef _WIN32
27+ g_hStandardOutput = starlib::detail::PointerToHandle (GetStdHandle (STD_OUTPUT_HANDLE));
28+ SetConsoleCP (CP_UTF8); // Ensure UTF-8
29+ SetConsoleOutputCP (CP_UTF8);
30+ const auto hConsole = reinterpret_cast <HANDLE>(std::to_underlying (g_hStandardOutput));
31+
32+ DWORD mode{};
33+ if (GetConsoleMode (hConsole, &mode))
34+ {
35+ mode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
36+ SetConsoleMode (hConsole, mode);
37+ }
38+ #else
39+ #endif
40+ }
41+ void starlib::detail::PrintString (const char * szBuffer, std::size_t dwLength)
42+ {
43+ InitialisePrintBuffers ();
44+
45+ #ifdef _WIN32
46+ DWORD dwWritten{};
47+ const auto hConsole = reinterpret_cast <HANDLE>(std::to_underlying (g_hStandardOutput));
48+ WriteConsoleA (hConsole, szBuffer, dwLength, &dwWritten, nullptr );
49+ #else
50+ #endif
51+ }
52+ void starlib::detail::PrintString (const wchar_t * szBuffer, std::size_t dwLength)
53+ {
54+ InitialisePrintBuffers ();
55+
56+ #ifdef _WIN32
57+ DWORD dwWritten{};
58+ WriteConsoleW (reinterpret_cast <HANDLE>(std::to_underlying (g_hStandardOutput)), szBuffer, dwLength, &dwWritten, nullptr );
59+ #else
60+ #endif
61+ }
62+
63+ std::unique_ptr<char []> starlib::detail::Utf8ToCP (const char8_t * szInput, std::size_t & dwLength)
64+ {
65+ #ifdef _WIN32
66+ if (szInput == nullptr || dwLength == 0 )
67+ return nullptr ;
68+
69+ const auto wideSize = MultiByteToWideChar (CP_UTF8, 0 , reinterpret_cast <const char *>(szInput), dwLength, nullptr , 0 );
70+
71+ std::unique_ptr<wchar_t []> wideBuffer = std::make_unique_for_overwrite<wchar_t []>(wideSize);
72+
73+ wideBuffer[MultiByteToWideChar (CP_UTF8, 0 , reinterpret_cast <const char *>(szInput), dwLength, wideBuffer.get (), wideSize)] = 0 ;
74+
75+ const auto convertedSize = WideCharToMultiByte (CP_ACP, 0 , wideBuffer.get (), wideSize, nullptr , 0 , nullptr , nullptr );
76+
77+ std::unique_ptr<char []> converted = std::make_unique_for_overwrite<char []>(convertedSize + 1 );
78+
79+ WideCharToMultiByte (CP_ACP, 0 , wideBuffer.get (), wideSize, converted.get (), convertedSize, nullptr , nullptr );
80+ converted[convertedSize] = 0 ;
81+ dwLength = convertedSize;
82+ return converted;
83+ #else
84+ #error Unsupported platform
85+ #endif
86+ }
87+
88+ std::unique_ptr<char []> starlib::detail::Utf16ToCP (const char16_t * szInput, std::size_t & dwLength)
89+ {
90+ #ifdef _WIN32
91+ if (szInput == nullptr || dwLength == 0 )
92+ return nullptr ;
93+
94+ static_assert (sizeof (wchar_t ) == 2 );
95+
96+ const wchar_t * wideInput = reinterpret_cast <const wchar_t *>(szInput);
97+ std::unique_ptr<wchar_t []> temporaryBuffer{};
98+
99+ const int requiredSize = WideCharToMultiByte (CP_ACP, 0 , wideInput, dwLength, nullptr , 0 , nullptr , nullptr );
100+
101+ if (requiredSize <= 0 ) return nullptr ;
102+
103+ std::unique_ptr<char []> output = std::make_unique_for_overwrite<char []>(requiredSize + 1 );
104+ WideCharToMultiByte (CP_ACP, 0 , wideInput, dwLength, output.get (), requiredSize, nullptr , nullptr );
105+ output[requiredSize] = 0 ;
106+ dwLength = static_cast <std::size_t >(requiredSize);
107+ return output;
108+ #else
109+ #error Unsupported platform
110+ #endif
111+ }
112+
113+ std::unique_ptr<char []> starlib::detail::Utf32ToCP (const char32_t * szInput, std::size_t & dwLength)
114+ {
115+ #ifdef _WIN32
116+ std::unique_ptr<char16_t []> utf16String = std::make_unique_for_overwrite<char16_t []>(dwLength * 2 );
117+ std::size_t utf16Length{};
118+
119+ for (std::size_t i = 0 ; i < dwLength; ++i)
120+ {
121+ char32_t codepoint = szInput[i];
122+ if (codepoint <= 0xFFFF )
123+ {
124+ utf16String[utf16Length++] = static_cast <char16_t >(codepoint);
125+ }
126+ else if (codepoint <= 0x10FFFF )
127+ {
128+ codepoint -= 0x10000 ;
129+ utf16String[utf16Length++] = static_cast <char16_t >((codepoint >> 10 ) + 0xD800 );
130+ utf16String[utf16Length++] = static_cast <char16_t >((codepoint & 0x3FF ) + 0xDC00 );
131+ }
132+ else return nullptr ;
133+ }
134+ dwLength = utf16Length;
135+ return starlib::detail::Utf16ToCP (utf16String.get (), dwLength);
136+ #else
137+ #error Unsupported platform
138+ #endif
139+ }
0 commit comments