зеркало из https://github.com/github/ruby.git
setbyte / ungetbyte allow out-of-range integers
* string.c: String#setbyte to accept arbitrary integers [Bug #15460] * io.c: ditto for IO#ungetbyte * ext/strringio/stringio.c: ditto for StringIO#ungetbyte git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66824 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
5e84537d32
Коммит
d154bec0d5
|
@ -805,33 +805,26 @@ strio_ungetbyte(VALUE self, VALUE c)
|
|||
struct StringIO *ptr = readable(self);
|
||||
|
||||
check_modifiable(ptr);
|
||||
if (NIL_P(c)) return Qnil;
|
||||
if (FIXNUM_P(c)) {
|
||||
int i = FIX2INT(c);
|
||||
if (0 <= i && i <= UCHAR_MAX) {
|
||||
char buf[1];
|
||||
buf[0] = (char)i;
|
||||
return strio_unget_bytes(ptr, buf, 1);
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eRangeError,
|
||||
"integer %d too big to convert into `unsigned char'", i);
|
||||
}
|
||||
}
|
||||
else if (RB_TYPE_P(c, T_BIGNUM)) {
|
||||
rb_raise(rb_eRangeError, "bignum too big to convert into `unsigned char'");
|
||||
}
|
||||
else {
|
||||
char *cp;
|
||||
long cl;
|
||||
SafeStringValue(c);
|
||||
cp = RSTRING_PTR(c);
|
||||
cl = RSTRING_LEN(c);
|
||||
if (cl == 0) return Qnil;
|
||||
strio_unget_bytes(ptr, cp, cl);
|
||||
RB_GC_GUARD(c);
|
||||
return Qnil;
|
||||
switch (TYPE(c)) {
|
||||
case T_NIL:
|
||||
return Qnil;
|
||||
case T_FIXNUM:
|
||||
case T_BIGNUM: ;
|
||||
/* rb_int_modulo() not visible from exts */
|
||||
VALUE v = rb_funcall(c, rb_intern("modulo"), 1, INT2FIX(256));
|
||||
unsigned char cc = NUM2INT(v) & 0xFF;
|
||||
c = rb_str_new((const char *)&cc, 1);
|
||||
break;
|
||||
default:
|
||||
SafeStringValue(c);
|
||||
}
|
||||
|
||||
const char *cp = RSTRING_PTR(c);
|
||||
long cl = RSTRING_LEN(c);
|
||||
if (cl == 0) return Qnil;
|
||||
strio_unget_bytes(ptr, cp, cl);
|
||||
RB_GC_GUARD(c);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
|
28
io.c
28
io.c
|
@ -4258,23 +4258,17 @@ rb_io_ungetbyte(VALUE io, VALUE b)
|
|||
|
||||
GetOpenFile(io, fptr);
|
||||
rb_io_check_byte_readable(fptr);
|
||||
if (NIL_P(b)) return Qnil;
|
||||
if (FIXNUM_P(b)) {
|
||||
int i = FIX2INT(b);
|
||||
if (0 <= i && i <= UCHAR_MAX) {
|
||||
unsigned char cc = i & 0xFF;
|
||||
b = rb_str_new((const char *)&cc, 1);
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eRangeError,
|
||||
"integer %d too big to convert into `unsigned char'", i);
|
||||
}
|
||||
}
|
||||
else if (RB_TYPE_P(b, T_BIGNUM)) {
|
||||
rb_raise(rb_eRangeError, "bignum too big to convert into `unsigned char'");
|
||||
}
|
||||
else {
|
||||
SafeStringValue(b);
|
||||
switch (TYPE(b)) {
|
||||
case T_NIL:
|
||||
return Qnil;
|
||||
case T_FIXNUM:
|
||||
case T_BIGNUM: ;
|
||||
VALUE v = rb_int_modulo(b, INT2FIX(256));
|
||||
unsigned char c = NUM2INT(v) & 0xFF;
|
||||
b = rb_str_new((const char *)&c, 1);
|
||||
break;
|
||||
default:
|
||||
SafeStringValue(b);
|
||||
}
|
||||
io_ungetbyte(b, fptr);
|
||||
return Qnil;
|
||||
|
|
|
@ -49,7 +49,7 @@ describe "IO#ungetbyte" do
|
|||
end
|
||||
end
|
||||
|
||||
ruby_version_is '2.6' do
|
||||
ruby_version_is '2.6'...'2.7' do
|
||||
it "is an RangeError if the integer is not in 8bit" do
|
||||
for i in [4095, 0x4f7574206f6620636861722072616e6765] do
|
||||
lambda { @io.ungetbyte(i) }.should raise_error(RangeError)
|
||||
|
@ -57,6 +57,14 @@ describe "IO#ungetbyte" do
|
|||
end
|
||||
end
|
||||
|
||||
ruby_version_is '2.7' do
|
||||
it "never raises RangeError" do
|
||||
for i in [4095, 0x4f7574206f6620636861722072616e6765] do
|
||||
lambda { @io.ungetbyte(i) }.should_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an IOError if the IO is closed" do
|
||||
@io.close
|
||||
lambda { @io.ungetbyte(42) }.should raise_error(IOError)
|
||||
|
|
9
string.c
9
string.c
|
@ -5409,7 +5409,6 @@ static VALUE
|
|||
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
|
||||
{
|
||||
long pos = NUM2LONG(index);
|
||||
int byte = NUM2INT(value);
|
||||
long len = RSTRING_LEN(str);
|
||||
char *head, *left = 0;
|
||||
unsigned char *ptr;
|
||||
|
@ -5420,10 +5419,10 @@ rb_str_setbyte(VALUE str, VALUE index, VALUE value)
|
|||
rb_raise(rb_eIndexError, "index %ld out of string", pos);
|
||||
if (pos < 0)
|
||||
pos += len;
|
||||
if (byte < 0)
|
||||
rb_raise(rb_eRangeError, "integer %d too small to convert into `unsigned char'", byte);
|
||||
if (UCHAR_MAX < byte)
|
||||
rb_raise(rb_eRangeError, "integer %d too big to convert into `unsigned char'", byte);
|
||||
|
||||
VALUE v = rb_to_int(value);
|
||||
VALUE w = rb_int_modulo(v, INT2FIX(256));
|
||||
unsigned char byte = NUM2INT(w) & 0xFF;
|
||||
|
||||
if (!str_independent(str))
|
||||
str_make_independent(str);
|
||||
|
|
|
@ -1526,13 +1526,13 @@ class TestM17N < Test::Unit::TestCase
|
|||
|
||||
def test_setbyte_range
|
||||
s = u("\xE3\x81\x82\xE3\x81\x84")
|
||||
assert_raise(RangeError) { s.setbyte(0, -1) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x00) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x7F) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x80) }
|
||||
assert_nothing_raised { s.setbyte(0, 0xff) }
|
||||
assert_raise(RangeError) { s.setbyte(0, 0x100) }
|
||||
assert_raise(RangeError) { s.setbyte(0, 0x4f7574206f6620636861722072616e6765) }
|
||||
assert_nothing_raised { s.setbyte(0, -1) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x00) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x7F) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x80) }
|
||||
assert_nothing_raised { s.setbyte(0, 0xff) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x100) }
|
||||
assert_nothing_raised { s.setbyte(0, 0x4f7574206f6620636861722072616e6765) }
|
||||
end
|
||||
|
||||
def test_compatible
|
||||
|
|
|
@ -453,9 +453,9 @@ class TestStringIO < Test::Unit::TestCase
|
|||
assert_equal(0, t.pos)
|
||||
assert_equal("\u{30eb 30d3 30fc}\u7d05\u7389bar\n", s)
|
||||
|
||||
assert_raise(RangeError) {t.ungetbyte(-1)}
|
||||
assert_raise(RangeError) {t.ungetbyte(256)}
|
||||
assert_raise(RangeError) {t.ungetbyte(1<<64)}
|
||||
assert_nothing_raised {t.ungetbyte(-1)}
|
||||
assert_nothing_raised {t.ungetbyte(256)}
|
||||
assert_nothing_raised {t.ungetbyte(1<<64)}
|
||||
end
|
||||
|
||||
def test_ungetc
|
||||
|
|
Загрузка…
Ссылка в новой задаче