summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2014-02-28 18:45:31 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2014-02-28 18:45:31 +0900
commitcb7f82ac452cf0e869d1a3e3e2e58e6bb25bf347 (patch)
treea6a916a891abf4fc89b9f23633f82aaaf9242c59
parent6bd3d88eddb8932bd02fadfbf2235c3cba2ad624 (diff)
parentd60944ef3aaebefa3380cc984d32c127b1ed1782 (diff)
downloadmruby-cb7f82ac452cf0e869d1a3e3e2e58e6bb25bf347.tar.gz
mruby-cb7f82ac452cf0e869d1a3e3e2e58e6bb25bf347.zip
Merge pull request #1756 from chasonr/sprintf-utf8
Implement sprintf("%c") for UTF-8.
-rw-r--r--mrbgems/mruby-numeric-ext/test/numeric.rb9
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c21
-rw-r--r--mrbgems/mruby-string-utf8/src/string.c37
3 files changed, 54 insertions, 13 deletions
diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb
index 7d85eaaa2..1ca01648e 100644
--- a/mrbgems/mruby-numeric-ext/test/numeric.rb
+++ b/mrbgems/mruby-numeric-ext/test/numeric.rb
@@ -5,6 +5,11 @@ assert('Integer#chr') do
assert_equal("A", 65.chr)
assert_equal("B", 0x42.chr)
- # multibyte encoding (not support yet)
- assert_raise(RangeError) { 12345.chr }
+ if "こんにちわ世界".size == 7 then
+ # UTF-8 gem is configured
+ assert_raise(RangeError) { 0x110000.chr }
+ else
+ # multibyte encoding (not support yet)
+ assert_raise(RangeError) { 256.chr }
+ end
end
diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c
index b20cbe1df..5b255d28e 100644
--- a/mrbgems/mruby-sprintf/src/sprintf.c
+++ b/mrbgems/mruby-sprintf/src/sprintf.c
@@ -666,38 +666,37 @@ retry:
case 'c': {
mrb_value val = GETARG();
mrb_value tmp;
- unsigned int c;
+ char *c;
tmp = mrb_check_string_type(mrb, val);
if (!mrb_nil_p(tmp)) {
- if (RSTRING_LEN(tmp) != 1 ) {
+ if (mrb_fixnum(mrb_funcall(mrb, tmp, "size", 0)) != 1 ) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
}
- c = RSTRING_PTR(tmp)[0];
- n = 1;
}
- else {
- c = mrb_fixnum(val);
- n = 1;
+ else if (mrb_fixnum_p(val)) {
+ tmp = mrb_funcall(mrb, val, "chr", 0);
}
- if (n <= 0) {
+ else {
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
}
+ c = RSTRING_PTR(tmp);
+ n = RSTRING_LEN(tmp);
if (!(flags & FWIDTH)) {
CHECK(n);
- buf[blen] = c;
+ memcpy(buf+blen, c, n);
blen += n;
}
else if ((flags & FMINUS)) {
CHECK(n);
- buf[blen] = c;
+ memcpy(buf+blen, c, n);
blen += n;
FILL(' ', width-1);
}
else {
FILL(' ', width-1);
CHECK(n);
- buf[blen] = c;
+ memcpy(buf+blen, c, n);
blen += n;
}
}
diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c
index 2dd848c86..4f3833944 100644
--- a/mrbgems/mruby-string-utf8/src/string.c
+++ b/mrbgems/mruby-string-utf8/src/string.c
@@ -279,6 +279,41 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
return mrb_str_reverse_bang(mrb, mrb_str_dup(mrb, str));
}
+static mrb_value
+mrb_fixnum_chr(mrb_state *mrb, mrb_value num)
+{
+ mrb_int cp = mrb_fixnum(num);
+ char utf8[4];
+ int len;
+
+ if (cp < 0 || 0x10FFFF < cp) {
+ mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num);
+ }
+ if (cp < 0x80) {
+ utf8[0] = (char)cp;
+ len = 1;
+ }
+ else if (cp < 0x800) {
+ utf8[0] = (char)(0xC0 | (cp >> 6));
+ utf8[1] = (char)(0x80 | (cp & 0x3F));
+ len = 2;
+ }
+ else if (cp < 0x10000) {
+ utf8[0] = (char)(0xE0 | (cp >> 12));
+ utf8[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
+ utf8[2] = (char)(0x80 | ( cp & 0x3F));
+ len = 3;
+ }
+ else {
+ utf8[0] = (char)(0xF0 | (cp >> 18));
+ utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
+ utf8[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
+ utf8[3] = (char)(0x80 | ( cp & 0x3F));
+ len = 4;
+ }
+ return mrb_str_new(mrb, utf8, len);
+}
+
void
mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
{
@@ -290,6 +325,8 @@ mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY());
mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
}
void