From 84f8a75a2ec980af83afef5590b5f637a3b321bf Mon Sep 17 00:00:00 2001 From: Pauli Date: Tue, 12 Jun 2018 20:25:40 +0300 Subject: [PATCH] Add cuchar fallback implementation for gcc 4 and 5 --- CMakeLists.txt | 6 ++++ library/Console-posix.cpp | 64 +++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e8663f88..7a8cb42ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,12 @@ ${CMAKE_MODULE_PATH} # generates compile_commands.json, used for autocompletion by some editors SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) +include(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX("cuchar" HAVE_CUCHAR) +if(HAVE_CUCHAR) + add_definitions("-DHAVE_CUCHAR") +endif() + # mixing the build system with the source code is ugly and stupid. enforce the opposite :) if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message(FATAL_ERROR "In-source builds are not allowed.") diff --git a/library/Console-posix.cpp b/library/Console-posix.cpp index 6184bd011..a06008cba 100644 --- a/library/Console-posix.cpp +++ b/library/Console-posix.cpp @@ -60,7 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#ifdef HAVE_CUCHAR #include +#else +#include +#endif // George Vulov for MacOSX #ifndef __LINUX__ @@ -134,37 +138,63 @@ const char * getANSIColor(const int c) } } -std::u32string fromLocaleMB(const std::string& str) + +#ifdef HAVE_CUCHAR +// Use u32string for GCC 6 and later and msvc to allow potable implementation +using u32string = std::u32string; +using std::c32rtomb; +using std::mbrtoc32; +#else +// Fallback for gcc 4 and 5 that don't have cuchar header +// But wchar_t is 4 bytes that is a good fallback implementation +using u32string = std::wstring; +size_t mbrtoc32(u32string::value_type* c, + const char* s, + std::size_t n, + std::mbstate_t* ps) +{ + return std::mbrtowc(c, s, n, ps); +} + +size_t c32rtomb(char* mb, + u32string::value_type c, + std::mbstate_t* ps) +{ + return std::wcrtomb(mb, c, ps); +} +#endif + +//! Convert a locale defined multibyte coding to UTF-32 string for easier +//! character processing. +static u32string fromLocaleMB(const std::string& str) { - std::u32string rv; - char32_t ch; + u32string rv; + u32string::value_type ch; size_t pos = 0; ssize_t sz; std::mbstate_t state{}; - while ((sz = std::mbrtoc32(&ch,&str[pos], str.size() - pos, &state)) != 0) { + while ((sz = mbrtoc32(&ch,&str[pos], str.size() - pos, &state)) != 0) { if (sz == -1 || sz == -2) break; rv.push_back(ch); - if (sz == -3) + if (sz == -3) /* multi value character */ continue; pos += sz; } - rv.push_back('\0'); return rv; } -std::string toLocaleMB(const std::u32string& wstr) +//! Convert a UTF-32 string back to locale defined multibyte coding. +static std::string toLocaleMB(const u32string& wstr) { std::stringstream ss{}; char mb[MB_CUR_MAX]; std::mbstate_t state{}; const size_t err = -1; - for (char32_t ch: wstr) { - size_t sz = std::c32rtomb(mb, ch, &state); - if (sz == err) { - ss << '\0'; + for (auto ch: wstr) { + size_t sz = c32rtomb(mb, ch, &state); + if (sz == err) break; - } ss.write(mb, sz); } return ss.str(); @@ -707,13 +737,15 @@ namespace DFHack default: if (c >= 32) // Space { - char32_t c32; + u32string::value_type c32; char mb[MB_CUR_MAX]; size_t count = 1; mb[0] = c; ssize_t sz; std::mbstate_t state{}; - while ((sz = std::mbrtoc32(&c32,reinterpret_cast(&c),1, &state)) < 0) { + // Read all bytes belonging to a multi byte + // character starting from the first bye already red + while ((sz = mbrtoc32(&c32,&mb[count-1],1, &state)) < 0) { if (sz == -1 || sz == -3) return -1; /* mbrtoc32 error (not valid utf-32 character */ if(!read_char(c)) @@ -760,8 +792,8 @@ namespace DFHack } state; bool in_batch; std::string prompt; // current prompt string - std::u32string raw_buffer; // current raw mode buffer - std::u32string yank_buffer; // last text deleted with Ctrl-K/Ctrl-U + u32string raw_buffer; // current raw mode buffer + u32string yank_buffer; // last text deleted with Ctrl-K/Ctrl-U int raw_cursor; // cursor position in the buffer // thread exit mechanism int exit_pipe[2];