mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-29 00:03:58 +01:00
Separator: uses widecharwidth for Unicode wcwidth and fixes issue that wchar_t on Windows is 2-byte length
This commit is contained in:
@@ -9,27 +9,52 @@
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
static inline uint32_t max(uint32_t a, uint32_t b)
|
||||
#if __SIZEOF_WCHAR_T__ == 4
|
||||
static inline size_t mbrtoc32(uint32_t* restrict pc32, const char* restrict s, size_t n, mbstate_t* restrict ps)
|
||||
{
|
||||
return mbrtowc((wchar_t*) pc32, s, n, ps);
|
||||
}
|
||||
#else
|
||||
#include <uchar.h>
|
||||
#endif
|
||||
|
||||
static uint8_t getMbrWidth(const char* mbstr, uint32_t length, const char** next, mbstate_t* state)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
if (__builtin_expect((uint8_t) *mbstr < 0x80, true)) // ASCII fast path
|
||||
{
|
||||
if (next) *next = mbstr + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t c32;
|
||||
uint32_t len = (uint32_t) mbrtoc32(&c32, mbstr, length, state);
|
||||
if (len >= (uint32_t) -3)
|
||||
{
|
||||
// Invalid or incomplete multibyte sequence
|
||||
if (next) *next = mbstr + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (next) *next = mbstr + len;
|
||||
int width = mk_wcwidth(c32);
|
||||
return width < 0 ? 0 : (uint8_t) width;
|
||||
}
|
||||
|
||||
static inline uint32_t getWcsWidth(const FFstrbuf* mbstr, wchar_t* wstr, mbstate_t* state)
|
||||
static uint32_t getWcsWidth(const FFstrbuf* mbstr)
|
||||
{
|
||||
int result = 1;
|
||||
for (uint32_t i = 0; i < mbstr->length; i++)
|
||||
{
|
||||
if (!isascii(mbstr->chars[i]))
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (__builtin_expect(result, 1)) return mbstr->length;
|
||||
mbstate_t state = {};
|
||||
uint32_t remainLength = mbstr->length;
|
||||
uint32_t result = 0;
|
||||
|
||||
const char* ptr = mbstr->chars;
|
||||
while (remainLength > 0 && *ptr != '\0')
|
||||
{
|
||||
const char* lastPtr = NULL;
|
||||
result += getMbrWidth(ptr, remainLength, &lastPtr, &state);
|
||||
remainLength -= (uint32_t)(lastPtr - ptr);
|
||||
ptr = lastPtr;
|
||||
}
|
||||
|
||||
const char* str = mbstr->chars;
|
||||
uint32_t wstrLength = (uint32_t) mbsrtowcs(wstr, &str, mbstr->length, state);
|
||||
result = mk_wcswidth(wstr, wstrLength);
|
||||
return result > 0 ? (uint32_t) result : mbstr->length;
|
||||
}
|
||||
|
||||
@@ -55,14 +80,10 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
|
||||
else
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
mbstate_t state = {};
|
||||
const FFPlatform* platform = &instance.state.platform;
|
||||
|
||||
FF_AUTO_FREE wchar_t* wstr = malloc((max(
|
||||
platform->userName.length, options->string.length) + 1) * sizeof(*wstr));
|
||||
|
||||
uint32_t titleLength = 1 // @
|
||||
+ getWcsWidth(&platform->userName, wstr, &state) // user name
|
||||
+ getWcsWidth(&platform->userName) // user name
|
||||
+ (instance.state.titleFqdn ? platform->hostName.length : ffStrbufFirstIndexC(&platform->hostName, '.')); // host name
|
||||
|
||||
if(__builtin_expect(options->string.length == 1, 1))
|
||||
@@ -71,7 +92,7 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t wcsLength = getWcsWidth(&options->string, wstr, &state);
|
||||
uint32_t wcsLength = getWcsWidth(&options->string);
|
||||
|
||||
int remaining = (int) titleLength;
|
||||
//Write the whole separator as often as it fits fully into titleLength
|
||||
@@ -84,24 +105,19 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
|
||||
if (wcsLength != options->string.length)
|
||||
{
|
||||
// Unicode chars
|
||||
for(int i = 0; remaining > 0; ++i)
|
||||
const char* ptr = options->string.chars;
|
||||
mbstate_t state = {};
|
||||
const char* next = NULL;
|
||||
while (remaining > 0 && *ptr != '\0')
|
||||
{
|
||||
#ifdef __linux__
|
||||
// https://stackoverflow.com/questions/75126743/i-have-difficulties-with-putwchar-in-c#answer-75137784
|
||||
char wch[16] = "";
|
||||
uint32_t wchLength = (uint32_t) wcrtomb(wch, wstr[i], &state);
|
||||
fwrite(wch, wchLength, 1, stdout);
|
||||
#else
|
||||
putwchar(wstr[i]);
|
||||
#endif
|
||||
int width = mk_wcwidth(wstr[i]);
|
||||
remaining -= width < 0 ? 0 : width;
|
||||
remaining -= (int) getMbrWidth(ptr, (uint32_t)(options->string.length - (ptr - options->string.chars)), &next, &state);
|
||||
ptr = next;
|
||||
}
|
||||
fwrite(options->string.chars, (size_t) (ptr - options->string.chars), 1, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < remaining; i++)
|
||||
putchar(options->string.chars[i]);
|
||||
fwrite(options->string.chars, (size_t) remaining, 1, stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user