ruby-changes:16253
From: shyouhei <ko1@a...>
Date: Tue, 8 Jun 2010 17:43:05 +0900 (JST)
Subject: [ruby-changes:16253] Ruby:r28220 (ruby_1_8_7): merge revision(s) 27721:27725,27738:27740:
shyouhei 2010-06-08 17:42:55 +0900 (Tue, 08 Jun 2010) New Revision: 28220 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=28220 Log: merge revision(s) 27721:27725,27738:27740: * pack.c: backport integer pack/unpack from 1.9 for [ruby-core:21937]. * configure.in: backport RUBY_DEFINT and fixed size integer checks. * ruby.h: include stdint.h if available. * bignum.c (rb_big_pack): defined.. (rb_big_unpack): defined. * intern.h (rb_big_pack): declared. (rb_big_unpack): declared. * pack.c (pack_pack): call rb_quad_pack to preserve RangeError. Modified files: branches/ruby_1_8_7/ChangeLog branches/ruby_1_8_7/bignum.c branches/ruby_1_8_7/configure.in branches/ruby_1_8_7/intern.h branches/ruby_1_8_7/pack.c branches/ruby_1_8_7/ruby.h branches/ruby_1_8_7/test/ruby/test_pack.rb branches/ruby_1_8_7/version.h Index: ruby_1_8_7/intern.h =================================================================== --- ruby_1_8_7/intern.h (revision 28219) +++ ruby_1_8_7/intern.h (revision 28220) @@ -83,6 +83,8 @@ #endif /* HAVE_LONG_LONG */ void rb_quad_pack _((char*,VALUE)); VALUE rb_quad_unpack _((const char*,int)); +void rb_big_pack(VALUE val, unsigned long *buf, long num_longs); +VALUE rb_big_unpack(unsigned long *buf, long num_longs); VALUE rb_dbl2big _((double)); double rb_big2dbl _((VALUE)); VALUE rb_big_plus _((VALUE, VALUE)); Index: ruby_1_8_7/configure.in =================================================================== --- ruby_1_8_7/configure.in (revision 28219) +++ ruby_1_8_7/configure.in (revision 28220) @@ -544,6 +544,43 @@ AC_STRUCT_ST_BLOCKS AC_STRUCT_ST_RDEV +dnl RUBY_DEFINT TYPENAME, SIZE, [SIGNED-OR-UNSIGNED], [INCLUDES = DEFAULT-INCLUDES] +AC_DEFUN([RUBY_DEFINT], [dnl +AC_CACHE_CHECK([for $1], [rb_cv_type_$1], +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$4]) +typedef $1 t; int s = sizeof(t) == 42;])], + [rb_cv_type_$1=yes], + [AS_CASE([m4_bmatch([$2], [^[1-9][0-9]*$], $2, [$ac_cv_sizeof_]AS_TR_SH($2))], + ["1"], [ rb_cv_type_$1="m4_if([$3], [], [signed ], [$3 ])char"], + ["$ac_cv_sizeof_short"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])short"], + ["$ac_cv_sizeof_int"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])int"], + ["$ac_cv_sizeof_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long"], + ["$ac_cv_sizeof_long_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long long"], + ["$ac_cv_sizeof___int64"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int64"], + [ rb_cv_type_$1=no])])]) +if test "${rb_cv_type_$1}" != no; then + AC_DEFINE([HAVE_]AS_TR_CPP($1), 1) + if test "${rb_cv_type_$1}" = yes; then + m4_bmatch([$2], [^[1-9][0-9]*$], [AC_CHECK_SIZEOF([$1], 0, [AC_INCLUDES_DEFAULT([$4])])], + [RUBY_CHECK_SIZEOF([$1], [$2], [], [AC_INCLUDES_DEFAULT([$4])])]) + else + AC_DEFINE_UNQUOTED($1, [$rb_cv_type_$1]) + AC_DEFINE_UNQUOTED([SIZEOF_]AS_TR_CPP($1), [SIZEOF_]AS_TR_CPP([$rb_cv_type_$1])) + fi +fi +]) + +RUBY_DEFINT(int8_t, 1) +RUBY_DEFINT(uint8_t, 1, unsigned) +RUBY_DEFINT(int16_t, 2) +RUBY_DEFINT(uint16_t, 2, unsigned) +RUBY_DEFINT(int32_t, 4) +RUBY_DEFINT(uint32_t, 4, unsigned) +RUBY_DEFINT(int64_t, 8) +RUBY_DEFINT(uint64_t, 8, unsigned) +RUBY_DEFINT(int128_t, 16) +RUBY_DEFINT(uint128_t, 16, unsigned) + dnl Checks for library functions. AC_TYPE_GETGROUPS AC_TYPE_SIGNAL Index: ruby_1_8_7/ChangeLog =================================================================== --- ruby_1_8_7/ChangeLog (revision 28219) +++ ruby_1_8_7/ChangeLog (revision 28220) @@ -1,3 +1,21 @@ +Tue Jun 8 17:32:37 2010 Tanaka Akira <akr@f...> + + * pack.c (pack_pack): call rb_quad_pack to preserve RangeError. + +Tue Jun 8 17:32:37 2010 Tanaka Akira <akr@f...> + + * pack.c: backport integer pack/unpack from 1.9 for [ruby-core:21937]. + + * configure.in: backport RUBY_DEFINT and fixed size integer checks. + + * ruby.h: include stdint.h if available. + + * bignum.c (rb_big_pack): defined.. + (rb_big_unpack): defined. + + * intern.h (rb_big_pack): declared. + (rb_big_unpack): declared. + Tue Jun 8 16:52:35 2010 Nobuyoshi Nakada <nobu@r...> * regex.c (read_special): get rid of overrun. Index: ruby_1_8_7/version.h =================================================================== --- ruby_1_8_7/version.h (revision 28219) +++ ruby_1_8_7/version.h (revision 28220) @@ -2,7 +2,7 @@ #define RUBY_RELEASE_DATE "2010-06-08" #define RUBY_VERSION_CODE 187 #define RUBY_RELEASE_CODE 20100608 -#define RUBY_PATCHLEVEL 284 +#define RUBY_PATCHLEVEL 285 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 Index: ruby_1_8_7/pack.c =================================================================== --- ruby_1_8_7/pack.c (revision 28219) +++ ruby_1_8_7/pack.c (revision 28220) @@ -14,6 +14,12 @@ #include <sys/types.h> #include <ctype.h> +#define GCC_VERSION_SINCE(major, minor, patchlevel) \ + (defined(__GNUC__) && !defined(__INTEL_COMPILER) && \ + ((__GNUC__ > (major)) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ > (minor)) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patchlevel)))) + #define SIZE16 2 #define SIZE32 4 @@ -21,34 +27,41 @@ # define NATINT_PACK #endif +#ifdef DYNAMIC_ENDIAN + /* for universal binary of NEXTSTEP and MacOS X */ + /* useless since autoconf 2.63? */ + static int + is_bigendian(void) + { + static int init = 0; + static int endian_value; + char *p; + + if (init) return endian_value; + init = 1; + p = (char*)&init; + return endian_value = p[0]?0:1; + } +# define BIGENDIAN_P() (is_bigendian()) +#elif defined(WORDS_BIGENDIAN) +# define BIGENDIAN_P() 1 +#else +# define BIGENDIAN_P() 0 +#endif + #ifdef NATINT_PACK -# define OFF16B(p) ((char*)(p) + (natint?0:(sizeof(short) - SIZE16))) -# define OFF32B(p) ((char*)(p) + (natint?0:(sizeof(long) - SIZE32))) -# define NATINT_LEN(type,len) (natint?sizeof(type):(len)) -# ifdef WORDS_BIGENDIAN -# define OFF16(p) OFF16B(p) -# define OFF32(p) OFF32B(p) -# endif -# define NATINT_HTOVS(x) (natint?htovs(x):htov16(x)) -# define NATINT_HTOVL(x) (natint?htovl(x):htov32(x)) -# define NATINT_HTONS(x) (natint?htons(x):hton16(x)) -# define NATINT_HTONL(x) (natint?htonl(x):hton32(x)) +# define NATINT_LEN(type,len) (natint?(int)sizeof(type):(int)(len)) #else -# define NATINT_LEN(type,len) sizeof(type) -# define NATINT_HTOVS(x) htovs(x) -# define NATINT_HTOVL(x) htovl(x) -# define NATINT_HTONS(x) htons(x) -# define NATINT_HTONL(x) htonl(x) +# define NATINT_LEN(type,len) ((int)sizeof(type)) #endif -#ifndef OFF16 -# define OFF16(p) (char*)(p) -# define OFF32(p) (char*)(p) +#if SIZEOF_LONG == 8 +# define INT64toNUM(x) LONG2NUM(x) +# define UINT64toNUM(x) ULONG2NUM(x) +#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 +# define INT64toNUM(x) LL2NUM(x) +# define UINT64toNUM(x) ULL2NUM(x) #endif -#ifndef OFF16B -# define OFF16B(p) (char*)(p) -# define OFF32B(p) (char*)(p) -#endif #define define_swapx(x, xtype) \ static xtype \ @@ -73,262 +86,185 @@ return r; \ } +#if GCC_VERSION_SINCE(4,3,0) +# define swap32(x) __builtin_bswap32(x) +# define swap64(x) __builtin_bswap64(x) +#endif + #ifndef swap16 -#define swap16(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) +# define swap16(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) #endif -#if SIZEOF_SHORT == 2 -#define swaps(x) swap16(x) -#else -#if SIZEOF_SHORT == 4 -#define swaps(x) ((((x)&0xFF)<<24) \ + +#ifndef swap32 +# define swap32(x) ((((x)&0xFF)<<24) \ |(((x)>>24)&0xFF) \ |(((x)&0x0000FF00)<<8) \ |(((x)&0x00FF0000)>>8) ) +#endif + +#ifndef swap64 +# ifdef HAVE_INT64_T +# define byte_in_64bit(n) ((uint64_t)0xff << (n)) +# define swap64(x) ((((x)&byte_in_64bit(0))<<56) \ + |(((x)>>56)&0xFF) \ + |(((x)&byte_in_64bit(8))<<40) \ + |(((x)&byte_in_64bit(48))>>40) \ + |(((x)&byte_in_64bit(16))<<24) \ + |(((x)&byte_in_64bit(40))>>24) \ + |(((x)&byte_in_64bit(24))<<8) \ + |(((x)&byte_in_64bit(32))>>8)) +# endif +#endif + +#if SIZEOF_SHORT == 2 +# define swaps(x) swap16(x) +#elif SIZEOF_SHORT == 4 +# define swaps(x) swap32(x) #else -define_swapx(s,short) + define_swapx(s,short) #endif + +#if SIZEOF_INT == 2 +# define swapi(x) swap16(x) +#elif SIZEOF_INT == 4 +# define swapi(x) swap32(x) +#else + define_swapx(i,int) #endif -#ifndef swap32 -#define swap32(x) ((((x)&0xFF)<<24) \ - |(((x)>>24)&0xFF) \ - |(((x)&0x0000FF00)<<8) \ - |(((x)&0x00FF0000)>>8) ) -#endif #if SIZEOF_LONG == 4 -#define swapl(x) swap32(x) +# define swapl(x) swap32(x) +#elif SIZEOF_LONG == 8 +# define swapl(x) swap64(x) #else -#if SIZEOF_LONG == 8 -#define swapl(x) ((((x)&0x00000000000000FF)<<56) \ - |(((x)&0xFF00000000000000)>>56) \ - |(((x)&0x000000000000FF00)<<40) \ - |(((x)&0x00FF000000000000)>>40) \ - |(((x)&0x0000000000FF0000)<<24) \ - |(((x)&0x0000FF0000000000)>>24) \ - |(((x)&0x00000000FF000000)<<8) \ - |(((x)&0x000000FF00000000)>>8)) -#else -define_swapx(l,long) + define_swapx(l,long) #endif + +#ifdef HAVE_LONG_LONG +# if SIZEOF_LONG_LONG == 8 +# define swapll(x) swap64(x) +# else + define_swapx(ll,LONG_LONG) +# endif #endif #if SIZEOF_FLOAT == 4 -#if SIZEOF_LONG == 4 /* SIZEOF_FLOAT == 4 == SIZEOF_LONG */ -#define swapf(x) swapl(x) -#define FLOAT_SWAPPER unsigned long -#else -#if SIZEOF_SHORT == 4 /* SIZEOF_FLOAT == 4 == SIZEOF_SHORT */ -#define swapf(x) swaps(x) -#define FLOAT_SWAPPER unsigned short -#else /* SIZEOF_FLOAT == 4 but undivide by known size of int */ -define_swapx(f,float) -#endif /* #if SIZEOF_SHORT == 4 */ -#endif /* #if SIZEOF_LONG == 4 */ +# ifdef HAVE_UINT32_T +# define swapf(x) swap32(x) +# define FLOAT_SWAPPER uint32_t +# else /* SIZEOF_FLOAT == 4 but undivide by known size of int */ + define_swapx(f,float) +# endif #else /* SIZEOF_FLOAT != 4 */ -define_swapx(f,float) + define_swapx(f,float) #endif /* #if SIZEOF_FLOAT == 4 */ #if SIZEOF_DOUBLE == 8 -#if SIZEOF_LONG == 8 /* SIZEOF_DOUBLE == 8 == SIZEOF_LONG */ -#define swapd(x) swapl(x) -#define DOUBLE_SWAPPER unsigned long -#else -#if SIZEOF_LONG == 4 /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_LONG */ -static double -swapd(d) - const double d; -{ - double dtmp = d; - unsigned long utmp[2]; - unsigned long utmp0; +# ifdef HAVE_UINT64_T /* SIZEOF_DOUBLE == 8 == SIZEOF_UINT64_T */ +# define swapd(x) swap64(x) +# define DOUBLE_SWAPPER uint64_t +# else +# if SIZEOF_LONG == 4 /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_LONG */ + static double + swapd(const double d) + { + double dtmp = d; + unsigned long utmp[2]; + unsigned long utmp0; - utmp[0] = 0; utmp[1] = 0; - memcpy(utmp,&dtmp,sizeof(double)); - utmp0 = utmp[0]; - utmp[0] = swapl(utmp[1]); - utmp[1] = swapl(utmp0); - memcpy(&dtmp,utmp,sizeof(double)); - return dtmp; -} -#else -#if SIZEOF_SHORT == 4 /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_SHORT */ -static double -swapd(d) - const double d; -{ - double dtmp = d; - unsigned short utmp[2]; - unsigned short utmp0; + utmp[0] = 0; utmp[1] = 0; + memcpy(utmp,&dtmp,sizeof(double)); + utmp0 = utmp[0]; + utmp[0] = swapl(utmp[1]); + utmp[1] = swapl(utmp0); + memcpy(&dtmp,utmp,sizeof(double)); + return dtmp; + } +# elif SIZEOF_SHORT == 4 /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_SHORT */ + static double + swapd(const double d) + { + double dtmp = d; + unsigned short utmp[2]; + unsigned short utmp0; - utmp[0] = 0; utmp[1] = 0; - memcpy(utmp,&dtmp,sizeof(double)); - utmp0 = utmp[0]; - utmp[0] = swaps(utmp[1]); - utmp[1] = swaps(utmp0); - memcpy(&dtmp,utmp,sizeof(double)); - return dtmp; -} -#else /* SIZEOF_DOUBLE == 8 but undivied by known size of int */ -define_swapx(d, double) -#endif /* #if SIZEOF_SHORT == 4 */ -#endif /* #if SIZEOF_LONG == 4 */ -#endif /* #if SIZEOF_LONG == 8 */ + utmp[0] = 0; utmp[1] = 0; + memcpy(utmp,&dtmp,sizeof(double)); + utmp0 = utmp[0]; + utmp[0] = swaps(utmp[1]); + utmp[1] = swaps(utmp0); + memcpy(&dtmp,utmp,sizeof(double)); + return dtmp; + } +# else /* SIZEOF_DOUBLE == 8 but undivide by known size of int */ + define_swapx(d, double) +# endif +# endif /* #if SIZEOF_LONG == 8 */ #else /* SIZEOF_DOUBLE != 8 */ -define_swapx(d, double) + define_swapx(d, double) #endif /* #if SIZEOF_DOUBLE == 8 */ #undef define_swapx -#ifdef DYNAMIC_ENDIAN -#ifdef ntohs -#undef ntohs -#undef ntohl -#undef htons -#undef htonl -#endif -static int -endian() -{ - static int init = 0; - static int endian_value; - char *p; +#define rb_ntohf(x) (BIGENDIAN_P()?(x):swapf(x)) +#define rb_ntohd(x) (BIGENDIAN_P()?(x):swapd(x)) +#define rb_htonf(x) (BIGENDIAN_P()?(x):swapf(x)) +#define rb_htond(x) (BIGENDIAN_P()?(x):swapd(x)) +#define rb_htovf(x) (BIGENDIAN_P()?swapf(x):(x)) +#define rb_htovd(x) (BIGENDIAN_P()?swapd(x):(x)) +#define rb_vtohf(x) (BIGENDIAN_P()?swapf(x):(x)) +#define rb_vtohd(x) (BIGENDIAN_P()?swapd(x):(x)) - if (init) return endian_value; - init = 1; - p = (char*)&init; - return endian_value = p[0]?0:1; -} - -#define ntohs(x) (endian()?(x):swaps(x)) -#define ntohl(x) (endian()?(x):swapl(x)) -#define ntohf(x) (endian()?(x):swapf(x)) -#define ntohd(x) (endian()?(x):swapd(x)) -#define htons(x) (endian()?(x):swaps(x)) -#define htonl(x) (endian()?(x):swapl(x)) -#define htonf(x) (endian()?(x):swapf(x)) -#define htond(x) (endian()?(x):swapd(x)) -#define htovs(x) (endian()?swaps(x):(x)) -#define htovl(x) (endian()?swapl(x):(x)) -#define htovf(x) (endian()?swapf(x):(x)) -#define htovd(x) (endian()?swapd(x):(x)) -#define vtohs(x) (endian()?swaps(x):(x)) -#define vtohl(x) (endian()?swapl(x):(x)) -#define vtohf(x) (endian()?swapf(x):(x)) -#define vtohd(x) (endian()?swapd(x):(x)) -# ifdef NATINT_PACK -#define htov16(x) (endian()?swap16(x):(x)) -#define htov32(x) (endian()?swap32(x):(x)) -#define hton16(x) (endian()?(x):swap16(x)) -#define hton32(x) (endian()?(x):swap32(x)) -# endif -#else -#ifdef WORDS_BIGENDIAN -#ifndef ntohs -#define ntohs(x) (x) -#define ntohl(x) (x) -#define htons(x) (x) -#define htonl(x) (x) -#endif -#define ntohf(x) (x) -#define ntohd(x) (x) -#define htonf(x) (x) -#define htond(x) (x) -#define htovs(x) swaps(x) -#define htovl(x) swapl(x) -#define htovf(x) swapf(x) -#define htovd(x) swapd(x) -#define vtohs(x) swaps(x) -#define vtohl(x) swapl(x) -#define vtohf(x) swapf(x) -#define vtohd(x) swapd(x) -# ifdef NATINT_PACK -#define htov16(x) swap16(x) -#define htov32(x) swap32(x) -#define hton16(x) (x) -#define hton32(x) (x) -# endif -#else /* LITTLE ENDIAN */ -#ifdef ntohs -#undef ntohs -#undef ntohl -#undef htons -#undef htonl -#endif -#define ntohs(x) swaps(x) -#define ntohl(x) swapl(x) -#define htons(x) swaps(x) -#define htonl(x) swapl(x) -#define ntohf(x) swapf(x) -#define ntohd(x) swapd(x) -#define htonf(x) swapf(x) -#define htond(x) swapd(x) -#define htovs(x) (x) -#define htovl(x) (x) -#define htovf(x) (x) -#define htovd(x) (x) -#define vtohs(x) (x) -#define vtohl(x) (x) -#define vtohf(x) (x) -#define vtohd(x) (x) -# ifdef NATINT_PACK -#define htov16(x) (x) -#define htov32(x) (x) -#define hton16(x) swap16(x) -#define hton32(x) swap32(x) -# endif -#endif -#endif - #ifdef FLOAT_SWAPPER #define FLOAT_CONVWITH(y) FLOAT_SWAPPER y; #define HTONF(x,y) (memcpy(&y,&x,sizeof(float)), \ - y = htonf((FLOAT_SWAPPER)y), \ + y = rb_htonf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #define HTOVF(x,y) (memcpy(&y,&x,sizeof(float)), \ - y = htovf((FLOAT_SWAPPER)y), \ + y = rb_htovf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #define NTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \ - y = ntohf((FLOAT_SWAPPER)y), \ + y = rb_ntohf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #define VTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \ - y = vtohf((FLOAT_SWAPPER)y), \ + y = rb_vtohf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #else #define FLOAT_CONVWITH(y) -#define HTONF(x,y) htonf(x) -#define HTOVF(x,y) htovf(x) -#define NTOHF(x,y) ntohf(x) -#define VTOHF(x,y) vtohf(x) +# define HTONF(x,y) rb_htonf(x) +# define HTOVF(x,y) rb_htovf(x) +# define NTOHF(x,y) rb_ntohf(x) +# define VTOHF(x,y) rb_vtohf(x) #endif #ifdef DOUBLE_SWAPPER #define DOUBLE_CONVWITH(y) DOUBLE_SWAPPER y; #define HTOND(x,y) (memcpy(&y,&x,sizeof(double)), \ - y = htond((DOUBLE_SWAPPER)y), \ + y = rb_htond((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #define HTOVD(x,y) (memcpy(&y,&x,sizeof(double)), \ - y = htovd((DOUBLE_SWAPPER)y), \ + y = rb_htovd((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #define NTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \ - y = ntohd((DOUBLE_SWAPPER)y), \ + y = rb_ntohd((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #define VTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \ - y = vtohd((DOUBLE_SWAPPER)y), \ + y = rb_vtohd((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #else #define DOUBLE_CONVWITH(y) -#define HTOND(x,y) htond(x) -#define HTOVD(x,y) htovd(x) -#define NTOHD(x,y) ntohd(x) -#define VTOHD(x,y) vtohd(x) +# define HTOND(x,y) rb_htond(x) +# define HTOVD(x,y) rb_htovd(x) +# define NTOHD(x,y) rb_ntohd(x) +# define VTOHD(x,y) rb_vtohd(x) #endif unsigned long rb_big2ulong_pack _((VALUE x)); @@ -359,11 +295,10 @@ # define EXTEND16(x) do { if (!natint) {(x) = (short)(((1<<15)-1-(x))^~(~0<<15));}} while(0) #endif -#ifdef HAVE_LONG_LONG -# define QUAD_SIZE sizeof(LONG_LONG) -#else -# define QUAD_SIZE 8 -#endif +#define QUAD_SIZE 8 +#define MAX_INTEGER_PACK_SIZE 8 +/* #define FORCE_BIG_PACK */ + static const char toofew[] = "too few arguments"; static void encodes _((VALUE,const char*,long,int)); @@ -397,44 +332,67 @@ * * Directives for +pack+. * - * Directive Meaning - * --------------------------------------------------------------- - * @ | Moves to absolute position - * A | ASCII string (space padded, count is width) - * a | ASCII string (null padded, count is width) - * B | Bit string (descending bit order) - * b | Bit string (ascending bit order) - * C | Unsigned char - * c | Char - * D, d | Double-precision float, native format - * E | Double-precision float, little-endian byte order - * e | Single-precision float, little-endian byte order - * F, f | Single-precision float, native format - * G | Double-precision float, network (big-endian) byte order - * g | Single-precision float, network (big-endian) byte order - * H | Hex string (high nibble first) - * h | Hex string (low nibble first) - * I | Unsigned integer - * i | Integer - * L | Unsigned long - * l | Long - * M | Quoted printable, MIME encoding (see RFC2045) - * m | Base64 encoded string - * N | Long, network (big-endian) byte order - * n | Short, network (big-endian) byte-order - * P | Pointer to a structure (fixed-length string) - * p | Pointer to a null-terminated string - * Q, q | 64-bit number - * S | Unsigned short - * s | Short - * U | UTF-8 - * u | UU-encoded string - * V | Long, little-endian byte order - * v | Short, little-endian byte order - * w | BER-compressed integer\fnm - * X | Back up a byte - * x | Null byte - * Z | Same as ``a'', except that null is added with * + * Integer | Array | + * Directive | Element | Meaning + * ------------------------------------------------------------------------ + * C | Integer | 8-bit unsigned integer (unsigned char) + * S | Integer | 16-bit unsigned integer, native endian (uint16_t) + * L | Integer | 32-bit unsigned integer, native endian (uint32_t) + * Q | Integer | 64-bit unsigned integer, native endian (uint64_t) + * | | + * c | Integer | 8-bit signed integer (char) + * s | Integer | 16-bit signed integer, native endian (int16_t) + * l | Integer | 32-bit signed integer, native endian (int32_t) + * q | Integer | 64-bit signed integer, native endian (int64_t) + * | | + * S_ | Integer | unsigned short, native endian + * I, I_ | Integer | unsigned int, native endian + * L_ | Integer | unsigned long, native endian + * | | + * s_ | Integer | signed short, native endian + * i, i_ | Integer | signed int, native endian + * l_ | Integer | signed long, native endian + * | | + * n | Integer | 16-bit unsigned integer, network (big-endian) byte order + * N | Integer | 32-bit unsigned integer, network (big-endian) byte order + * v | Integer | 16-bit unsigned integer, VAX (little-endian) byte order + * V | Integer | 32-bit unsigned integer, VAX (little-endian) byte order + * | | + * U | Integer | UTF-8 character + * w | Integer | BER-compressed integer + * + * Float | | + * Directive | | Meaning + * ------------------------------------------------------------------------ + * D, d | Float | double-precision float, native format + * F, f | Float | single-precision float, native format + * E | Float | double-precision float, little-endian byte order + * e | Float | single-precision float, little-endian byte order + * G | Float | double-precision float, network (big-endian) byte order + * g | Float | single-precision float, network (big-endian) byte order + * + * String | | + * Directive | | Meaning + * ------------------------------------------------------------------------ + * A | String | arbitrary binary string (space padded, count is width) + * a | String | arbitrary binary string (null padded, count is width) + * Z | String | same as ``a'', except that null is added with * + * B | String | bit string (MSB first) + * b | String | bit string (LSB first) + * H | String | hex string (high nibble first) + * h | String | hex string (low nibble first) + * u | String | UU-encoded string + * M | String | quoted printable, MIME encoding (see RFC2045) + * m | String | base64 encoded string (see RFC 2045, count is width) + * P | String | pointer to a structure (fixed-length string) + * p | String | pointer to a null-terminated string + * + * Misc. | | + * Directive | | Meaning + * ------------------------------------------------------------------------ + * @ | --- | moves to absolute position + * X | --- | back up a byte + * x | --- | null byte */ static VALUE @@ -451,6 +409,7 @@ #ifdef NATINT_PACK int natint; /* native integer */ #endif + int signed_p, integer_size, bigendian_p; StringValue(fmt); p = RSTRING(fmt)->ptr; @@ -682,93 +641,164 @@ break; case 's': /* signed short */ + signed_p = 1; + integer_size = NATINT_LEN(short, 2); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; + case 'S': /* unsigned short */ - while (len-- > 0) { - short s; + signed_p = 0; + integer_size = NATINT_LEN(short, 2); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - from = NEXTFROM; - s = num2i32(from); - rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); - } - break; + case 'i': /* signed int */ + signed_p = 1; + integer_size = (int)sizeof(int); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - case 'i': /* signed int */ case 'I': /* unsigned int */ - while (len-- > 0) { - long i; + signed_p = 0; + integer_size = (int)sizeof(int); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - from = NEXTFROM; - i = num2i32(from); - rb_str_buf_cat(res, OFF32(&i), NATINT_LEN(int,4)); - } - break; + case 'l': /* signed long */ + signed_p = 1; + integer_size = NATINT_LEN(long, 4); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - case 'l': /* signed long */ case 'L': /* unsigned long */ - while (len-- > 0) { - long l; + signed_p = 0; + integer_size = NATINT_LEN(long, 4); + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - from = NEXTFROM; - l = num2i32(from); - rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); - } - break; + case 'q': /* signed quad (64bit) int */ + signed_p = 1; + integer_size = 8; + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - case 'q': /* signed quad (64bit) int */ case 'Q': /* unsigned quad (64bit) int */ - while (len-- > 0) { - char tmp[QUAD_SIZE]; + signed_p = 0; + integer_size = 8; + bigendian_p = BIGENDIAN_P(); + goto pack_integer; - from = NEXTFROM; - rb_quad_pack(tmp, from); - rb_str_buf_cat(res, (char*)&tmp, QUAD_SIZE); - } - break; - case 'n': /* unsigned short (network byte-order) */ - while (len-- > 0) { - unsigned short s; + signed_p = 0; + integer_size = 2; + bigendian_p = 1; + goto pack_integer; - from = NEXTFROM; - s = num2i32(from); - s = NATINT_HTONS(s); - rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); - } - break; - case 'N': /* unsigned long (network byte-order) */ - while (len-- > 0) { - unsigned long l; + signed_p = 0; + integer_size = 4; + bigendian_p = 1; + goto pack_integer; - from = NEXTFROM; - l = num2i32(from); - l = NATINT_HTONL(l); - rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); - } - break; - case 'v': /* unsigned short (VAX byte-order) */ - while (len-- > 0) { - unsigned short s; + signed_p = 0; + integer_size = 2; + bigendian_p = 0; + goto pack_integer; - from = NEXTFROM; - s = num2i32(from); - s = NATINT_HTOVS(s); - rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); - } - break; - case 'V': /* unsigned long (VAX byte-order) */ - while (len-- > 0) { - unsigned long l; + signed_p = 0; + integer_size = 4; + bigendian_p = 0; + goto pack_integer; - from = NEXTFROM; - l = num2i32(from); - l = NATINT_HTOVL(l); - rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); - } - break; + pack_integer: + switch (integer_size) { +#if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK) + case SIZEOF_INT16_T: + while (len-- > 0) { + union { + int16_t i; + char a[sizeof(int16_t)]; + } v; + from = NEXTFROM; + v.i = (int16_t)num2i32(from); + if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i); + rb_str_buf_cat(res, v.a, sizeof(int16_t)); + } + break; +#endif + +#if defined(HAVE_INT32_T) && !defined(FORCE_BIG_PACK) + case SIZEOF_INT32_T: + while (len-- > 0) { + union { + int32_t i; + char a[sizeof(int32_t)]; + } v; + + from = NEXTFROM; + v.i = (int32_t)num2i32(from); + if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i); + rb_str_buf_cat(res, v.a, sizeof(int32_t)); + } + break; +#endif + +#if defined(HAVE_INT64_T) && SIZEOF_LONG == SIZEOF_INT64_T && !defined(FORCE_BIG_PACK) + case SIZEOF_INT64_T: + while (len-- > 0) { + union { + int64_t i; + char a[sizeof(int64_t)]; + } v; + + from = NEXTFROM; + v.i = num2i32(from); /* can return 64bit value if SIZEOF_LONG == SIZEOF_INT64_T */ + if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i); + rb_str_buf_cat(res, v.a, sizeof(int64_t)); + } + break; +#endif + + default: + if (integer_size > MAX_INTEGER_PACK_SIZE) + rb_bug("unexpected intger size for pack: %d", integer_size); + while (len-- > 0) { + union { + unsigned long i[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG-1)/SIZEOF_LONG]; + char a[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG-1)/SIZEOF_LONG*SIZEOF_LONG]; + } v; + int num_longs = (integer_size+SIZEOF_LONG-1)/SIZEOF_LONG; + int i; + + from = NEXTFROM; + from = rb_to_int(from); + if (integer_size == QUAD_SIZE) + rb_quad_pack(v.a, from); /* RangeError compatibility for Ruby 1.8. */ + rb_big_pack(from, v.i, num_longs); + if (bigendian_p) { + for (i = 0; i < num_longs/2; i++) { + unsigned long t = v.i[i]; + v.i[i] = v.i[num_longs-1-i]; + v.i[num_longs-1-i] = t; + } + } + if (bigendian_p != BIGENDIAN_P()) { + for (i = 0; i < num_longs; i++) + v.i[i] = swapl(v.i[i]); + } + rb_str_buf_cat(res, + bigendian_p ? + v.a + sizeof(long)*num_longs - integer_size : + v.a, + integer_size); + } + break; + } + break; + case 'f': /* single precision float in native format */ case 'F': /* ditto */ while (len-- > 0) { @@ -1132,27 +1162,20 @@ } #define PACK_LENGTH_ADJUST_SIZE(sz) do { \ - tmp = 0; \ - if (len > (send-s)/sz) { \ + tmp_len = 0; \ + if (len > (long)((send-s)/sz)) { \ if (!star) { \ - tmp = len-(send-s)/sz; \ + tmp_len = len-(send-s)/sz; \ } \ len = (send-s)/sz; \ } \ } while (0) -#ifdef NATINT_PACK -#define PACK_LENGTH_ADJUST(type,sz) do { \ - int t__len = NATINT_LEN(type,(sz)); \ - PACK_LENGTH_ADJUST_SIZE(t__len); \ +#define PACK_ITEM_ADJUST() do { \ + if (tmp_len > 0) \ + rb_ary_store(ary, RARRAY_LEN(ary)+tmp_len-1, Qnil); \ } while (0) -#else -#define PACK_LENGTH_ADJUST(type,sz) \ - PACK_LENGTH_ADJUST_SIZE(sizeof(type)) -#endif -#define PACK_ITEM_ADJUST() while (tmp--) rb_ary_push(ary, Qnil) - static VALUE infected_str_new(ptr, len, str) const char *ptr; @@ -1312,11 +1335,12 @@ char *p, *pend; VALUE ary; char type; - long len; - int tmp, star; + long len, tmp_len; + int star; #ifdef NATINT_PACK int natint; /* native integer */ #endif + int signed_p, integer_size, bigendian_p; StringValue(str); StringValue(fmt); @@ -1490,7 +1514,7 @@ break; case 'c': - PACK_LENGTH_ADJUST(char,sizeof(char)); + PACK_LENGTH_ADJUST_SIZE(sizeof(char)); while (len-- > 0) { int c = *s++; if (c > (char)127) c-=256; @@ -1500,7 +1524,7 @@ break; case 'C': - PACK_LENGTH_ADJUST(unsigned char,sizeof(unsigned char)); + PACK_LENGTH_ADJUST_SIZE(sizeof(unsigned char)); while (len-- > 0) { unsigned char c = *s++; rb_ary_push(ary, INT2FIX(c)); @@ -1509,139 +1533,221 @@ break; case 's': - PACK_LENGTH_ADJUST(short,2); - while (len-- > 0) { - short tmp = 0; - memcpy(OFF16(&tmp), s, NATINT_LEN(short,2)); - EXTEND16(tmp); - s += NATINT_LEN(short,2); - rb_ary_push(ary, INT2FIX(tmp)); - } - PACK_ITEM_ADJUST(); - break; + signed_p = 1; + integer_size = NATINT_LEN(short, 2); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; case 'S': - PACK_LENGTH_ADJUST(unsigned short,2); - while (len-- > 0) { - unsigned short tmp = 0; - memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2)); - s += NATINT_LEN(unsigned short,2); - rb_ary_push(ary, INT2FIX(tmp)); - } - PACK_ITEM_ADJUST(); - break; + signed_p = 0; + integer_size = NATINT_LEN(short, 2); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; case 'i': - PACK_LENGTH_ADJUST(int,sizeof(int)); - while (len-- > 0) { - int tmp; - memcpy(&tmp, s, sizeof(int)); - s += sizeof(int); - rb_ary_push(ary, INT2NUM(tmp)); - } - PACK_ITEM_ADJUST(); - break; + signed_p = 1; + integer_size = (int)sizeof(int); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; case 'I': - PACK_LENGTH_ADJUST(unsigned int,sizeof(unsigned int)); - while (len-- > 0) { - unsigned int tmp; - memcpy(&tmp, s, sizeof(unsigned int)); - s += sizeof(unsigned int); - rb_ary_push(ary, UINT2NUM(tmp)); - } - PACK_ITEM_ADJUST(); - break; + signed_p = 0; + integer_size = (int)sizeof(int); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; case 'l': - PACK_LENGTH_ADJUST(long,4); - while (len-- > 0) { - long tmp = 0; - memcpy(OFF32(&tmp), s, NATINT_LEN(long,4)); - EXTEND32(tmp); - s += NATINT_LEN(long,4); - rb_ary_push(ary, LONG2NUM(tmp)); - } - PACK_ITEM_ADJUST(); - break; + signed_p = 1; + integer_size = NATINT_LEN(long, 4); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; - case 'L': - PACK_LENGTH_ADJUST(unsigned long,4); - while (len-- > 0) { - unsigned long tmp = 0; - memcpy(OFF32(&tmp), s, NATINT_LEN(unsigned long,4)); - s += NATINT_LEN(unsigned long,4); - rb_ary_push(ary, ULONG2NUM(tmp)); - } - PACK_ITEM_ADJUST(); - break; + case 'L': + signed_p = 0; + integer_size = NATINT_LEN(long, 4); + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; - case 'q': - PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE); - while (len-- > 0) { - char *tmp = (char*)s; - s += QUAD_SIZE; - rb_ary_push(ary, rb_quad_unpack(tmp, 1)); - } - PACK_ITEM_ADJUST(); - break; + case 'q': + signed_p = 1; + integer_size = QUAD_SIZE; + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; - case 'Q': - PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE); - while (len-- > 0) { - char *tmp = (char*)s; - s += QUAD_SIZE; - rb_ary_push(ary, rb_quad_unpack(tmp, 0)); - } - break; + case 'Q': + signed_p = 0; + integer_size = QUAD_SIZE; + bigendian_p = BIGENDIAN_P(); + goto unpack_integer; - case 'n': - PACK_LENGTH_ADJUST(unsigned short,2); - while (len-- > 0) { - unsigned short tmp = 0; - memcpy(OFF16B(&tmp), s, NATINT_LEN(unsigned short,2)); - s += NATINT_LEN(unsigned short,2); - rb_ary_push(ary, UINT2NUM(ntohs(tmp))); - } - PACK_ITEM_ADJUST(); - break; + case 'n': + signed_p = 0; + integer_size = 2; + bigendian_p = 1; + goto unpack_integer; - case 'N': - PACK_LENGTH_ADJUST(unsigned long,4); - while (len-- > 0) { - unsigned long tmp = 0; - memcpy(OFF32B(&tmp), s, NATINT_LEN(unsigned long,4)); - s += NATINT_LEN(unsigned long,4); - rb_ary_push(ary, ULONG2NUM(ntohl(tmp))); - } - PACK_ITEM_ADJUST(); - break; + case 'N': + signed_p = 0; + integer_size = 4; + bigendian_p = 1; + goto unpack_integer; - case 'v': - PACK_LENGTH_ADJUST(unsigned short,2); - while (len-- > 0) { - unsigned short tmp = 0; - memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2)); - s += NATINT_LEN(unsigned short,2); - rb_ary_push(ary, UINT2NUM(vtohs(tmp))); - } - PACK_ITEM_ADJUST(); - break; + case 'v': + signed_p = 0; + integer_size = 2; + bigendian_p = 0; + goto unpack_integer; - case 'V': - PACK_LENGTH_ADJUST(unsigned long,4); - while (len-- > 0) { - unsigned long tmp = 0; - memcpy(OFF32(&tmp), s, NATINT_LEN(long,4)); - s += NATINT_LEN(long,4); - rb_ary_push(ary, ULONG2NUM(vtohl(tmp))); - } - PACK_ITEM_ADJUST(); - break; + case 'V': + signed_p = 0; + integer_size = 4; + bigendian_p = 0; + goto unpack_integer; + unpack_integer: + switch (integer_size) { +#if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK) + case SIZEOF_INT16_T: + if (signed_p) { + PACK_LENGTH_ADJUST_SIZE(sizeof(int16_t)); + while (len-- > 0) { + union { + int16_t i; + char a[sizeof(int16_t)]; + } v; + memcpy(v.a, s, sizeof(int16_t)); + if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i); + s += sizeof(int16_t); + rb_ary_push(ary, INT2FIX(v.i)); + } + PACK_ITEM_ADJUST(); + } + else { + PACK_LENGTH_ADJUST_SIZE(sizeof(uint16_t)); + while (len-- > 0) { + union { + uint16_t i; + char a[sizeof(uint16_t)]; + } v; + memcpy(v.a, s, sizeof(uint16_t)); + if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i); + s += sizeof(uint16_t); + rb_ary_push(ary, INT2FIX(v.i)); + } + PACK_ITEM_ADJUST(); + } + break; +#endif + +#if defined(HAVE_INT32_T) && !defined(FORCE_BIG_PACK) + case SIZEOF_INT32_T: + if (signed_p) { + PACK_LENGTH_ADJUST_SIZE(sizeof(int32_t)); + while (len-- > 0) { + union { + int32_t i; + char a[sizeof(int32_t)]; + } v; + memcpy(v.a, s, sizeof(int32_t)); + if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i); + s += sizeof(int32_t); + rb_ary_push(ary, INT2NUM(v.i)); + } + PACK_ITEM_ADJUST(); + } + else { + PACK_LENGTH_ADJUST_SIZE(sizeof(uint32_t)); + while (len-- > 0) { + union { + uint32_t i; + char a[sizeof(uint32_t)]; + } v; + memcpy(v.a, s, sizeof(uint32_t)); + if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i); + s += sizeof(uint32_t); + rb_ary_push(ary, UINT2NUM(v.i)); + } + PACK_ITEM_ADJUST(); + } + break; +#endif + +#if defined(HAVE_INT64_T) && !defined(FORCE_BIG_PACK) + case SIZEOF_INT64_T: + if (signed_p) { + PACK_LENGTH_ADJUST_SIZE(sizeof(int64_t)); + while (len-- > 0) { + union { + int64_t i; + char a[sizeof(int64_t)]; + } v; + memcpy(v.a, s, sizeof(int64_t)); + if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i); + s += sizeof(int64_t); + rb_ary_push(ary, INT64toNUM(v.i)); + } + PACK_ITEM_ADJUST(); + } + else { + PACK_LENGTH_ADJUST_SIZE(sizeof(uint64_t)); + while (len-- > 0) { + union { + uint64_t i; + char a[sizeof(uint64_t)]; + } v; + memcpy(v.a, s, sizeof(uint64_t)); + if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i); + s += sizeof(uint64_t); + rb_ary_push(ary, UINT64toNUM(v.i)); + } + PACK_ITEM_ADJUST(); + } + break; +#endif + + + default: + if (integer_size > MAX_INTEGER_PACK_SIZE) + rb_bug("unexpected intger size for pack: %d", integer_size); + PACK_LENGTH_ADJUST_SIZE(integer_size); + while (len-- > 0) { + union { + unsigned long i[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG]; + char a[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG*SIZEOF_LONG]; + } v; + int num_longs = (integer_size+SIZEOF_LONG)/SIZEOF_LONG; + int i; + + if (signed_p && (signed char)s[bigendian_p ? 0 : (integer_size-1)] < 0) + memset(v.a, 0xff, sizeof(long)*num_longs); + else + memset(v.a, 0, sizeof(long)*num_longs); + if (bigendian_p) + memcpy(v.a + sizeof(long)*num_longs - integer_size, s, integer_size); + else + memcpy(v.a, s, integer_size); + if (bigendian_p) { + for (i = 0; i < num_longs/2; i++) { + unsigned long t = v.i[i]; + v.i[i] = v.i[num_longs-1-i]; + v.i[num_longs-1-i] = t; + } + } + if (bigendian_p != BIGENDIAN_P()) { + for (i = 0; i < num_longs; i++) + v.i[i] = swapl(v.i[i]); + } + s += integer_size; + rb_ary_push(ary, rb_big_unpack(v.i, num_longs)); + } + PACK_ITEM_ADJUST(); + break; + } + break; + case 'f': case 'F': - PACK_LENGTH_ADJUST(float,sizeof(float)); + PACK_LENGTH_ADJUST_SIZE(sizeof(float)); while (len-- > 0) { float tmp; memcpy(&tmp, s, sizeof(float)); @@ -1652,7 +1758,7 @@ break; case 'e': - PACK_LENGTH_ADJUST(float,sizeof(float)); + PACK_LENGTH_ADJUST_SIZE(sizeof(float)); while (len-- > 0) { float tmp; FLOAT_CONVWITH(ftmp); @@ -1666,7 +1772,7 @@ break; case 'E': - PACK_LENGTH_ADJUST(double,sizeof(double)); + PACK_LENGTH_ADJUST_SIZE(sizeof(double)); while (len-- > 0) { double tmp; DOUBLE_CONVWITH(dtmp); @@ -1681,7 +1787,7 @@ case 'D': case 'd': - PACK_LENGTH_ADJUST(double,sizeof(double)); + PACK_LENGTH_ADJUST_SIZE(sizeof(double)); while (len-- > 0) { double tmp; memcpy(&tmp, s, sizeof(double)); @@ -1692,7 +1798,7 @@ break; case 'g': - PACK_LENGTH_ADJUST(float,sizeof(float)); + PACK_LENGTH_ADJUST_SIZE(sizeof(float)); while (len-- > 0) { float tmp; FLOAT_CONVWITH(ftmp;) @@ -1706,7 +1812,7 @@ break; case 'G': - PACK_LENGTH_ADJUST(double,sizeof(double)); + PACK_LENGTH_ADJUST_SIZE(sizeof(double)); while (len-- > 0) { double tmp; DOUBLE_CONVWITH(dtmp); @@ -1886,7 +1992,7 @@ break; case 'P': - if (sizeof(char *) <= send - s) { + if (sizeof(char *) <= (size_t)(send - s)) { VALUE tmp = Qnil; char *t; @@ -1926,7 +2032,7 @@ if (len > (send - s) / sizeof(char *)) len = (send - s) / sizeof(char *); while (len-- > 0) { - if (send - s < sizeof(char *)) + if ((size_t)(send - s) < sizeof(char *)) break; else { VALUE tmp = Qnil; Index: ruby_1_8_7/bignum.c =================================================================== --- ruby_1_8_7/bignum.c (revision 28219) +++ ruby_1_8_7/bignum.c (revision 28220) @@ -222,9 +222,112 @@ return rb_int2big(n); } -#ifdef HAVE_LONG_LONG +#if SIZEOF_LONG % SIZEOF_BDIGITS != 0 +# error unexpected SIZEOF_LONG : SIZEOF_BDIGITS ratio +#endif +/* + * buf is an array of long integers. + * buf is ordered from least significant word to most significant word. + * buf[0] is the least significant word and + * buf[num_longs-1] is the most significant word. + * This means words in buf is little endian. + * However each word in buf is native endian. + * (buf[i]&1) is the least significant bit and + * (buf[i]&(1<<(SIZEOF_LONG*CHAR_BIT-1))) is the most significant bit + * for each 0 <= i < num_longs. + * So buf is little endian at whole on a little endian machine. + * But buf is mixed endian on a big endian machine. + */ void +rb_big_pack(VALUE val, unsigned long *buf, long num_longs) +{ + val = rb_to_int(val); + if (num_longs == 0) + return; + if (FIXNUM_P(val)) { + long i; + long tmp = FIX2LONG(val); + buf[0] = (unsigned long)tmp; + tmp = tmp < 0 ? ~0L : 0; + for (i = 1; i < num_longs; i++) + buf[i] = (unsigned long)tmp; + return; + } + else { + long len = RBIGNUM_LEN(val); + BDIGIT *ds = BDIGITS(val), *dend = ds + len; + long i, j; + for (i = 0; i < num_longs && ds < dend; i++) { + unsigned long l = 0; + for (j = 0; j < DIGSPERLONG && ds < dend; j++, ds++) { + l |= ((unsigned long)*ds << (j * BITSPERDIG)); + } + buf[i] = l; + } + for (; i < num_longs; i++) + buf[i] = 0; + if (RBIGNUM_NEGATIVE_P(val)) { + for (i = 0; i < num_longs; i++) { + buf[i] = ~buf[i]; + } + for (i = 0; i < num_longs; i++) { + buf[i]++; + if (buf[i] != 0) + return; + } + } + } +} + +/* See rb_big_pack comment for endianness of buf. */ +VALUE +rb_big_unpack(unsigned long *buf, long num_longs) +{ + while (2 <= num_longs) { + if (buf[num_longs-1] == 0 && (long)buf[num_longs-2] >= 0) + num_longs--; + else if (buf[num_longs-1] == ~0UL && (long)buf[num_longs-2] < 0) + num_longs--; + else + break; + } + if (num_longs == 0) + return INT2FIX(0); + else if (num_longs == 1) + return LONG2NUM((long)buf[0]); + else { + VALUE big; + BDIGIT *ds; + long len = num_longs * DIGSPERLONG; + long i; + big = bignew(len, 1); + ds = BDIGITS(big); + for (i = 0; i < num_longs; i++) { + unsigned long d = buf[i]; +#if SIZEOF_LONG == SIZEOF_BDIGITS + *ds++ = d; +#else + int j; + for (j = 0; j < DIGSPERLONG; j++) { + *ds++ = BIGLO(d); + d = BIGDN(d); + } +#endif + } + if ((long)buf[num_longs-1] < 0) { + get2comp(big); + RBIGNUM_SET_SIGN(big, 0); + } + return bignorm(big); + } +} + +#define QUAD_SIZE 8 + +#if SIZEOF_LONG_LONG == QUAD_SIZE && SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG + +void rb_quad_pack(buf, val) char *buf; VALUE val; @@ -295,7 +398,19 @@ #else -#define QUAD_SIZE 8 +static int +quad_buf_complement(char *buf, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) + buf[i] = ~buf[i]; + for (i = 0; i < len; i++) { + buf[i]++; + if (buf[i] != 0) + return 0; + } + return 1; +} void rb_quad_pack(buf, val) @@ -314,12 +429,8 @@ rb_raise(rb_eRangeError, "bignum too big to convert into `quad int'"); } memcpy(buf, (char*)BDIGITS(val), len); - if (!RBIGNUM(val)->sign) { - len = QUAD_SIZE; - while (len--) { - *buf = ~*buf; - buf++; - } + if (RBIGNUM_NEGATIVE_P(val)) { + quad_buf_complement(buf, QUAD_SIZE); } } @@ -334,14 +445,10 @@ memcpy((char*)BDIGITS(big), buf, QUAD_SIZE); if (sign && BNEG(buf)) { - long len = QUAD_SIZE; char *tmp = (char*)BDIGITS(big); RBIGNUM(big)->sign = 0; - while (len--) { - *tmp = ~*tmp; - tmp++; - } + quad_buf_complement(tmp, QUAD_SIZE); } return bignorm(big); Index: ruby_1_8_7/ruby.h =================================================================== --- ruby_1_8_7/ruby.h (revision 28219) +++ ruby_1_8_7/ruby.h (revision 28220) @@ -50,6 +50,10 @@ # include <intrinsics.h> #endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif + #include <stddef.h> #include <stdio.h> Index: ruby_1_8_7/test/ruby/test_pack.rb =================================================================== --- ruby_1_8_7/test/ruby/test_pack.rb (revision 28219) +++ ruby_1_8_7/test/ruby/test_pack.rb (revision 28220) @@ -20,6 +20,31 @@ assert_equal($x, $x.pack("l").unpack("l")) end + def test_pack_n + assert_equal "\000\000", [0].pack('n') + assert_equal "\000\001", [1].pack('n') + assert_equal "\000\002", [2].pack('n') + assert_equal "\000\003", [3].pack('n') + assert_equal "\377\376", [65534].pack('n') + assert_equal "\377\377", [65535].pack('n') + + assert_equal "\200\000", [2**15].pack('n') + assert_equal "\177\377", [-2**15-1].pack('n') + assert_equal "\377\377", [-1].pack('n') + + assert_equal "\000\001\000\001", [1,1].pack('n*') + assert_equal "\000\001\000\001\000\001", [1,1,1].pack('n*') + end + + def test_unpack_n + assert_equal 1, "\000\001".unpack('n')[0] + assert_equal 2, "\000\002".unpack('n')[0] + assert_equal 3, "\000\003".unpack('n')[0] + assert_equal 65535, "\377\377".unpack('n')[0] + assert_equal [1,1], "\000\001\000\001".unpack('n*') + assert_equal [1,1,1], "\000\001\000\001\000\001".unpack('n*') + end + def test_pack_N assert_equal "\000\000\000\000", [0].pack('N') assert_equal "\000\000\000\001", [1].pack('N') @@ -40,24 +65,208 @@ assert_equal 1, "\000\000\000\001".unpack('N')[0] assert_equal 2, "\000\000\000\002".unpack('N')[0] assert_equal 3, "\000\000\000\003".unpack('N')[0] - assert_equal 3, "\000\000\000\003".unpack('N')[0] assert_equal 4294967295, "\377\377\377\377".unpack('N')[0] assert_equal [1,1], "\000\000\000\001\000\000\000\001".unpack('N*') assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*') end + def test_integer_endian + s = [1].pack("s") + assert_operator(["\0\1", "\1\0"], :include?, s) + if s == "\0\1" + # big endian + assert_equal("\x01\x02", [0x0102].pack("s")) + assert_equal("\x01\x02", [0x0102].pack("S")) + assert_equal("\x01\x02\x03\x04", [0x01020304].pack("l")) + assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L")) + assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q")) + assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q")) + assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!")) + assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!")) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i")) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I")) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i!")) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!")) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!")) + assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!")) + %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt| + nuls = [0].pack(fmt) + v = 0 + s = "" + nuls.bytesize.times {|i| + j = i + 40 + v = v * 256 + j + s << [j].pack("C") + } + assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})") + assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})") + s2 = s+s + fmt2 = fmt+"*" + assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})") + } + else + # little endian + assert_equal("\x02\x01", [0x0102].pack("s")) + assert_equal("\x02\x01", [0x0102].pack("S")) + assert_equal("\x04\x03\x02\x01", [0x01020304].pack("l")) + assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L")) + assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q")) + assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q")) + assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!")) + assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!")) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i")) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I")) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i!")) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!")) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!")) + assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!")) + %w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt| + nuls = [0].pack(fmt) + v = 0 + s = "" + nuls.bytesize.times {|i| + j = i+40 + v = v * 256 + j + s << [j].pack("C") + } + s.reverse! + assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})") + assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})") + s2 = s+s + fmt2 = fmt+"*" + assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})") + } + end + end + def test_pack_U - assert_raises(RangeError) { [-0x40000001].pack("U") } - assert_raises(RangeError) { [-0x40000000].pack("U") } - assert_raises(RangeError) { [-1].pack("U") } + assert_raise(RangeError) { [-0x40000001].pack("U") } + assert_raise(RangeError) { [-0x40000000].pack("U") } + assert_raise(RangeError) { [-1].pack("U") } assert_equal "\000", [0].pack("U") assert_equal "\374\277\277\277\277\277", [0x3fffffff].pack("U") assert_equal "\375\200\200\200\200\200", [0x40000000].pack("U") assert_equal "\375\277\277\277\277\277", [0x7fffffff].pack("U") - assert_raises(RangeError) { [0x80000000].pack("U") } - assert_raises(RangeError) { [0x100000000].pack("U") } + assert_raise(RangeError) { [0x80000000].pack("U") } + assert_raise(RangeError) { [0x100000000].pack("U") } end + def test_pack_P + a = ["abc"] + assert_equal a, a.pack("P").unpack("P*") + assert_equal "a", a.pack("P").unpack("P")[0] + assert_equal a, a.pack("P").freeze.unpack("P*") + assert_raise(ArgumentError) { (a.pack("P") + "").unpack("P*") } + end + + def test_pack_p + a = ["abc"] + assert_equal a, a.pack("p").unpack("p*") + assert_equal a[0], a.pack("p").unpack("p")[0] + assert_equal a, a.pack("p").freeze.unpack("p*") + assert_raise(ArgumentError) { (a.pack("p") + "").unpack("p*") } + end + + def test_format_string_modified + fmt = "CC" + o = Object.new + class << o; self; end.class_eval do + define_method(:to_int) { fmt.replace ""; 0 } + end + assert_raise(RuntimeError) do + [o, o].pack(fmt) + end + end + + def test_comment + assert_equal("\0\1", [0,1].pack(" C #foo \n C ")) + assert_equal([0,1], "\0\1".unpack(" C #foo \n C ")) + end + + def test_illegal_bang + assert_raise(ArgumentError) { [].pack("a!") } + assert_raise(ArgumentError) { "".unpack("a!") } + end + + def test_pack_unpack_aA + assert_equal("f", ["foo"].pack("A")) + assert_equal("f", ["foo"].pack("a")) + assert_equal("foo", ["foo"].pack("A*")) + assert_equal("foo", ["foo"].pack("a*")) + assert_equal("fo", ["foo"].pack("A2")) + assert_equal("fo", ["foo"].pack("a2")) + assert_equal("foo ", ["foo"].pack("A4")) + assert_equal("foo\0", ["foo"].pack("a4")) + assert_equal(" ", [nil].pack("A")) + assert_equal("\0", [nil].pack("a")) + assert_equal("", [nil].pack("A*")) + assert_equal("", [nil].pack("a*")) + assert_equal(" ", [nil].pack("A2")) + assert_equal("\0\0", [nil].pack("a2")) + + assert_equal("foo" + "\0" * 27, ["foo"].pack("a30")) + + assert_equal(["f"], "foo\0".unpack("A")) + assert_equal(["f"], "foo\0".unpack("a")) + assert_equal(["foo"], "foo\0".unpack("A4")) + assert_equal(["foo\0"], "foo\0".unpack("a4")) + assert_equal(["foo"], "foo ".unpack("A4")) + assert_equal(["foo "], "foo ".unpack("a4")) + assert_equal(["foo"], "foo".unpack("A4")) + assert_equal(["foo"], "foo".unpack("a4")) + end + + def test_pack_unpack_Z + assert_equal("f", ["foo"].pack("Z")) + assert_equal("foo\0", ["foo"].pack("Z*")) + assert_equal("fo", ["foo"].pack("Z2")) + assert_equal("foo\0\0", ["foo"].pack("Z5")) + assert_equal("\0", [nil].pack("Z")) + assert_equal("\0", [nil].pack("Z*")) + assert_equal("\0\0", [nil].pack("Z2")) + + assert_equal(["f"], "foo\0".unpack("Z")) + assert_equal(["foo"], "foo".unpack("Z*")) + assert_equal(["foo"], "foo\0".unpack("Z*")) + assert_equal(["foo"], "foo".unpack("Z5")) + end + + def test_pack_unpack_bB + assert_equal("\xff\x00", ["1111111100000000"].pack("b*")) + assert_equal("\x01\x02", ["1000000001000000"].pack("b*")) + assert_equal("", ["1"].pack("b0")) + assert_equal("\x01", ["1"].pack("b1")) + assert_equal("\x01\x00", ["1"].pack("b2")) + assert_equal("\x01\x00", ["1"].pack("b3")) + assert_equal("\x01\x00\x00", ["1"].pack("b4")) + assert_equal("\x01\x00\x00", ["1"].pack("b5")) + assert_equal("\x01\x00\x00\x00", ["1"].pack("b6")) + + assert_equal("\xff\x00", ["1111111100000000"].pack("B*")) + assert_equal("\x01\x02", ["0000000100000010"].pack("B*")) + assert_equal("", ["1"].pack("B0")) + assert_equal("\x80", ["1"].pack("B1")) + assert_equal("\x80\x00", ["1"].pack("B2")) + assert_equal("\x80\x00", ["1"].pack("B3")) + assert_equal("\x80\x00\x00", ["1"].pack("B4")) + assert_equal("\x80\x00\x00", ["1"].pack("B5")) + assert_equal("\x80\x00\x00\x00", ["1"].pack("B6")) + + assert_equal(["1111111100000000"], "\xff\x00".unpack("b*")) + assert_equal(["1000000001000000"], "\x01\x02".unpack("b*")) + assert_equal([""], "".unpack("b0")) + assert_equal(["1"], "\x01".unpack("b1")) + assert_equal(["10"], "\x01".unpack("b2")) + assert_equal(["100"], "\x01".unpack("b3")) + + assert_equal(["1111111100000000"], "\xff\x00".unpack("B*")) + assert_equal(["0000000100000010"], "\x01\x02".unpack("B*")) + assert_equal([""], "".unpack("B0")) + assert_equal(["1"], "\x80".unpack("B1")) + assert_equal(["10"], "\x80".unpack("B2")) + assert_equal(["100"], "\x80".unpack("B3")) + end + def test_pack_unpack_hH assert_equal("\x01\xfe", ["10ef"].pack("h*")) assert_equal("", ["10ef"].pack("h0")) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/