diff options
| -rw-r--r-- | doc/language/packed_data.rdoc | 5 | ||||
| -rw-r--r-- | pack.c | 4 | ||||
| -rw-r--r-- | spec/ruby/core/string/unpack/carret_spec.rb | 43 | ||||
| -rw-r--r-- | test/ruby/test_pack.rb | 28 |
4 files changed, 80 insertions, 0 deletions
diff --git a/doc/language/packed_data.rdoc b/doc/language/packed_data.rdoc index 2dce7bb57c..1a6d80bd4e 100644 --- a/doc/language/packed_data.rdoc +++ b/doc/language/packed_data.rdoc @@ -100,6 +100,7 @@ These tables summarize the directives for packing and unpacking. @ | skip to the offset given by the length argument X | skip backward one byte x | skip forward one byte + ^ | return the current offset == Packing and Unpacking @@ -722,3 +723,7 @@ for one byte in the input or output string. "\x00\x00\x02".unpack("CxC") # => [0, 2] "\x00\x00\x02".unpack("x3C") # => [nil] "\x00\x00\x02".unpack("x4C") # Raises ArgumentError + +- <tt>'^'</tt> - Only for unpacking; the current position: + + "foo\0\0\0".unpack("Z*C") # => ["foo", 6] @@ -1570,6 +1570,10 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset) s += len; break; + case '^': + UNPACK_PUSH(SSIZET2NUM(s - RSTRING_PTR(str))); + break; + case 'P': if (sizeof(char *) <= (size_t)(send - s)) { VALUE tmp = Qnil; diff --git a/spec/ruby/core/string/unpack/carret_spec.rb b/spec/ruby/core/string/unpack/carret_spec.rb new file mode 100644 index 0000000000..815df0c718 --- /dev/null +++ b/spec/ruby/core/string/unpack/carret_spec.rb @@ -0,0 +1,43 @@ +# encoding: binary +ruby_version_is "4.1" do + require_relative '../../../spec_helper' + require_relative '../fixtures/classes' + require_relative 'shared/basic' + + describe "String#unpack with format '^'" do + it_behaves_like :string_unpack_basic, '^' + it_behaves_like :string_unpack_no_platform, '^' + + it "returns the current offset that start from 0" do + "".unpack("^").should == [0] + end + + it "returns the current offset after the last decode ended" do + "a".unpack("CC^").should == [97, nil, 1] + end + + it "returns the current offset that start from the given offset" do + "abc".unpack("^", offset: 1).should == [1] + end + + it "returns the offset moved by 'X'" do + "\x01\x02\x03\x04".unpack("C3X2^").should == [1, 2, 3, 1] + end + + it "returns the offset moved by 'x'" do + "\x01\x02\x03\x04".unpack("Cx2^").should == [1, 3] + end + + it "returns the offset to the position the previous decode ended" do + "foo".unpack("A4^").should == ["foo", 3] + "foo".unpack("a4^").should == ["foo", 3] + "foo".unpack("Z5^").should == ["foo", 3] + end + + it "returns the offset including truncated part" do + "foo ".unpack("A*^").should == ["foo", 6] + "foo\0".unpack("Z*^").should == ["foo", 4] + "foo\0\0\0".unpack("Z5^").should == ["foo", 5] + end + end +end diff --git a/test/ruby/test_pack.rb b/test/ruby/test_pack.rb index 9c40cfaa20..c23b2832f5 100644 --- a/test/ruby/test_pack.rb +++ b/test/ruby/test_pack.rb @@ -283,6 +283,15 @@ class TestPack < Test::Unit::TestCase assert_equal(["foo "], "foo ".unpack("a4")) assert_equal(["foo"], "foo".unpack("A4")) assert_equal(["foo"], "foo".unpack("a4")) + + assert_equal(["foo", 4], "foo\0 ".unpack("A4^")) + assert_equal(["foo\0", 4], "foo\0 ".unpack("a4^")) + assert_equal(["foo", 4], "foo ".unpack("A4^")) + assert_equal(["foo ", 4], "foo ".unpack("a4^")) + assert_equal(["foo", 3], "foo".unpack("A4^")) + assert_equal(["foo", 3], "foo".unpack("a4^")) + assert_equal(["foo", 6], "foo\0 ".unpack("A*^")) + assert_equal(["foo", 6], "foo ".unpack("A*^")) end def test_pack_unpack_Z @@ -298,6 +307,11 @@ class TestPack < Test::Unit::TestCase assert_equal(["foo"], "foo".unpack("Z*")) assert_equal(["foo"], "foo\0".unpack("Z*")) assert_equal(["foo"], "foo".unpack("Z5")) + + assert_equal(["foo", 3], "foo".unpack("Z*^")) + assert_equal(["foo", 4], "foo\0".unpack("Z*^")) + assert_equal(["foo", 3], "foo".unpack("Z5^")) + assert_equal(["foo", 5], "foo\0\0\0".unpack("Z5^")) end def test_pack_unpack_bB @@ -549,6 +563,8 @@ class TestPack < Test::Unit::TestCase assert_equal([0, 2], "\x00\x00\x02".unpack("CxC")) assert_raise(ArgumentError) { "".unpack("x") } + + assert_equal([0, 1, 2, 2, 3], "\x00\x00\x02".unpack("C^x^C^")) end def test_pack_unpack_X @@ -558,6 +574,7 @@ class TestPack < Test::Unit::TestCase assert_equal([0, 2, 2], "\x00\x02".unpack("CCXC")) assert_raise(ArgumentError) { "".unpack("X") } + assert_equal([0, 1, 2, 2, 1, 2, 2], "\x00\x02".unpack("C^C^X^C^")) end def test_pack_unpack_atmark @@ -571,6 +588,17 @@ class TestPack < Test::Unit::TestCase pos = RbConfig::LIMITS["UINTPTR_MAX"] - 99 # -100 assert_raise(RangeError) {"0123456789".unpack("@#{pos}C10")} + + assert_equal([1, 3, 4], "\x01\x00\x00\x02".unpack("x^@3^x^")) + end + + def test_unpack_carret + assert_equal([0], "abc".unpack("^")) + assert_equal([2], "abc".unpack("^", offset: 2)) + assert_equal([97, nil, 1], "a".unpack("CC^")) + + assert_raise(ArgumentError) { "".unpack("^!") } + assert_raise(ArgumentError) { "".unpack("^_") } end def test_pack_unpack_percent |
