string.c: add mrb_utf8_to_buf() to consolidate UTF-8 encoding

Extract duplicated UTF-8 codepoint-to-bytes encoding into a shared
function in src/string.c. Update all gems to use it:

- mruby-sprintf: %c specifier
- mruby-io: putc
- mruby-string-ext: Integer#chr
- mruby-pack: pack("U")
- mruby-compiler: Unicode escapes in parser

Also use existing mrb_utf8len() in io.c for character length detection.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-12-18 16:30:03 +09:00
parent 53fce124e6
commit 7e28e68dca
8 changed files with 50 additions and 142 deletions
+33
View File
@@ -316,6 +316,39 @@ mrb_gc_free_str(mrb_state *mrb, struct RString *str)
#define MASK01 0x01010101ul
#endif
/*
* Encode a Unicode codepoint to UTF-8 bytes.
* buf must have at least 4 bytes of space.
* Returns the number of bytes written (1-4), or 0 for invalid codepoint.
*/
mrb_int
mrb_utf8_to_buf(char *buf, uint32_t cp)
{
if (cp < 0x80) {
buf[0] = (char)cp;
return 1;
}
else if (cp < 0x800) {
buf[0] = (char)(0xC0 | (cp >> 6));
buf[1] = (char)(0x80 | (cp & 0x3F));
return 2;
}
else if (cp < 0x10000) {
buf[0] = (char)(0xE0 | (cp >> 12));
buf[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
buf[2] = (char)(0x80 | (cp & 0x3F));
return 3;
}
else if (cp <= 0x10FFFF) {
buf[0] = (char)(0xF0 | (cp >> 18));
buf[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
buf[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
buf[3] = (char)(0x80 | (cp & 0x3F));
return 4;
}
return 0; /* invalid codepoint */
}
#ifdef MRB_UTF8_STRING
#define NOASCII(c) ((c) & 0x80)