diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-07-11 11:17:59 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-07-11 11:17:59 +0000 |
commit | b271a8c98d7301482d5b4eb2c7d79b7e1a1fc368 (patch) | |
tree | 1d8dafbbbfc506d1b562fc78984ccf42d18599c6 | |
parent | db3ddad3a710de4f0c6ef5d47493c5f7ba9b7384 (diff) | |
download | ruby-b271a8c98d7301482d5b4eb2c7d79b7e1a1fc368.tar.gz |
string.c: multi-byte terminator
* string.c (rb_string_value_cstr): fill minimum length of the encoding
as the terminator.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41919 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | ext/-test-/string/cstr.c | 8 | ||||
-rw-r--r-- | string.c | 30 | ||||
-rw-r--r-- | test/-ext-/string/test_cstr.rb | 10 |
4 files changed, 48 insertions, 5 deletions
@@ -1,4 +1,7 @@ -Thu Jul 11 20:17:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> +Thu Jul 11 20:17:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * string.c (rb_string_value_cstr): fill minimum length of the encoding + as the terminator. * string.c (rb_string_value_cstr): check null char in char, not in byte. diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c index d4ff360575..c2ed410b41 100644 --- a/ext/-test-/string/cstr.c +++ b/ext/-test-/string/cstr.c @@ -1,16 +1,22 @@ #include "ruby.h" +#include "ruby/encoding.h" static VALUE bug_str_cstr_term(VALUE str) { long len; char *s; + int c; + rb_encoding *enc; + rb_str_modify(str); len = RSTRING_LEN(str); RSTRING_PTR(str)[len] = 'x'; s = StringValueCStr(str); rb_gc(); - return INT2NUM(s[len]); + enc = rb_enc_get(str); + c = rb_enc_codepoint(&s[len], &s[len+rb_enc_mbminlen(enc)], enc); + return INT2NUM(c); } void @@ -91,6 +91,15 @@ VALUE rb_cSymbol; }\ } while (0) +#define TERM_LEN(str) rb_enc_mbminlen(rb_enc_get(str)) +#define TERM_FILL(ptr, termlen) do {\ + char *const term_fill_ptr = (ptr);\ + const int term_fill_len = (termlen);\ + *term_fill_ptr = '\0';\ + if (UNLIKELY(term_fill_len > 1))\ + memset(term_fill_ptr, 0, term_fill_len);\ +} while (0) + #define RESIZE_CAPA(str,capacity) do {\ if (STR_EMBED_P(str)) {\ if ((capacity) > RSTRING_EMBED_LEN_MAX) {\ @@ -1471,6 +1480,25 @@ str_null_char(const char *s, long len, rb_encoding *enc) return 0; } +static char * +str_fill_term(VALUE str, char *s, long len, int termlen, rb_encoding *enc) +{ + long capa = rb_str_capacity(str) + 1; + int n; + + if (capa < len + termlen) { + rb_str_modify_expand(str, len + termlen - capa); + } + else { + const char *e = s + len; + if (!rb_enc_ascget(e, e + termlen, &n, enc)) return s; + rb_str_modify(str); + } + s = RSTRING_PTR(str); + TERM_FILL(s + len, termlen); + return s; +} + char * rb_string_value_cstr(volatile VALUE *ptr) { @@ -1484,8 +1512,8 @@ rb_string_value_cstr(volatile VALUE *ptr) if (str_null_char(s, len, enc)) { rb_raise(rb_eArgError, "string contains null char"); } + return str_fill_term(str, s, len, minlen, enc); } - else if (!s || memchr(s, 0, len)) { rb_raise(rb_eArgError, "string contains null byte"); } diff --git a/test/-ext-/string/test_cstr.rb b/test/-ext-/string/test_cstr.rb index 8ea86aa6da..f691da6f79 100644 --- a/test/-ext-/string/test_cstr.rb +++ b/test/-ext-/string/test_cstr.rb @@ -19,18 +19,24 @@ class Test_StringCStr < Test::Unit::TestCase def test_wchar_embed WCHARS.each do |enc| - s = Bug::String.new("ab".encode(enc)) + s = Bug::String.new("\u{4022}a".encode(enc)) assert_nothing_raised(ArgumentError) {s.cstr_term} + s.set_len(s.bytesize / 2) + assert_equal(1, s.size) + assert_equal(0, s.cstr_term) end end def test_wchar_long - str = "abcdef" + str = "\u{4022}abcdef" n = 100 len = str.size * n WCHARS.each do |enc| s = Bug::String.new(str.encode(enc))*n assert_nothing_raised(ArgumentError) {s.cstr_term} + s.set_len(s.bytesize / 2) + assert_equal(len / 2, s.size) + assert_equal(0, s.cstr_term) end end end |