| 1 | #!./perl
|
|---|
| 2 | # FIXME - why isn't this -w clean in maint?
|
|---|
| 3 |
|
|---|
| 4 | BEGIN {
|
|---|
| 5 | chdir 't' if -d 't';
|
|---|
| 6 | @INC = '../lib';
|
|---|
| 7 | require './test.pl';
|
|---|
| 8 | }
|
|---|
| 9 |
|
|---|
| 10 | # This is truth in an if statement, and could be a skip message
|
|---|
| 11 | my $no_endianness = $] > 5.009 ? '' :
|
|---|
| 12 | "Endianness pack modifiers not available on this perl";
|
|---|
| 13 | my $no_signedness = $] > 5.009 ? '' :
|
|---|
| 14 | "Signed/unsigned pack modifiers not available on this perl";
|
|---|
| 15 |
|
|---|
| 16 | plan tests => 13864;
|
|---|
| 17 |
|
|---|
| 18 | use strict;
|
|---|
| 19 | # use warnings;
|
|---|
| 20 | use Config;
|
|---|
| 21 |
|
|---|
| 22 | my $Is_EBCDIC = (defined $Config{ebcdic} && $Config{ebcdic} eq 'define');
|
|---|
| 23 | my $Perl = which_perl();
|
|---|
| 24 | my @valid_errors = (qr/^Invalid type '\w'/);
|
|---|
| 25 |
|
|---|
| 26 | my $ByteOrder = 'unknown';
|
|---|
| 27 | my $maybe_not_avail = '(?:hto[bl]e|[bl]etoh)';
|
|---|
| 28 | if ($no_endianness) {
|
|---|
| 29 | push @valid_errors, qr/^Invalid type '[<>]'/;
|
|---|
| 30 | } elsif ($Config{byteorder} =~ /^1234(?:5678)?$/) {
|
|---|
| 31 | $ByteOrder = 'little';
|
|---|
| 32 | $maybe_not_avail = '(?:htobe|betoh)';
|
|---|
| 33 | }
|
|---|
| 34 | elsif ($Config{byteorder} =~ /^(?:8765)?4321$/) {
|
|---|
| 35 | $ByteOrder = 'big';
|
|---|
| 36 | $maybe_not_avail = '(?:htole|letoh)';
|
|---|
| 37 | }
|
|---|
| 38 | else {
|
|---|
| 39 | push @valid_errors, qr/^Can't (?:un)?pack (?:big|little)-endian .*? on this platform/;
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | if ($no_signedness) {
|
|---|
| 43 | push @valid_errors, qr/^'!' allowed only after types sSiIlLxX in (?:un)?pack/;
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | for my $size ( 16, 32, 64 ) {
|
|---|
| 47 | if (defined $Config{"u${size}size"} and $Config{"u${size}size"} != ($size >> 3)) {
|
|---|
| 48 | push @valid_errors, qr/^Perl_my_$maybe_not_avail$size\(\) not available/;
|
|---|
| 49 | }
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | my $IsTwosComplement = pack('i', -1) eq "\xFF" x $Config{intsize};
|
|---|
| 53 | print "# \$IsTwosComplement = $IsTwosComplement\n";
|
|---|
| 54 |
|
|---|
| 55 | sub is_valid_error
|
|---|
| 56 | {
|
|---|
| 57 | my $err = shift;
|
|---|
| 58 |
|
|---|
| 59 | for my $e (@valid_errors) {
|
|---|
| 60 | $err =~ $e and return 1;
|
|---|
| 61 | }
|
|---|
| 62 |
|
|---|
| 63 | return 0;
|
|---|
| 64 | }
|
|---|
| 65 |
|
|---|
| 66 | sub encode_list {
|
|---|
| 67 | my @result = map {_qq($_)} @_;
|
|---|
| 68 | if (@result == 1) {
|
|---|
| 69 | return @result;
|
|---|
| 70 | }
|
|---|
| 71 | return '(' . join (', ', @result) . ')';
|
|---|
| 72 | }
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 | sub list_eq ($$) {
|
|---|
| 76 | my ($l, $r) = @_;
|
|---|
| 77 | return 0 unless @$l == @$r;
|
|---|
| 78 | for my $i (0..$#$l) {
|
|---|
| 79 | if (defined $l->[$i]) {
|
|---|
| 80 | return 0 unless defined ($r->[$i]) && $l->[$i] eq $r->[$i];
|
|---|
| 81 | } else {
|
|---|
| 82 | return 0 if defined $r->[$i]
|
|---|
| 83 | }
|
|---|
| 84 | }
|
|---|
| 85 | return 1;
|
|---|
| 86 | }
|
|---|
| 87 |
|
|---|
| 88 | ##############################################################################
|
|---|
| 89 | #
|
|---|
| 90 | # Here starteth the tests
|
|---|
| 91 | #
|
|---|
| 92 |
|
|---|
| 93 | {
|
|---|
| 94 | my $format = "c2 x5 C C x s d i l a6";
|
|---|
| 95 | # Need the expression in here to force ary[5] to be numeric. This avoids
|
|---|
| 96 | # test2 failing because ary2 goes str->numeric->str and ary doesn't.
|
|---|
| 97 | my @ary = (1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,
|
|---|
| 98 | "abcdef");
|
|---|
| 99 | my $foo = pack($format,@ary);
|
|---|
| 100 | my @ary2 = unpack($format,$foo);
|
|---|
| 101 |
|
|---|
| 102 | is($#ary, $#ary2);
|
|---|
| 103 |
|
|---|
| 104 | my $out1=join(':',@ary);
|
|---|
| 105 | my $out2=join(':',@ary2);
|
|---|
| 106 | # Using long double NVs may introduce greater accuracy than wanted.
|
|---|
| 107 | $out1 =~ s/:9\.87654321097999\d*:/:9.87654321098:/;
|
|---|
| 108 | $out2 =~ s/:9\.87654321097999\d*:/:9.87654321098:/;
|
|---|
| 109 | is($out1, $out2);
|
|---|
| 110 |
|
|---|
| 111 | like($foo, qr/def/);
|
|---|
| 112 | }
|
|---|
| 113 | # How about counting bits?
|
|---|
| 114 |
|
|---|
| 115 | {
|
|---|
| 116 | my $x;
|
|---|
| 117 | is( ($x = unpack("%32B*", "\001\002\004\010\020\040\100\200\377")), 16 );
|
|---|
| 118 |
|
|---|
| 119 | is( ($x = unpack("%32b69", "\001\002\004\010\020\040\100\200\017")), 12 );
|
|---|
| 120 |
|
|---|
| 121 | is( ($x = unpack("%32B69", "\001\002\004\010\020\040\100\200\017")), 9 );
|
|---|
| 122 | }
|
|---|
| 123 |
|
|---|
| 124 | {
|
|---|
| 125 | my $sum = 129; # ASCII
|
|---|
| 126 | $sum = 103 if $Is_EBCDIC;
|
|---|
| 127 |
|
|---|
| 128 | my $x;
|
|---|
| 129 | is( ($x = unpack("%32B*", "Now is the time for all good blurfl")), $sum );
|
|---|
| 130 |
|
|---|
| 131 | my $foo;
|
|---|
| 132 | open(BIN, $Perl) || die "Can't open $Perl: $!\n";
|
|---|
| 133 | sysread BIN, $foo, 8192;
|
|---|
| 134 | close BIN;
|
|---|
| 135 |
|
|---|
| 136 | $sum = unpack("%32b*", $foo);
|
|---|
| 137 | my $longway = unpack("b*", $foo);
|
|---|
| 138 | is( $sum, $longway =~ tr/1/1/ );
|
|---|
| 139 | }
|
|---|
| 140 |
|
|---|
| 141 | {
|
|---|
| 142 | my $x;
|
|---|
| 143 | is( ($x = unpack("I",pack("I", 0xFFFFFFFF))), 0xFFFFFFFF );
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | {
|
|---|
| 147 | # check 'w'
|
|---|
| 148 | my @x = (5,130,256,560,32000,3097152,268435455,1073741844, 2**33,
|
|---|
| 149 | '4503599627365785','23728385234614992549757750638446');
|
|---|
| 150 | my $x = pack('w*', @x);
|
|---|
| 151 | my $y = pack 'H*', '0581028200843081fa0081bd8440ffffff7f8480808014A0808'.
|
|---|
| 152 | '0800087ffffffffffdb19caefe8e1eeeea0c2e1e3e8ede1ee6e';
|
|---|
| 153 |
|
|---|
| 154 | is($x, $y);
|
|---|
| 155 |
|
|---|
| 156 | my @y = unpack('w*', $y);
|
|---|
| 157 | my $a;
|
|---|
| 158 | while ($a = pop @x) {
|
|---|
| 159 | my $b = pop @y;
|
|---|
| 160 | is($a, $b);
|
|---|
| 161 | }
|
|---|
| 162 |
|
|---|
| 163 | @y = unpack('w2', $x);
|
|---|
| 164 |
|
|---|
| 165 | is(scalar(@y), 2);
|
|---|
| 166 | is($y[1], 130);
|
|---|
| 167 | $x = pack('w*', 5000000000); $y = '';
|
|---|
| 168 | eval {
|
|---|
| 169 | use Math::BigInt;
|
|---|
| 170 | $y = pack('w*', Math::BigInt::->new(5000000000));
|
|---|
| 171 | };
|
|---|
| 172 | is($x, $y);
|
|---|
| 173 |
|
|---|
| 174 | $x = pack 'w', ~0;
|
|---|
| 175 | $y = pack 'w', (~0).'';
|
|---|
| 176 | is($x, $y);
|
|---|
| 177 | is(unpack ('w',$x), ~0);
|
|---|
| 178 | is(unpack ('w',$y), ~0);
|
|---|
| 179 |
|
|---|
| 180 | $x = pack 'w', ~0 - 1;
|
|---|
| 181 | $y = pack 'w', (~0) - 2;
|
|---|
| 182 |
|
|---|
| 183 | if (~0 - 1 == (~0) - 2) {
|
|---|
| 184 | is($x, $y, "NV arithmetic");
|
|---|
| 185 | } else {
|
|---|
| 186 | isnt($x, $y, "IV/NV arithmetic");
|
|---|
| 187 | }
|
|---|
| 188 | cmp_ok(unpack ('w',$x), '==', ~0 - 1);
|
|---|
| 189 | cmp_ok(unpack ('w',$y), '==', ~0 - 2);
|
|---|
| 190 |
|
|---|
| 191 | # These should spot that pack 'w' is using NV, not double, on platforms
|
|---|
| 192 | # where IVs are smaller than doubles, and harmlessly pass elsewhere.
|
|---|
| 193 | # (tests for change 16861)
|
|---|
| 194 | my $x0 = 2**54+3;
|
|---|
| 195 | my $y0 = 2**54-2;
|
|---|
| 196 |
|
|---|
| 197 | $x = pack 'w', $x0;
|
|---|
| 198 | $y = pack 'w', $y0;
|
|---|
| 199 |
|
|---|
| 200 | if ($x0 == $y0) {
|
|---|
| 201 | is($x, $y, "NV arithmetic");
|
|---|
| 202 | } else {
|
|---|
| 203 | isnt($x, $y, "IV/NV arithmetic");
|
|---|
| 204 | }
|
|---|
| 205 | cmp_ok(unpack ('w',$x), '==', $x0);
|
|---|
| 206 | cmp_ok(unpack ('w',$y), '==', $y0);
|
|---|
| 207 | }
|
|---|
| 208 |
|
|---|
| 209 |
|
|---|
| 210 | {
|
|---|
| 211 | print "# test exceptions\n";
|
|---|
| 212 | my $x;
|
|---|
| 213 | eval { $x = unpack 'w', pack 'C*', 0xff, 0xff};
|
|---|
| 214 | like($@, qr/^Unterminated compressed integer/);
|
|---|
| 215 |
|
|---|
| 216 | eval { $x = unpack 'w', pack 'C*', 0xff, 0xff, 0xff, 0xff};
|
|---|
| 217 | like($@, qr/^Unterminated compressed integer/);
|
|---|
| 218 |
|
|---|
| 219 | eval { $x = unpack 'w', pack 'C*', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|---|
| 220 | like($@, qr/^Unterminated compressed integer/);
|
|---|
| 221 |
|
|---|
| 222 | eval { $x = pack 'w', -1 };
|
|---|
| 223 | like ($@, qr/^Cannot compress negative numbers/);
|
|---|
| 224 |
|
|---|
| 225 | eval { $x = pack 'w', '1'x(1 + length ~0) . 'e0' };
|
|---|
| 226 | like ($@, qr/^Can only compress unsigned integers/);
|
|---|
| 227 |
|
|---|
| 228 | # Check that the warning behaviour on the modifiers !, < and > is as we
|
|---|
| 229 | # expect it for this perl.
|
|---|
| 230 | my $can_endian = $no_endianness ? '' : 'sSiIlLqQjJfFdDpP';
|
|---|
| 231 | my $can_shriek = 'sSiIlL';
|
|---|
| 232 | $can_shriek .= 'nNvV' unless $no_signedness;
|
|---|
| 233 | # h and H can't do either, so act as sanity checks in blead
|
|---|
| 234 | foreach my $base (split '', 'hHsSiIlLqQjJfFdDpPnNvV') {
|
|---|
| 235 | foreach my $mod ('', '<', '>', '!', '<!', '>!', '!<', '!>') {
|
|---|
| 236 | SKIP: {
|
|---|
| 237 | # Avoid void context warnings.
|
|---|
| 238 | my $a = eval {pack "$base$mod"};
|
|---|
| 239 | skip "pack can't $base", 1 if $@ =~ /^Invalid type '\w'/;
|
|---|
| 240 | # Which error you get when 2 would be possible seems to be emergent
|
|---|
| 241 | # behaviour of pack's format parser.
|
|---|
| 242 |
|
|---|
| 243 | my $fails_shriek = $mod =~ /!/ && index ($can_shriek, $base) == -1;
|
|---|
| 244 | my $fails_endian = $mod =~ /[<>]/ && index ($can_endian, $base) == -1;
|
|---|
| 245 | my $shriek_first = $mod =~ /^!/;
|
|---|
| 246 |
|
|---|
| 247 | if ($no_endianness and ($mod eq '<!' or $mod eq '>!')) {
|
|---|
| 248 | # The ! isn't seem as part of $base. Instead it's seen as a modifier
|
|---|
| 249 | # on > or <
|
|---|
| 250 | $fails_shriek = 1;
|
|---|
| 251 | undef $fails_endian;
|
|---|
| 252 | } elsif ($fails_shriek and $fails_endian) {
|
|---|
| 253 | if ($shriek_first) {
|
|---|
| 254 | undef $fails_endian;
|
|---|
| 255 | }
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | if ($fails_endian) {
|
|---|
| 259 | if ($no_endianness) {
|
|---|
| 260 | # < and > are seen as pattern letters, not modifiers
|
|---|
| 261 | like ($@, qr/^Invalid type '[<>]'/, "pack can't $base$mod");
|
|---|
| 262 | } else {
|
|---|
| 263 | like ($@, qr/^'[<>]' allowed only after types/,
|
|---|
| 264 | "pack can't $base$mod");
|
|---|
| 265 | }
|
|---|
| 266 | } elsif ($fails_shriek) {
|
|---|
| 267 | like ($@, qr/^'!' allowed only after types/,
|
|---|
| 268 | "pack can't $base$mod");
|
|---|
| 269 | } else {
|
|---|
| 270 | is ($@, '', "pack can $base$mod");
|
|---|
| 271 | }
|
|---|
| 272 | }
|
|---|
| 273 | }
|
|---|
| 274 | }
|
|---|
| 275 |
|
|---|
| 276 | SKIP: {
|
|---|
| 277 | skip $no_endianness, 2*3 + 2*8 if $no_endianness;
|
|---|
| 278 | for my $mod (qw( ! < > )) {
|
|---|
| 279 | eval { $x = pack "a$mod", 42 };
|
|---|
| 280 | like ($@, qr/^'$mod' allowed only after types \S+ in pack/);
|
|---|
| 281 |
|
|---|
| 282 | eval { $x = unpack "a$mod", 'x'x8 };
|
|---|
| 283 | like ($@, qr/^'$mod' allowed only after types \S+ in unpack/);
|
|---|
| 284 | }
|
|---|
| 285 |
|
|---|
| 286 | for my $mod (qw( <> >< !<> !>< <!> >!< <>! ><! )) {
|
|---|
| 287 | eval { $x = pack "sI${mod}s", 42, 47, 11 };
|
|---|
| 288 | like ($@, qr/^Can't use both '<' and '>' after type 'I' in pack/);
|
|---|
| 289 |
|
|---|
| 290 | eval { $x = unpack "sI${mod}s", 'x'x16 };
|
|---|
| 291 | like ($@, qr/^Can't use both '<' and '>' after type 'I' in unpack/);
|
|---|
| 292 | }
|
|---|
| 293 | }
|
|---|
| 294 |
|
|---|
| 295 | SKIP: {
|
|---|
| 296 | # Is this a stupid thing to do on VMS, VOS and other unusual platforms?
|
|---|
| 297 |
|
|---|
| 298 | skip("-- the IEEE infinity model is unavailable in this configuration.", 1)
|
|---|
| 299 | if (($^O eq 'VMS') && !defined($Config{useieee}));
|
|---|
| 300 |
|
|---|
| 301 | skip("-- $^O has serious fp indigestion on w-packed infinities", 1)
|
|---|
| 302 | if (
|
|---|
| 303 | ($^O eq 'mpeix')
|
|---|
| 304 | ||
|
|---|
| 305 | ($^O eq 'ultrix')
|
|---|
| 306 | ||
|
|---|
| 307 | ($^O =~ /^svr4/ && -f "/etc/issue" && -f "/etc/.relid") # NCR MP-RAS
|
|---|
| 308 | );
|
|---|
| 309 |
|
|---|
| 310 | my $inf = eval '2**1000000';
|
|---|
| 311 |
|
|---|
| 312 | skip("Couldn't generate infinity - got error '$@'", 1)
|
|---|
| 313 | unless defined $inf and $inf == $inf / 2 and $inf + 1 == $inf;
|
|---|
| 314 |
|
|---|
| 315 | local our $TODO;
|
|---|
| 316 | $TODO = "VOS needs a fix for posix-1022 to pass this test."
|
|---|
| 317 | if ($^O eq 'vos');
|
|---|
| 318 |
|
|---|
| 319 | eval { $x = pack 'w', $inf };
|
|---|
| 320 | like ($@, qr/^Cannot compress integer/, "Cannot compress integer");
|
|---|
| 321 | }
|
|---|
| 322 |
|
|---|
|
|---|