Skip to content

Commit 18472a7

Browse files
committed
multi-byte output stuff: switch to wchar_t
Actually, wcsrtombs() is supported since C99 and there doesn't seem any major implementation missing it. (On contrarty to that c8rtombs() - which is understandable, since it is C23. But even macOS is missing the C11 uchar.h stuff like c32rtomb() but weirdly just for C, not C++). \unnnn and \Unnnnnnnn code points in wide character literals (L"") seem to work reliable. Advantages: simplified the stuff - no configure check, conditional translation while extending the backward compatibility. Less code paths (avoided UTF-8 fallback, which may not be now required since wcsrtombs is almost everywhere supported).
1 parent fc65057 commit 18472a7

9 files changed

Lines changed: 59 additions & 87 deletions

File tree

configure.ac

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,6 @@ AC_CHECK_LIB(rt, timer_create)
432432
AC_CHECK_FUNC(sin, MATHLIBS="", MATHLIBS="-lm")
433433
AC_SUBST(MATHLIBS)
434434

435-
if test "$system" != "Windows"; then
436-
AC_CHECK_FUNCS(c8rtomb)
437-
fi
438-
439435
# -------------------------------------------------------------------------------------------------
440436
# See if this system supports sched_setscheduler()
441437

src/audio/capture/coreaudio.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
#include "utils/macros.h"
5858
#include "utils/pthread.h" // for CHK_PTHR
5959
#include "utils/ring_buffer.h"
60-
#include "utils/unicode.h" // for u8s_to_mbs
60+
#include "utils/unicode.h" // for wcs_to_mbs_fallb
6161

6262
#define MOD_NAME "[CoreAudio cap.] "
6363

@@ -392,7 +392,7 @@ static void (^cb)(BOOL) = ^void(BOOL granted) {
392392

393393
if (!failed) {
394394
char rec_fallb_sym[128] = TBOLD(TRED("(RECORDING)"));
395-
const char *rec_sym = u8s_to_mbs(U8_LARGE_RED_CIRCLE, rec_fallb_sym);
395+
const char *rec_sym = wcs_to_mbs_fallb(W_LARGE_RED_CIRCLE, rec_fallb_sym);
396396
color_printf("%s " MOD_NAME TBOLD(TYELLOW("This application"
397397
" is capturing computer audio.")) "\n", rec_sym);
398398
return s;

src/blackmagic_common.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
#include "utils/debug.h" // for DEBUG_TIMER_*
6666
#include "utils/macros.h" // for STR_LEN, snprintf_ch, IS_FCC
6767
#include "utils/string.h" // for DELDEL
68-
#include "utils/unicode.h" // for u8s_to_mbs
68+
#include "utils/unicode.h" // for wcs_to_mbs_fallb
6969
#include "utils/windows.h"
7070
#include "utils/worker.h"
7171

@@ -1739,7 +1739,7 @@ class BMDNotificationCallback : public IDeckLinkNotificationCallback
17391739
// check overheating
17401740
if (cur_temp >= m_tempThresholdErr) {
17411741
char deg_fallb_sym[128] = "deg ";
1742-
const char *deg_sym = u8s_to_mbs(U8_DEGREE_SIGN, deg_fallb_sym);
1742+
const char *deg_sym = wcs_to_mbs_fallb(W_DEGREE_SIGN, deg_fallb_sym);
17431743
log_msg(LOG_LEVEL_ERROR,
17441744
"%sDevice is overheating! The temperature is "
17451745
"%" PRId64 " %sC.\n",

src/control_socket.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
#include "utils/net.h"
7373
#include "utils/macros.h" // for MODULE_MAGIC
7474
#include "utils/thread.h"
75-
#include "utils/unicode.h" // for u8s_to_mbs
75+
#include "utils/unicode.h" // for wcs_to_mbs_fallb
7676

7777
#define MAX_CLIENTS 16
7878
#define MOD_NAME "[control_socket] "
@@ -1067,7 +1067,7 @@ get_control_state(struct module *mod)
10671067

10681068
static void print_control_help() {
10691069
char fn1_flbk[128] = "[1]";
1070-
const char *footn1 = u8s_to_mbs(U8_SUPERSCRIPT_ONE, fn1_flbk);
1070+
const char *footn1 = wcs_to_mbs_fallb(W_SUPERSCRIPT_ONE, fn1_flbk);
10711071
color_printf("Control internal commands:\n"
10721072
TBOLD("\texit") "\n"
10731073
TBOLD("\tpause") "\n"

src/ndi_common.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
#include "utils/color_out.h"
5252
#include "utils/fs.h" // for MAX_PATH_SIZE, PATH_SEPARATOR
5353
#include "utils/macros.h" // for MAX, MERGE, TOSTRING, snprintf_ch
54-
#include "utils/unicode.h" // u8s_to_mbs
54+
#include "utils/unicode.h" // wcs_to_mbs_fallb
5555

5656
#define MOD_NAME "[NDI] "
5757

@@ -167,7 +167,7 @@ static inline void
167167
ndi_print_copyright()
168168
{
169169
char r_fallb_sym[128] = "(r)";
170-
const char *reg_sym = u8s_to_mbs(U8_REGISTERED_SIGN, r_fallb_sym);
170+
const char *reg_sym = wcs_to_mbs_fallb(W_REGISTERED_SIGN, r_fallb_sym);
171171

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

src/utils/unicode.c

Lines changed: 39 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,102 +3,80 @@
33

44
/**
55
* @file
6-
* @note
7-
* char32_t implementation with c32rtomb() could be more compatible since it
8-
* should be supported since C11/C++11 but its implementation is unfortuntately
9-
* missing from macOS (up to including 26) and the pass-through workaround won't
10-
* work with UTF-32 data.
6+
* helper function around wcsrtombs() to handle conversion failures
7+
* (fallback) or where is the MBS output may be unsupported (eg. in
8+
* Windows if neither in Terminal nor in MSYS2 window).
119
*/
1210

1311
#include "utils/unicode.h"
1412

15-
#ifdef HAVE_CONFIG_H
16-
#include "config.h" // for HAVE_C8RTOMB
17-
#endif
18-
19-
#include <assert.h> // for assert
20-
#include <limits.h> // for INT_MAX, PATH_MAX
2113
#include <locale.h> // for setlocale
22-
#include <string.h> // for memcpy, strlen, strpbrk
23-
#ifdef HAVE_C8RTOMB
24-
#include <uchar.h> // for c8rtomb
14+
#include <string.h> // for memcpy, strlen, strpbrk, strstr
2515
#include <wchar.h> // for mbstate_t
26-
#endif
2716

2817
#include "compat/c23.h" // IWYU pragma: keep
2918
#include "debug.h"
3019

3120
#define MOD_NAME "[utils/unicode] "
3221

33-
static bool utf8_terminal = false;
22+
#ifdef _WIN32
23+
static bool win_utf8_terminal = false;
24+
#endif
25+
3426
void
3527
u8_out_init(bool is_win_utf8_terminal)
3628
{
3729
#ifdef _WIN32
38-
utf8_terminal = is_win_utf8_terminal;
30+
win_utf8_terminal = is_win_utf8_terminal;
31+
// this is necessary for wcsrtombs work with 2 wchar_t character
32+
// conversion (eg. W_LARGE_RED_CIRCLE)
33+
const char *lc_ctype = setlocale(LC_CTYPE, ".UTF8");
3934
#else
35+
(void) is_win_utf8_terminal;
4036
const char *lc_ctype = setlocale(LC_CTYPE, "");
37+
#endif
4138
if (lc_ctype == nullptr) {
4239
MSG(WARNING, "Cannot set locale.");
4340
} else {
4441
MSG(DEBUG, "LC_CTYPE set to: %s\n", lc_ctype);
45-
utf8_terminal = strstr(lc_ctype, ".UTF-8") != nullptr;
4642
}
47-
(void) is_win_utf8_terminal;
48-
#endif
4943
}
5044

5145
/**
52-
* Tries to convert utf-8 string to locale-specific multibyte string. If
53-
* c8rtomb not present and UTF-8 terminal detected, copies the UTF-8 string.
54-
* Otherwise, out_fallback is kept untouched (should contain fallback text).
46+
* Tries to convert wide string to locale-specific multibyte string. If
47+
* conversion fails out_fallback is returned untouched (should contain fallback
48+
* text).
5549
*
5650
* @param buflen out_fallback buffer length long enough to hold the converted
57-
string with some headroom (MB_LEN_MAX-1)
51+
string
5852
* @param[in,out] out_fallback NUL-terminated fallback string. If conversion
5953
* succeeds, it is rewritten by the u8_str converted to MBS
60-
* @returns out_fallback with converted data if we have c8rtomb
61-
* @returns u8_str if it is safe to pass-through
62-
* @returns out_fallback unchanged if u8_str not convertible and terminal not in
63-
UTF-8
54+
* @returns out_fallback with converted data if conversion suceeds
55+
* @returns out_fallback unchanged if wstr not convertible
6456
*
65-
* u8_to_mb_init() must be called otherwise fallback is always ret
57+
* u8_out_init() must be called otherwise fallback is always ret
6658
*/
6759
const char *
68-
u8s_to_mbs_buf(const unsigned char *u8_str, size_t buflen, char *out_fallback)
60+
wcs_to_mbs_buf(const wchar_t *wstr, size_t buflen, char *out_fallback)
6961
{
70-
#if defined HAVE_C8RTOMB && !defined _WIN32
71-
mbstate_t ps = { 0 };
72-
const char8_t *in_ptr = u8_str;
73-
// check convertibility first
74-
do {
75-
char discard[MB_LEN_MAX];
76-
size_t ret = c8rtomb(discard, *in_ptr, &ps);
77-
if (ret == (size_t) -1) { // not convertible
78-
return out_fallback;
79-
}
80-
} while (*in_ptr++ != '\0');
81-
// actual conversion
82-
in_ptr = u8_str;
83-
char *out_ptr = out_fallback;
84-
do {
85-
if (buflen < MB_LEN_MAX || buflen == 1) {
86-
MSG(WARNING, "utf-8 string truncated.\n");
87-
assert(buflen >= 1);
88-
*out_ptr = '\0';
89-
break;
90-
}
91-
size_t ret = c8rtomb(out_ptr, *in_ptr, &ps);
92-
assert(ret != (size_t) -1);
93-
out_ptr += ret;
94-
buflen -= ret;
95-
} while (*in_ptr++ != '\0');
96-
return out_fallback;
97-
#else
98-
(void) buflen;
99-
if (!utf8_terminal) {
62+
#ifdef _WIN32
63+
if (!win_utf8_terminal) {
10064
return out_fallback;
10165
}
102-
return (const char *) u8_str;
10366
#endif
67+
68+
mbstate_t ps = { 0 };
69+
70+
// check convertibility first
71+
size_t ret = wcsrtombs(nullptr, &wstr, 0, &ps);
72+
if (ret == (size_t) -1) { // not convertible
73+
return out_fallback;
74+
}
75+
76+
// actual conversion
77+
(void) wcsrtombs(out_fallback, &wstr, buflen, &ps);
78+
if (wstr != nullptr) {
79+
MSG(WARNING, "%s: wide string truncated.\n", __func__);
80+
}
81+
return out_fallback;
10482
}

src/utils/unicode.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,17 @@
1616
extern "C" {
1717
#endif
1818

19-
#define U8_REGISTERED_SIGN u8"\xC2\xAE"
20-
#define U8_DEGREE_SIGN u8"\xC2\xB0"
21-
#define U8_SUPERSCRIPT_ONE u8"\xC2\xB9"
22-
#define U8_LARGE_RED_CIRCLE u8"\xF0\x9F\x94\xB4"
19+
#define W_REGISTERED_SIGN L"\u00AE"
20+
#define W_DEGREE_SIGN L"\u00B0"
21+
#define W_SUPERSCRIPT_ONE L"\u00B9"
22+
#define W_LARGE_RED_CIRCLE L"\U0001F534"
2323

2424
void u8_out_init(bool is_win_utf8_terminal);
25-
const char *u8s_to_mbs_buf(const unsigned char *u8_str, size_t buflen,
25+
const char *wcs_to_mbs_buf(const wchar_t *wstr, size_t buflen,
2626
char *out_fallback);
27-
// convenience macro casting char8_t ptr to (const unsigned char *) + len from
28-
// buf
29-
#define u8s_to_mbs(u8_str, out_fallback) \
30-
u8s_to_mbs_buf((const unsigned char *) (u8_str), sizeof(out_fallback), \
31-
(out_fallback))
27+
// convenience adding length from out_fallback array size
28+
#define wcs_to_mbs_fallb(wstr, out_fallback) \
29+
wcs_to_mbs_buf((wstr), sizeof(out_fallback), (out_fallback))
3230

3331
#ifdef __cplusplus
3432
}

src/video_capture/avfoundation.mm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
#include "debug.h"
5050
#include "lib_common.h"
5151
#include "utils/color_out.h"
52-
#include "utils/unicode.h" // for u8s_to_mbs
52+
#include "utils/unicode.h" // for wcs_to_mbs_fallb
5353
#include "video.h"
5454
#include "video_capture.h"
5555

@@ -802,7 +802,7 @@ static int vidcap_avfoundation_init(const struct vidcap_params *params, void **s
802802
return VIDCAP_INIT_FAIL;
803803
}
804804
char rec_fallb_sym[128] = TBOLD(TRED("(RECORDING)"));
805-
const char *rec_sym = u8s_to_mbs(U8_LARGE_RED_CIRCLE, rec_fallb_sym);
805+
const char *rec_sym = wcs_to_mbs_fallb(W_LARGE_RED_CIRCLE, rec_fallb_sym);
806806
color_printf("%s " MOD_NAME TBOLD(TYELLOW("This"
807807
" application is capturing computer video.")) "\n", rec_sym);
808808
*state = ret;

src/video_display/gl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
#include "utils/macros.h" // for OPTIMIZED_FOR, STRINGIFY
8686
#include "utils/misc.h" // for ug_strerror
8787
#include "utils/pthread.h" // for ug_pthread_*
88-
#include "utils/unicode.h" // u8s_to_mbs
88+
#include "utils/unicode.h" // wcs_to_mbs_fallb
8989
#include "video.h"
9090
#include "video_display.h"
9191

@@ -587,7 +587,7 @@ static void
587587
gl_show_help(bool full)
588588
{
589589
char fn1_flbk[128] = "[1]";
590-
const char *footn1 = u8s_to_mbs(U8_SUPERSCRIPT_ONE, fn1_flbk);
590+
const char *footn1 = wcs_to_mbs_fallb(W_SUPERSCRIPT_ONE, fn1_flbk);
591591

592592
color_printf("usage:\n");
593593
color_printf(TBOLD(TRED("\t-d gl[:<options>]") "%s")

0 commit comments

Comments
 (0)