diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-09-16 05:50:00 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-09-16 05:50:00 +0000 |
commit | 965d8241c1ac3556685a833206d644bd6c7dc646 (patch) | |
tree | 0cd1be11831d65517b08c912815a33d230f2948e /string.c | |
parent | 22190b3f32010075c1dacd6d9cbec3fa488a6187 (diff) | |
download | ruby-965d8241c1ac3556685a833206d644bd6c7dc646.tar.gz |
string.c: keep coderange
* string.c (rb_str_setbyte): keep the code range as possible.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51873 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r-- | string.c | 45 |
1 files changed, 43 insertions, 2 deletions
@@ -4702,15 +4702,56 @@ rb_str_setbyte(VALUE str, VALUE index, VALUE value) long pos = NUM2LONG(index); int byte = NUM2INT(value); long len = RSTRING_LEN(str); + char *head, *ptr, *left = 0; + rb_encoding *enc; + int cr = ENC_CODERANGE_UNKNOWN, width, nlen; if (pos < -len || len <= pos) rb_raise(rb_eIndexError, "index %ld out of string", pos); if (pos < 0) pos += len; - rb_str_modify(str); + if (!str_independent(str)) + str_make_independent(str); + enc = STR_ENC_GET(str); + head = RSTRING_PTR(str); + ptr = &head[pos]; + if (len > RSTRING_EMBED_LEN_MAX) { + cr = ENC_CODERANGE(str); + switch (cr) { + case ENC_CODERANGE_7BIT: + left = ptr; + width = 1; + break; + case ENC_CODERANGE_VALID: + left = rb_enc_left_char_head(head, ptr, head+len, enc); + width = rb_enc_precise_mbclen(left, head+len, enc); + break; + default: + ENC_CODERANGE_CLEAR(str); + } + } + else { + ENC_CODERANGE_CLEAR(str); + } + + *ptr = byte; - RSTRING_PTR(str)[pos] = byte; + switch (cr) { + case ENC_CODERANGE_7BIT: + if (ISASCII(byte)) break; + case ENC_CODERANGE_VALID: + nlen = rb_enc_precise_mbclen(left, head+len, enc); + if (!MBCLEN_CHARFOUND_P(nlen)) + ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN); + else if (cr == ENC_CODERANGE_7BIT) + ENC_CODERANGE_SET(str, ENC_CODERANGE_VALID); + else if (MBCLEN_CHARFOUND_LEN(nlen) != width) + ENC_CODERANGE_CLEAR(str); + else if (ISASCII(byte)) /* may become 7BIT */ + ENC_CODERANGE_CLEAR(str); + break; + } return value; } |