Index: pack.c =================================================================== --- pack.c (リビジョン 50745) +++ pack.c (作業コピー) @@ -23,11 +23,11 @@ * This behavior is consistent with the document of pack/unpack. */ #ifdef HAVE_TRUE_LONG_LONG -static const char natstr[] = "sSiIlLqQ"; +static const char natstr[] = "sSiIlLqQjJ"; #else -static const char natstr[] = "sSiIlL"; +static const char natstr[] = "sSiIlLjJ"; #endif -static const char endstr[] = "sSiIlLqQ"; +static const char endstr[] = "sSiIlLqQjJ"; #ifdef HAVE_TRUE_LONG_LONG /* It is intentional to use long long instead of LONG_LONG. */ @@ -264,11 +264,15 @@ rb_str_associated(VALUE str) * S | Integer | 16-bit unsigned, native endian (uint16_t) * L | Integer | 32-bit unsigned, native endian (uint32_t) * Q | Integer | 64-bit unsigned, native endian (uint64_t) + * J | Integer | pointer width unsigned, native endian (uintptr_t) + * | | (J is available since Ruby 2.3.) * | | * c | Integer | 8-bit signed (signed char) * s | Integer | 16-bit signed, native endian (int16_t) * l | Integer | 32-bit signed, native endian (int32_t) * q | Integer | 64-bit signed, native endian (int64_t) + * j | Integer | pointer width signed, native endian (intptr_t) + * | | (j is available since Ruby 2.3.) * | | * S_, S! | Integer | unsigned short, native endian * I, I_, I! | Integer | unsigned int, native endian @@ -276,6 +280,8 @@ rb_str_associated(VALUE str) * Q_, Q! | Integer | unsigned long long, native endian (ArgumentError * | | if the platform has no long long type.) * | | (Q_ and Q! is available since Ruby 2.1.) + * J! | Integer | uintptr_t, native endian (same with J) + * | | (J! is available since Ruby 2.3.) * | | * s_, s! | Integer | signed short, native endian * i, i_, i! | Integer | signed int, native endian @@ -283,20 +289,26 @@ rb_str_associated(VALUE str) * q_, q! | Integer | signed long long, native endian (ArgumentError * | | if the platform has no long long type.) * | | (q_ and q! is available since Ruby 2.1.) + * j! | Integer | intptr_t, native endian (same with j) + * | | (j! is available since Ruby 2.3.) * | | * S> L> Q> | Integer | same as the directives without ">" except - * s> l> q> | | big endian - * S!> I!> | | (available since Ruby 1.9.3) - * L!> Q!> | | "S>" is same as "n" - * s!> i!> | | "L>" is same as "N" - * l!> q!> | | + * J> s> l> | | big endian + * q> j> | | (available since Ruby 1.9.3) + * S!> I!> | | "S>" is same as "n" + * L!> Q!> | | "L>" is same as "N" + * J!> s!> | | + * i!> l!> | | + * q!> j!> | | * | | * S< L< Q< | Integer | same as the directives without "<" except - * s< l< q< | | little endian - * S!< I!< | | (available since Ruby 1.9.3) - * L!< Q!< | | "S<" is same as "v" - * s!< i!< | | "L<" is same as "V" - * l!< q!< | | + * J< s< l< | | little endian + * q< j< | | (available since Ruby 1.9.3) + * S!< I!< | | "S<" is same as "v" + * L!< Q!< | | "L<" is same as "V" + * J!< s!< | | + * i!< l!< | | + * q!< j!< | | * | | * n | Integer | 16-bit unsigned, network (big-endian) byte order * N | Integer | 32-bit unsigned, network (big-endian) byte order @@ -658,6 +670,16 @@ pack_pack(VALUE ary, VALUE fmt) bigendian_p = BIGENDIAN_P(); goto pack_integer; + case 'j': /* j for intptr_t */ + integer_size = sizeof(intptr_t); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; + + case 'J': /* j for intptr_t */ + integer_size = sizeof(uintptr_t); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; + case 'n': /* 16 bit (2 bytes) integer (network byte-order) */ integer_size = 2; bigendian_p = 1; @@ -1480,6 +1502,18 @@ pack_unpack(VALUE str, VALUE fmt) bigendian_p = BIGENDIAN_P(); goto unpack_integer; + case 'j': + signed_p = 1; + integer_size = sizeof(intptr_t); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; + + case 'J': + signed_p = 0; + integer_size = sizeof(uintptr_t); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; + case 'n': signed_p = 0; integer_size = 2; Index: test/ruby/test_pack.rb =================================================================== --- test/ruby/test_pack.rb (リビジョン 50745) +++ test/ruby/test_pack.rb (作業コピー) @@ -78,6 +78,14 @@ class TestPack < Test::Unit::TestCase assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"+mod)) assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"+mod)) assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"+mod)) + psize = [nil].pack('p').bytesize + if psize == 4 + assert_equal("\x01\x02\x03\x04", [0x01020304].pack("j"+mod)) + assert_equal("\x01\x02\x03\x04", [0x01020304].pack("J"+mod)) + elsif psize == 8 + assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("j"+mod)) + assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("J"+mod)) + end assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!"+mod)) assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i"+mod)) @@ -86,7 +94,14 @@ class TestPack < Test::Unit::TestCase assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"+mod)) assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"+mod)) - %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt| + if psize == 4 + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("j!"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("J!"+mod)) + elsif psize == 8 + assert_match(/\A\x00*\x01\x02\x03\x04\x05\x06\x07\x08\z/, [0x0102030405060708].pack("j!"+mod)) + assert_match(/\A\x00*\x01\x02\x03\x04\x05\x06\x07\x08\z/, [0x0102030405060708].pack("J!"+mod)) + end + %w[s S l L q Q j J s! S! i I i! I! l! L! j! J!].each {|fmt| fmt += mod nuls = [0].pack(fmt) v = 0 @@ -111,6 +126,14 @@ class TestPack < Test::Unit::TestCase assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"+mod)) assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"+mod)) assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"+mod)) + psize = [nil].pack('p').bytesize + if psize == 4 + assert_equal("\x04\x03\x02\x01", [0x01020304].pack("j"+mod)) + assert_equal("\x04\x03\x02\x01", [0x01020304].pack("J"+mod)) + elsif psize == 8 + assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("j"+mod)) + assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("J"+mod)) + end assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!"+mod)) assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!"+mod)) assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i"+mod)) @@ -119,7 +142,14 @@ class TestPack < Test::Unit::TestCase assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"+mod)) assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"+mod)) assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"+mod)) - %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt| + if psize == 4 + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("j!"+mod)) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("J!"+mod)) + elsif psize == 8 + assert_match(/\A\x08\x07\x06\x05\x04\x03\x02\x01\x00*\z/, [0x0102030405060708].pack("j!"+mod)) + assert_match(/\A\x08\x07\x06\x05\x04\x03\x02\x01\x00*\z/, [0x0102030405060708].pack("J!"+mod)) + end + %w[s S l L q Q j J s! S! i I i! I! l! L! j! J!].each {|fmt| fmt += mod nuls = [0].pack(fmt) v = 0 @@ -417,6 +447,43 @@ class TestPack < Test::Unit::TestCase assert_operator(8, :<=, [1].pack("Q!").bytesize) end + def test_pack_unpack_jJ + # Note: we assume that the size of intptr_t and uintptr_t equals to the size + # of real pointer. + psize = [nil].pack("p").bytesize + if psize == 4 + s1 = [67305985, -50462977].pack("j*") + s2 = [67305985, 4244504319].pack("J*") + assert_equal(s1, s2) + assert_equal([67305985, -50462977], s2.unpack("j*")) + assert_equal([67305985, 4244504319], s1.unpack("J*")) + + s1 = [67305985, -50462977].pack("j!*") + s2 = [67305985, 4244504319].pack("J!*") + assert_equal([67305985, -50462977], s1.unpack("j!*")) + assert_equal([67305985, 4244504319], s2.unpack("J!*")) + + assert_equal(4, [1].pack("j").bytesize) + assert_equal(4, [1].pack("J").bytesize) + elsif psize == 8 + s1 = [578437695752307201, -506097522914230529].pack("j*") + s2 = [578437695752307201, 17940646550795321087].pack("J*") + assert_equal(s1, s2) + assert_equal([578437695752307201, -506097522914230529], s2.unpack("j*")) + assert_equal([578437695752307201, 17940646550795321087], s1.unpack("J*")) + + s1 = [578437695752307201, -506097522914230529].pack("j!*") + s2 = [578437695752307201, 17940646550795321087].pack("J!*") + assert_equal([578437695752307201, -506097522914230529], s2.unpack("j!*")) + assert_equal([578437695752307201, 17940646550795321087], s1.unpack("J!*")) + + assert_equal(8, [1].pack("j").bytesize) + assert_equal(8, [1].pack("J").bytesize) + else + assert false, "we don't know such platform now." + end + end + def test_pack_unpack_nN assert_equal("\000\000\000\001\377\377\177\377\200\000\377\377", [0,1,-1,32767,-32768,65535].pack("n*")) assert_equal("\000\000\000\000\000\000\000\001\377\377\377\377", [0,1,-1].pack("N*"))