Skip to content

Commit 45c3625

Browse files
committed
u8_to_mb: pass through the u8 str if term is UTF-8
In POSIX systems, if setlocale(LC_CTYPE, "") returns string ending with '.UTF-8', we assume that UTF-8 can be displayed safely. In Windows, assume this in Windows Terminal and MSYS window now (didn't find a reliable way to do this eg. over SSH). Do not expect c8rtomb on MSW (not present now, anyways) - it is a bit dubious whether it will work even so (will need to be tested). + [minor] handle when implementation has MB_LEN_MAX==1 and buffer not long enough (do not fail on assert because the `if` was entered with buflen==0)
1 parent 9ce819b commit 45c3625

10 files changed

Lines changed: 61 additions & 37 deletions

File tree

configure.ac

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,9 @@ AC_CHECK_LIB(rt, timer_create)
432432
AC_CHECK_FUNC(sin, MATHLIBS="", MATHLIBS="-lm")
433433
AC_SUBST(MATHLIBS)
434434

435-
AC_CHECK_FUNCS(c8rtomb)
435+
if test "$system" != "Windows"; then
436+
AC_CHECK_FUNCS(c8rtomb)
437+
fi
436438

437439
# -------------------------------------------------------------------------------------------------
438440
# See if this system supports sched_setscheduler()

src/audio/capture/coreaudio.m

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "utils/macros.h"
5858
#include "utils/pthread.h" // for CHK_PTHR
5959
#include "utils/ring_buffer.h"
60+
#include "utils/text.h" // for c8_to_mb
6061

6162
#define MOD_NAME "[CoreAudio cap.] "
6263

@@ -390,9 +391,11 @@ static void (^cb)(BOOL) = ^void(BOOL granted) {
390391
} while(0);
391392

392393
if (!failed) {
393-
// c8rtomb not yet supported on mac - pass the str through
394-
color_printf((const char *) u8"🔴 " MOD_NAME TBOLD(TYELLOW("This application"
395-
" is capturing computer audio.")) "\n");
394+
char rec_fallb_sym[128] = TBOLD(TRED("(RECORDING)"));
395+
const char *rec_sym = c8_to_mb(u8"🔴", sizeof rec_fallb_sym,
396+
rec_fallb_sym);
397+
color_printf("%s " MOD_NAME TBOLD(TYELLOW("This application"
398+
" is capturing computer audio.")) "\n", rec_sym);
396399
return s;
397400
}
398401

src/blackmagic_common.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,8 +1739,8 @@ class BMDNotificationCallback : public IDeckLinkNotificationCallback
17391739
// check overheating
17401740
if (cur_temp >= m_tempThresholdErr) {
17411741
char deg_fallb_sym[128] = "deg ";
1742-
char *deg_sym = c8_to_mb(u8"°", sizeof deg_fallb_sym,
1743-
deg_fallb_sym);
1742+
const char *deg_sym = c8_to_mb(
1743+
u8"°", sizeof deg_fallb_sym, deg_fallb_sym);
17441744
log_msg(LOG_LEVEL_ERROR,
17451745
"%sDevice is overheating! The temperature is "
17461746
"%" PRId64 " %sC.\n",

src/host.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ struct init_data *common_preinit(int argc, char *argv[])
544544
#endif
545545

546546
struct init_data init{};
547+
bool is_win_utf8_terminal = false;
547548
#ifdef _WIN32
548549
WSADATA wsaData;
549550
int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
@@ -578,8 +579,12 @@ struct init_data *common_preinit(int argc, char *argv[])
578579
"consider using Windows Terminal instead!\n");
579580
Sleep(1000);
580581
}
582+
is_win_utf8_terminal = (getenv("TERM") == nullptr &&
583+
_isatty(fileno(stdout)) &&
584+
win_has_ancestor_process("WindowsTerminal.exe"))
585+
|| isMsysPty(fileno(stdout));
581586
#endif
582-
u8_to_mb_init(); // setlocale(LC_CTYPE, "");
587+
u8_to_mb_init(is_win_utf8_terminal); // setlocale(LC_CTYPE, "");
583588

584589
if (strstr(argv[0], "run_tests") == nullptr) {
585590
open_all("ultragrid_*.so", init.opened_libs); // load modules

src/ndi_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ static inline void
167167
ndi_print_copyright()
168168
{
169169
char r_fallb_sym[128] = "(r)";
170-
char *reg_sym = c8_to_mb(u8"®", sizeof r_fallb_sym, r_fallb_sym);
170+
const char *reg_sym = c8_to_mb(u8"®", sizeof r_fallb_sym, r_fallb_sym);
171171

172172
color_printf(TERM_BOLD TERM_FG_BLUE
173173
"This application uses NDI%s available "

src/utils/color_out.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,13 @@ static bool setWinTermAnsiColors(DWORD stream) {
7373
}
7474
return true;
7575
}
76+
#endif // defined _WIN32
7677

7778
/// Taken from [rang](https://github.com/agauniyal/rang)
78-
static bool isMsysPty(int fd) {
79+
bool
80+
isMsysPty(int fd)
81+
{
82+
#ifdef _WIN32
7983
// Dynamic load for binary compatibility with old Windows
8084
BOOL (*ptrGetFileInformationByHandleEx)(
8185
HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
@@ -120,8 +124,11 @@ static bool isMsysPty(int fd) {
120124
}
121125

122126
return true;
127+
#else
128+
(void) fd;
129+
return false;
130+
#endif
123131
}
124-
#endif // defined _WIN32
125132

126133
ADD_TO_PARAM("log-color", "* log-color[=no]\n"
127134
" Force enable/disable ANSI text formatting.\n");

src/utils/color_out.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
extern "C" {
9999
#endif
100100

101+
bool isMsysPty(int fd);
101102
bool color_output_init(void);
102103
[[gnu::format(printf, 1, 2)]] int color_printf(const char *format, ...);
103104

src/utils/text.c

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@
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;
434435
void
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 *
470468
u8_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
}

src/utils/text.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ bool draw_line_scaled(char *buf, int pitch, const char *text, uint32_t fg,
6363

6464
const char *const *get_font_candidates(void);
6565

66-
void u8_to_mb_init();
67-
char *u8_to_mb(const unsigned char *u8_str, size_t buflen, char *out_fallback);
66+
void u8_to_mb_init(bool is_win_utf8_terminal);
67+
const char *u8_to_mb(const unsigned char *u8_str, size_t buflen,
68+
char *out_fallback);
6869
// convenience macro casting char8_t pointer to (const unsigned char *)
6970
#define c8_to_mb(c8_str, buflen, out_fallback) \
7071
u8_to_mb((const unsigned char *) (c8_str), buflen, (out_fallback))

src/video_capture/avfoundation.mm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "debug.h"
5050
#include "lib_common.h"
5151
#include "utils/color_out.h"
52+
#include "utils/text.h" // for c8_to_mb
5253
#include "video.h"
5354
#include "video_capture.h"
5455

@@ -800,9 +801,11 @@ static int vidcap_avfoundation_init(const struct vidcap_params *params, void **s
800801
if (!ret) {
801802
return VIDCAP_INIT_FAIL;
802803
}
803-
// c8rtomb not yet supported on mac - pass the str through
804-
color_printf((const char *) u8"🔴 " MOD_NAME TBOLD(TYELLOW("This"
805-
" application is capturing computer video.")) "\n");
804+
char rec_fallb_sym[128] = TBOLD(TRED("(RECORDING)"));
805+
const char *rec_sym = c8_to_mb(u8"🔴", sizeof rec_fallb_sym,
806+
rec_fallb_sym);
807+
color_printf("%s " MOD_NAME TBOLD(TYELLOW("This"
808+
" application is capturing computer video.")) "\n", rec_sym);
806809
*state = ret;
807810
return VIDCAP_INIT_OK;
808811
}

0 commit comments

Comments
 (0)