4444#include <assert.h> // for assert
4545#include <ctype.h> // for isalnum
4646#include <limits.h> // for INT_MAX, PATH_MAX
47+ #include <locale.h> // for setlocale
4748#include <stdio.h> // for fclose, fwrite, rewind, sprintf, sscanf
4849#include <stdlib.h> // for getenv, malloc, free, realloc
4950#include <string.h> // for memcpy, strlen, strpbrk
5051#include <unistd.h> // for unlink
5152#ifdef HAVE_C8RTOMB
52- #include <locale.h> // for setlocale
5353#include <uchar.h> // for c8rtomb
5454#endif
5555
@@ -431,45 +431,43 @@ get_font_candidates()
431431 return ret ;
432432}
433433
434+ static bool utf8_terminal = false;
434435void
435- u8_to_mb_init ()
436+ u8_to_mb_init (bool is_win_utf8_terminal )
436437{
437- #ifdef HAVE_C8RTOMB
438- #ifndef __linux__
439- #warning "c8rtomb tested just in Linux - please check..."
440- #endif
438+ #ifdef _WIN32
439+ utf8_terminal = is_win_utf8_terminal ;
440+ #else
441441 const char * lc_ctype = setlocale (LC_CTYPE , "" );
442442 if (lc_ctype == nullptr ) {
443443 MSG (WARNING , "Cannot set locale." );
444444 } else {
445445 MSG (DEBUG , "LC_CTYPE set to: %s\n" , lc_ctype );
446+ utf8_terminal = strstr (lc_ctype , ".UTF-8" ) != nullptr ;
446447 }
448+ (void ) is_win_utf8_terminal ;
447449#endif
448450}
449451
450452/**
451- * Tries to convert utf-8 string to locale-specific multibyte string or returns
452- * fallback.
453+ * Tries to convert utf-8 string to locale-specific multibyte string. If
454+ * c8rtomb not present and UTF-8 terminal detected, copies the UTF-8 string.
455+ * Otherwise, out_fallback is kept untouched (should contain fallback text).
453456 *
454457 * @param buflen out_fallback buffer length long enough to hold the converted
455458 string with some headroom (MB_LEN_MAX-1)
456459 * @param[in,out] out_fallback NUL-terminated fallback string. If conversion
457460 * succeeds, it is rewritten by the u8_str converted to MBS
458- * @returns out_fallback. If u8_str not convertible (eg. terminal in ASCII),
459- * the content of out_fallback is returned unchanged (so that it should contain
460- * the fallback and in any case it must be NULL-terminated).
461- *
462- * u8_to_mb_init() must be called otherwise conv never suceeds and fallback ret
461+ * @returns out_fallback with converted data if we have c8rtomb
462+ * @returns u8_str if it is safe to pass-through
463+ * @returns out_fallback unchanged if u8_str not convertible and terminal not in UTF-8
463464 *
464- * This is the correct way to output UTF-8, but at this time, c8rtomb is not yet
465- * widely supported so if it is impotant that the u8_str is displayed and not the
466- * fallback, prefer passing the UTF-8 string through. Also if is probable that
467- * the term will likely to present the UTF-8 correcty. Most modern systems do.
465+ * u8_to_mb_init() must be called otherwise fallback is always ret
468466 */
469- char *
467+ const char *
470468u8_to_mb (const unsigned char * u8_str , size_t buflen , char * out_fallback )
471469{
472- #ifdef HAVE_C8RTOMB
470+ #if defined HAVE_C8RTOMB && !defined _WIN32
473471 mbstate_t ps = { 0 };
474472 const char8_t * in_ptr = u8_str ;
475473 // check convertibility first
@@ -484,7 +482,7 @@ u8_to_mb(const unsigned char *u8_str, size_t buflen, char *out_fallback)
484482 in_ptr = u8_str ;
485483 char * out_ptr = out_fallback ;
486484 do {
487- if (buflen < MB_LEN_MAX ) {
485+ if (buflen < MB_LEN_MAX || buflen == 1 ) {
488486 MSG (WARNING , "utf-8 string truncated.\n" );
489487 assert (buflen >= 1 );
490488 * out_ptr = '\0' ;
@@ -495,8 +493,12 @@ u8_to_mb(const unsigned char *u8_str, size_t buflen, char *out_fallback)
495493 out_ptr += ret ;
496494 buflen -= ret ;
497495 } while (* in_ptr ++ != '\0' );
496+ return out_fallback ;
498497#else
499- (void ) u8_str , (void ) buflen ;
498+ (void ) buflen ;
499+ if (!utf8_terminal ) {
500+ return out_fallback ;
501+ }
502+ return (const char * ) u8_str ;
500503#endif
501- return out_fallback ;
502504}
0 commit comments