feat: update console output method

- remove the macros disable the warning and error of std functions in MSVC because YYCC has disable them in header.
- update console input output functions. provide CSharp-like interface for UTF8 console input output.
	- console output function is done by WriteConsoleW and WriteFile.
	- console input function still work in progress.
- rename console ASCII color macros
- add console ASCII color test.
- remove EnableUTF8Console because no longer needed.
- add a bunch of annotation to describe YYCC UTF8 console strategy.
- add UNICODE macro in CMakeLists.txt to order CMake generate Visual Studio solution with UNICODE charset enabled, not MBCS.
This commit is contained in:
2024-06-09 21:34:28 +08:00
parent 019034a9c2
commit 1e990b74ae
5 changed files with 187 additions and 87 deletions

View File

@ -13,7 +13,7 @@
namespace YYCC::ConsoleHelper {
bool EnsureTerminalColor(FILE* fs) {
static bool RawEnableColorfulConsole(FILE* fs) {
if (!_isatty(_fileno(fs))) return false;
HANDLE h_output;
@ -21,38 +21,86 @@ namespace YYCC::ConsoleHelper {
h_output = (HANDLE)_get_osfhandle(_fileno(fs));
if (!GetConsoleMode(h_output, &dw_mode)) return false;
if (!SetConsoleMode(h_output, dw_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return false;
if (!SetConsoleMode(h_output, dw_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT)) return false;
return true;
}
bool EnsureTerminalUTF8(FILE* fs) {
if (!SetConsoleCP(CP_UTF8)) return false;
if (!SetConsoleOutputCP(CP_UTF8)) return false;
/*_setmode(_fileno(stdout), _O_U8TEXT);*/
int _ = _setmode(_fileno(fs), _O_U8TEXT);
bool EnableColorfulConsole(FILE* fs) {
if (!RawEnableColorfulConsole(stdout)) return false;
if (!RawEnableColorfulConsole(stderr)) return false;
return true;
}
bool FGets(std::string& u8_buf, FILE* stream) {
std::wstring wcmd;
if (std::getline(std::wcin, wcmd).fail()) return false;
YYCC::EncodingHelper::WcharToChar(wcmd.c_str(), u8_buf, CP_UTF8);
return true;
std::string ReadLine() {
#if YYCC_OS == YYCC_OS_WINDOWS
return std::string();
#elif YYCC_OS == YYCC_OS_LINUX
// in linux, directly use C++ function to fetch.
std::string cmd;
if (std::getline(std::cin, cmd).fail()) cmd.clear();
return cmd;
#endif
}
void FPuts(const char* u8_buf, FILE* stream) {
std::fputws(YYCC::EncodingHelper::UTF8ToWchar(u8_buf).c_str(), stream);
void Write(const char* u8_strl) {}
static void PlainWrite(const std::string& strl) {
#if YYCC_OS == YYCC_OS_WINDOWS
// fetch stdout handle first
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
// if stdout was redirected, this handle may point to a file handle or anything else,
// WriteConsoleW can not write data into such scenario, so we need check whether this handle is console handle
DWORD console_mode;
if (GetConsoleMode(hstdout, &console_mode)) {
// console handle, use WriteConsoleW.
// convert utf8 string to wide char first
std::wstring wstrl(YYCC::EncodingHelper::UTF8ToWchar(strl.c_str()));
size_t wstrl_size = wstrl.size();
// write string with size check
if (wstrl_size <= std::numeric_limits<DWORD>::max()) {
WriteConsoleW(hstdout, wstrl.c_str(), static_cast<DWORD>(wstrl_size), NULL, NULL);
}
} else {
// anything else, use WriteFile instead.
// WriteFile do not need extra convertion, because it is direct writing.
// check whether string length is overflow
size_t strl_size = strl.size() * sizeof(std::string::value_type);
// write string with size check
if (strl_size <= std::numeric_limits<DWORD>::max()) {
WriteFile(hstdout, strl.c_str(), static_cast<DWORD>(strl_size), NULL, NULL);
}
}
#elif YYCC_OS == YYCC_OS_LINUX
// in linux, directly use C function to write.
std::fputs(strl.c_str(), stdout);
#endif
}
void FPrintf(FILE* stream, const char* u8_fmt, ...) {
void Write(const char* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
FPuts(YYCC::StringHelper::VPrintf(u8_fmt, argptr).c_str(), stream);
PlainWrite(YYCC::StringHelper::VPrintf(u8_fmt, argptr));
va_end(argptr);
}
void WriteLine(const char* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
std::string cache(YYCC::StringHelper::VPrintf(u8_fmt, argptr));
cache += "\n";
PlainWrite(cache);
va_end(argptr);
}
}
#endif