ruby-changes:29867
From: nobu <ko1@a...>
Date: Thu, 11 Jul 2013 20:18:13 +0900 (JST)
Subject: [ruby-changes:29867] nobu:r41919 (trunk): string.c: multi-byte terminator
nobu 2013-07-11 20:17:59 +0900 (Thu, 11 Jul 2013) New Revision: 41919 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41919 Log: string.c: multi-byte terminator * string.c (rb_string_value_cstr): fill minimum length of the encoding as the terminator. Modified files: trunk/ChangeLog trunk/ext/-test-/string/cstr.c trunk/string.c trunk/test/-ext-/string/test_cstr.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 41918) +++ ChangeLog (revision 41919) @@ -1,4 +1,7 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 -Thu Jul 11 20:17:51 2013 Nobuyoshi Nakada <nobu@r...> +Thu Jul 11 20:17:57 2013 Nobuyoshi Nakada <nobu@r...> + + * 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. Index: string.c =================================================================== --- string.c (revision 41918) +++ string.c (revision 41919) @@ -91,6 +91,15 @@ VALUE rb_cSymbol; https://github.com/ruby/ruby/blob/trunk/string.c#L91 }\ } 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, r https://github.com/ruby/ruby/blob/trunk/string.c#L1480 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 https://github.com/ruby/ruby/blob/trunk/string.c#L1512 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"); } Index: ext/-test-/string/cstr.c =================================================================== --- ext/-test-/string/cstr.c (revision 41918) +++ ext/-test-/string/cstr.c (revision 41919) @@ -1,16 +1,22 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/string/cstr.c#L1 #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 Index: test/-ext-/string/test_cstr.rb =================================================================== --- test/-ext-/string/test_cstr.rb (revision 41918) +++ test/-ext-/string/test_cstr.rb (revision 41919) @@ -19,18 +19,24 @@ class Test_StringCStr < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/test/-ext-/string/test_cstr.rb#L19 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/