Separator: support Unicode / double width separator string

Fixes #504
This commit is contained in:
李通洲
2023-07-31 14:10:53 +08:00
parent f906d02720
commit b4d1c97d2c
7 changed files with 399 additions and 18 deletions
+54 -13
View File
@@ -2,19 +2,34 @@
#include "common/jsonconfig.h"
#include "modules/separator/separator.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "util/wcwidth.h"
static inline uint32_t max(uint32_t a, uint32_t b)
{
return a > b ? a : b;
}
static inline uint32_t getWcsWidth(const FFstrbuf* mbstr, wchar_t* wstr, mbstate_t* state)
{
const char* str = mbstr->chars;
uint32_t wstrLength = (uint32_t) mbsrtowcs(wstr, &str, mbstr->length, state);
int result = mk_wcswidth(wstr, wstrLength);
return result > 0 ? (uint32_t) result : mbstr->length;
}
void ffPrintSeparator(FFSeparatorOptions* options)
{
uint32_t titleLength = instance.state.titleLength;
if (titleLength == 0)
{
// Title was not printed, should we support this case?
titleLength = instance.state.platform.userName.length + 1 + (instance.config.title.fqdn ?
instance.state.platform.domainName.length :
instance.state.platform.hostName.length
);
}
mbstate_t state = {};
bool fqdn = instance.config.title.fqdn;
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
+ (fqdn ? platform->domainName.length : platform->hostName.length); // host name
ffLogoPrintLine();
if(options->string.length == 0)
@@ -23,13 +38,39 @@ void ffPrintSeparator(FFSeparatorOptions* options)
}
else
{
uint32_t wcsLength = getWcsWidth(&options->string, wstr, &state);
int remaining = (int) titleLength;
//Write the whole separator as often as it fits fully into titleLength
for(uint32_t i = 0; i < titleLength / options->string.length; i++)
for (; remaining >= (int) wcsLength; remaining -= (int) wcsLength)
ffStrbufWriteTo(&options->string, stdout);
//Write as much of the separator as needed to fill titleLength
for(uint32_t i = 0; i < titleLength % options->string.length; i++)
putchar(options->string.chars[i]);
if (remaining > 0)
{
//Write as much of the separator as needed to fill titleLength
if (wcsLength != options->string.length)
{
// Unicode chars
for(int i = 0; remaining > 0; ++i)
{
#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;
}
}
else
{
for(int i = 0; i < remaining; i++)
putchar(options->string.chars[i]);
}
}
}
putchar('\n');
}