From 89c6c3940520acec39f1c2aabe7cbfc942a6ac89 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Mon, 1 Aug 2022 11:27:03 +0100 Subject: [PATCH] stdio: support for UTF-8 %lc in printf() --- include/fxlibc/printf.h | 8 ++------ src/stdio/printf/format_usual.c | 22 +++++++++++++++++++++- src/stdio/printf/print.c | 8 ++++++-- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/include/fxlibc/printf.h b/include/fxlibc/printf.h index 828ebff..bac624e 100644 --- a/include/fxlibc/printf.h +++ b/include/fxlibc/printf.h @@ -85,12 +85,8 @@ struct __printf_format { int16_t precision; /* - ** Size specifier for integers (%o, %x, %i, %d, %u), may be one of: - ** (0) char (8-bit) - ** (1) short (16-bit) - ** (2) int (32-bit) - ** (3) long (32-bit) - ** (4) long long (64-bit) + ** Size specifier for integers (%o, %x, %i, %d, %u), is equal to the + ** sizeof() of the targeted type. Also used for %lc. */ uint8_t size; diff --git a/src/stdio/printf/format_usual.c b/src/stdio/printf/format_usual.c index cfcc5f3..7c8eb64 100644 --- a/src/stdio/printf/format_usual.c +++ b/src/stdio/printf/format_usual.c @@ -19,7 +19,27 @@ void __printf_format_c( __printf_compute_geometry(opt, &g); __printf_outn(out, ' ', g.left_spaces); - __printf_out(out, c); + + /* When using %lc, output as UTF-8 */ + if(opt->size != 4 || c <= 0x7f) { + __printf_out(out, c); + } + else if(c <= 0x7ff) { + __printf_out(out, 0xc0 | (c >> 6)); + __printf_out(out, 0x80 | (c & 0x3f)); + } + else if(c <= 0xffff) { + __printf_out(out, 0xe0 | (c >> 12)); + __printf_out(out, 0x80 | ((c >> 6) & 0x3f)); + __printf_out(out, 0x80 | (c & 0x3f)); + } + else { + __printf_out(out, 0xf0 | (c >> 18)); + __printf_out(out, 0x80 | ((c >> 12) & 0x3f)); + __printf_out(out, 0x80 | ((c >> 6) & 0x3f)); + __printf_out(out, 0x80 | (c & 0x3f)); + } + __printf_outn(out, ' ', g.right_spaces); } diff --git a/src/stdio/printf/print.c b/src/stdio/printf/print.c index 7b0efc3..e3269ff 100644 --- a/src/stdio/printf/print.c +++ b/src/stdio/printf/print.c @@ -125,8 +125,8 @@ void __printf_flush(struct __printf_output *out) /* Parse format strings. */ static struct __printf_format parse_fmt(char const * restrict *options_ptr) { - /* No options enabled by default, set the size to int */ - struct __printf_format opt = { .size = sizeof(int), .precision = -1 }; + /* No options enabled by default; default size is set at the end */ + struct __printf_format opt = { .size = 0, .precision = -1 }; /* This function acts as a deterministic finite automaton */ enum { @@ -252,6 +252,10 @@ int __printf( opt = parse_fmt(&format); opt.spec = *format++; + /* Set default size to 1 for %c, 4 otherwise */ + if(opt.size == 0) + opt.size = (opt.spec == 'c') ? 1 : 4; + int id; if(isupper(opt.spec)) id = opt.spec - 'A';