diff options
author | Nick Ing-Simmons <nik@tiuk.ti.com> | 2001-12-19 14:43:24 +0000 |
---|---|---|
committer | Nick Ing-Simmons <nik@tiuk.ti.com> | 2001-12-19 14:43:24 +0000 |
commit | 79b94f8b7c6a7b74e025d0a00e7a42445e59dda0 (patch) | |
tree | d839fda1296237d9a7f9df194a6a23366d0ec930 | |
parent | 205c8ad3acbda0df8cac03a0c7e619f1855229a8 (diff) | |
parent | f4abc3e7120c79388800ae3eaccafb9461d38553 (diff) | |
download | perl-79b94f8b7c6a7b74e025d0a00e7a42445e59dda0.tar.gz |
Integrate mainline
p4raw-id: //depot/perlio@13803
-rw-r--r-- | MANIFEST | 2 | ||||
-rw-r--r-- | ext/B/B/Assembler.pm | 75 | ||||
-rw-r--r-- | ext/B/B/Disassembler.pm | 62 | ||||
-rw-r--r-- | ext/B/t/assembler.t | 374 | ||||
-rw-r--r-- | lib/lib.t | 75 | ||||
-rw-r--r-- | lib/lib_pm.PL | 9 | ||||
-rwxr-xr-x | t/op/glob.t | 9 | ||||
-rw-r--r-- | utf8.c | 2 |
8 files changed, 570 insertions, 38 deletions
@@ -92,6 +92,7 @@ ext/B/ramblings/reg.alloc Compiler ramblings: register allocation ext/B/ramblings/runtime.porting Compiler ramblings: porting PP enging ext/B/README Compiler backend README ext/B/t/asmdata.t See if B::Asmdata works +ext/B/t/assembler.t See if B::Assembler, B::Disassembler comply ext/B/t/b.t See if B works ext/B/t/bblock.t See if B::Bblock works ext/B/t/debug.t See if B::Debug works @@ -1045,6 +1046,7 @@ lib/IPC/SysV.t See if IPC::SysV works lib/less.pm For "use less" lib/less.t See if less support works lib/lib_pm.PL For "use lib", produces lib/lib.pm +lib/lib.t For "use lib" testing lib/locale.pm For "use locale" lib/locale.t See if locale support works lib/Locale/Codes/t/all.t See if Locale::Codes work diff --git a/ext/B/B/Assembler.pm b/ext/B/B/Assembler.pm index 86f0962e38..10ae81bd0d 100644 --- a/ext/B/B/Assembler.pm +++ b/ext/B/B/Assembler.pm @@ -14,7 +14,7 @@ require ByteLoader; # we just need its $VERSIOM @ISA = qw(Exporter); @EXPORT_OK = qw(assemble_fh newasm endasm assemble); -$VERSION = 0.03; +$VERSION = 0.04; use strict; my %opnumber; @@ -34,6 +34,15 @@ sub error { my $debug = 0; sub debug { $debug = shift } +sub limcheck($$$$){ + my( $val, $lo, $hi, $loc ) = @_; + if( $val < $lo || $hi < $val ){ + error "argument for $loc outside [$lo, $hi]: $val"; + $val = $hi; + } + return $val; +} + # # First define all the data conversion subs to which Asmdata will refer # @@ -47,32 +56,46 @@ sub B::Asmdata::PUT_U8 { $c = substr($c, 0, 1); } } else { + $arg = limcheck( $arg, 0, 0xff, 'U8' ); $c = chr($arg); } return $c; } -sub B::Asmdata::PUT_U16 { pack("S", $_[0]) } -sub B::Asmdata::PUT_U32 { pack("L", $_[0]) } -sub B::Asmdata::PUT_I32 { pack("L", $_[0]) } -sub B::Asmdata::PUT_NV { sprintf("%s\0", $_[0]) } # "%lf" loses precision and pack('d',...) +sub B::Asmdata::PUT_U16 { + my $arg = limcheck( $_[0], 0, 0xffff, 'U16' ); + pack("S", $arg); +} +sub B::Asmdata::PUT_U32 { + my $arg = limcheck( $_[0], 0, 0xffffffff, 'U32' ); + pack("L", $arg); +} +sub B::Asmdata::PUT_I32 { + my $arg = limcheck( $_[0], -0x80000000, 0x7fffffff, 'I32' ); + pack("L", $arg); +} +sub B::Asmdata::PUT_NV { sprintf("%s\0", $_[0]) } # "%lf" looses precision and pack('d',...) # may not even be portable between compilers -sub B::Asmdata::PUT_objindex { pack("L", $_[0]) } # could allow names here +sub B::Asmdata::PUT_objindex { # could allow names here + my $arg = limcheck( $_[0], 0, 0xffffffff, '*index' ); + pack("L", $arg); +} sub B::Asmdata::PUT_svindex { &B::Asmdata::PUT_objindex } sub B::Asmdata::PUT_opindex { &B::Asmdata::PUT_objindex } sub B::Asmdata::PUT_pvindex { &B::Asmdata::PUT_objindex } sub B::Asmdata::PUT_strconst { my $arg = shift; - $arg = uncstring($arg); - if (!defined($arg)) { + my $str = uncstring($arg); + if (!defined($str)) { error "bad string constant: $arg"; - return ""; + $str = ''; } - if ($arg =~ s/\0//g) { + if ($str =~ s/\0//g) { error "string constant argument contains NUL: $arg"; + $str = ''; } - return $arg . "\0"; + return $str . "\0"; } sub B::Asmdata::PUT_pvcontents { @@ -82,9 +105,12 @@ sub B::Asmdata::PUT_pvcontents { } sub B::Asmdata::PUT_PV { my $arg = shift; - $arg = uncstring($arg); - error "bad string argument: $arg" unless defined($arg); - return pack("L", length($arg)) . $arg; + my $str = uncstring($arg); + if( ! defined($str) ){ + error "bad string argument: $arg"; + $str = ''; + } + return pack("L", length($str)) . $str; } sub B::Asmdata::PUT_comment_t { my $arg = shift; @@ -111,9 +137,14 @@ sub B::Asmdata::PUT_op_tr_array { return pack("S256", @ary); } # XXX Check this works +# Note: $arg >> 32 is a no-op on 32-bit systems sub B::Asmdata::PUT_IV64 { my $arg = shift; - return pack("LL", $arg >> 32, $arg & 0xffffffff); + return pack("LL", ($arg >> 16) >>16 , $arg & 0xffffffff); +} + +sub B::Asmdata::PUT_IV { + $Config{ivsize} == 4 ? &B::Asmdata::PUT_I32 : &B::Asmdata::PUT_IV64; } my %unesc = (n => "\n", r => "\r", t => "\t", a => "\a", @@ -164,14 +195,13 @@ sub gen_header { sub parse_statement { my $stmt = shift; my ($insn, $arg) = $stmt =~ m{ - (?sx) ^\s* # allow (but ignore) leading whitespace (.*?) # Instruction continues up until... (?: # ...an optional whitespace+argument group \s+ # first whitespace. (.*) # The argument is all the rest (newlines included). )?$ # anchor at end-of-line - }; + }sx; if (defined($arg)) { if ($arg =~ s/^0x(?=[0-9a-fA-F]+$)//) { $arg = hex($arg); @@ -247,11 +277,12 @@ sub assemble { $quotedline =~ s/"/\\"/g; $out->(assemble_insn("comment", qq("$quotedline"))); } - $line = strip_comments($line) or next; - ($insn, $arg) = parse_statement($line); - $out->(assemble_insn($insn, $arg)); - if ($debug) { - $out->(assemble_insn("nop", undef)); + if( $line = strip_comments($line) ){ + ($insn, $arg) = parse_statement($line); + $out->(assemble_insn($insn, $arg)); + if ($debug) { + $out->(assemble_insn("nop", undef)); + } } } diff --git a/ext/B/B/Disassembler.pm b/ext/B/B/Disassembler.pm index 7fc4ac7773..b8b5262f41 100644 --- a/ext/B/B/Disassembler.pm +++ b/ext/B/B/Disassembler.pm @@ -6,10 +6,11 @@ # License or the Artistic License, as specified in the README file. package B::Disassembler::BytecodeStream; -our $VERSION = '1.00'; +our $VERSION = '1.01'; use FileHandle; use Carp; +use Config qw(%Config); use B qw(cstring cast_I32); @ISA = qw(FileHandle); sub readn { @@ -31,54 +32,65 @@ sub GET_U16 { my $fh = shift; my $str = $fh->readn(2); croak "reached EOF while reading U16" unless length($str) == 2; - return unpack("n", $str); + return unpack("S", $str); } sub GET_NV { my $fh = shift; - my $str = $fh->readn(8); - croak "reached EOF while reading NV" unless length($str) == 8; - return unpack("N", $str); + my ($str, $c); + while (defined($c = $fh->getc) && $c ne "\0") { + $str .= $c; + } + croak "reached EOF while reading double" unless defined($c); + return $str; } sub GET_U32 { my $fh = shift; my $str = $fh->readn(4); croak "reached EOF while reading U32" unless length($str) == 4; - return unpack("N", $str); + return unpack("L", $str); } sub GET_I32 { my $fh = shift; my $str = $fh->readn(4); croak "reached EOF while reading I32" unless length($str) == 4; - return cast_I32(unpack("N", $str)); + return cast_I32(unpack("L", $str)); } sub GET_objindex { my $fh = shift; my $str = $fh->readn(4); croak "reached EOF while reading objindex" unless length($str) == 4; - return unpack("N", $str); + return unpack("L", $str); } sub GET_opindex { my $fh = shift; my $str = $fh->readn(4); croak "reached EOF while reading opindex" unless length($str) == 4; - return unpack("N", $str); + return unpack("L", $str); } sub GET_svindex { my $fh = shift; my $str = $fh->readn(4); croak "reached EOF while reading svindex" unless length($str) == 4; - return unpack("N", $str); + return unpack("L", $str); +} + +sub GET_pvindex { + my $fh = shift; + my $str = $fh->readn(4); + croak "reached EOF while reading pvindex" unless length($str) == 4; + return unpack("L", $str); } sub GET_strconst { my $fh = shift; my ($str, $c); + $str = ''; while (defined($c = $fh->getc) && $c ne "\0") { $str .= $c; } @@ -125,29 +137,51 @@ sub GET_none {} sub GET_op_tr_array { my $fh = shift; - my @ary = unpack("n256", $fh->readn(256 * 2)); + my @ary = unpack("S256", $fh->readn(256 * 2)); return join(",", @ary); } sub GET_IV64 { my $fh = shift; - my ($hi, $lo) = unpack("NN", $fh->readn(8)); - return sprintf("0x%4x%04x", $hi, $lo); # cheat + my ($hi, $lo) = unpack("LL", $fh->readn(8)); + return sprintf("0x%x%08x", $hi, $lo); # cheat +} + +sub GET_IV { + $Config{ivsize} == 4 ? &GET_I32 : &GET_IV64; } package B::Disassembler; use Exporter; @ISA = qw(Exporter); -@EXPORT_OK = qw(disassemble_fh); +@EXPORT_OK = qw(disassemble_fh get_header); use Carp; use strict; use B::Asmdata qw(%insn_data @insn_name); +our( $magic, $archname, $blversion, $ivsize, $ptrsize, $byteorder ); + +sub dis_header($){ + my( $fh ) = @_; + $magic = $fh->GET_U32(); + warn( "bad magic" ) if $magic != 0x43424c50; + $archname = $fh->GET_strconst(); + $blversion = $fh->GET_strconst(); + $ivsize = $fh->GET_U32(); + $ptrsize = $fh->GET_U32(); + $byteorder = $fh->GET_strconst(); +} + +sub get_header(){ + return( $magic, $archname, $blversion, $ivsize, $ptrsize, $byteorder ); +} + sub disassemble_fh { my ($fh, $out) = @_; my ($c, $getmeth, $insn, $arg); bless $fh, "B::Disassembler::BytecodeStream"; + dis_header( $fh ); while (defined($c = $fh->getc)) { $c = ord($c); $insn = $insn_name[$c]; diff --git a/ext/B/t/assembler.t b/ext/B/t/assembler.t new file mode 100644 index 0000000000..6bec7e091b --- /dev/null +++ b/ext/B/t/assembler.t @@ -0,0 +1,374 @@ +#!./perl -w + +=pod + +=head1 TEST FOR B::Assembler.pm AND B::Disassembler.pm + +=head2 Description + +The general idea is to test by assembling a choice set of assembler +instructions, then disassemble them, and check that we've completed the +round trip. Also, error checking of Assembler.pm is tested by feeding +it assorted errors. + +Since Assembler.pm likes to assemble a file, we comply by writing a +text file. This file contains three sections: + + testing operand categories + use each opcode + erronous assembler instructions + +An "operand category" is identified by the suffix of the PUT_/GET_ +subroutines as shown in the C<%Asmdata::insn_data> initialization, e.g. +opcode C<ldsv> has operand category C<svindex>: + + insn_data{ldsv} = [1, \&PUT_svindex, "GET_svindex"]; + +Because Disassembler.pm also assumes input from a file, we write the +resulting object code to a file. And disassembled output is written to +yet another text file which is then compared to the original input. +(Erronous assembler instructions still generate code, but this is not +written to the object file; therefore disassembly bails out at the first +instruction in error.) + +All files are kept in memory by using TIEHASH. + + +=head2 Caveats + +An error where Assembler.pm and Disassembler.pm agree but Assembler.pm +generates invalid object code will not be detected. + +Due to the way this test has been set up, failure of a single test +could cause all subsequent tests to fail as well: After an unexpected +assembler error no output is written, and disassembled lines will be +out of sync for all lines thereafter. + +Not all possibilities for writing a valid operand value can be tested +because disassembly results in a uniform representation. + + +=head2 Maintenance + +New opcodes are added automatically. + +A new operand category will cause this program to die ("no operand list +for XXX"). The cure is to add suitable entries to C<%goodlist> and +C<%badlist>. (Since the data in Asmdata.pm is autogenerated, it may also +happen that the corresponding assembly or disassembly subroutine is +missing.) Note that an empty array as a C<%goodlist> entry means that +opcodes of the operand category do not take an operand (and therefore the +corresponding entry in C<%badlist> should have one). An C<undef> entry +in C<%badlist> means that any value is acceptable (and thus there is no +way to cause an error). + +Set C<$dbg> to debug this test. + +=cut + +package VirtFile; +use strict; + +# Note: This is NOT a general purpose package. It implements +# sequential text and binary file i/o in a rather simple form. + +sub TIEHANDLE($;$){ + my( $class, $data ) = @_; + my $obj = { data => defined( $data ) ? $data : '', + pos => 0 }; + return bless( $obj, $class ); +} + +sub PRINT($@){ + my( $self ) = shift; + $self->{data} .= join( '', @_ ); +} + +sub WRITE($$;$$){ + my( $self, $buf, $len, $offset ) = @_; + unless( defined( $len ) ){ + $len = length( $buf ); + $offset = 0; + } + unless( defined( $offset ) ){ + $offset = 0; + } + $self->{data} .= substr( $buf, $offset, $len ); + return $len; +} + + +sub GETC($){ + my( $self ) = @_; + return undef() if $self->{pos} >= length( $self->{data} ); + return substr( $self->{data}, $self->{pos}++, 1 ); +} + +sub READLINE($){ + my( $self ) = @_; + return undef() if $self->{pos} >= length( $self->{data} ); + my $lfpos = index( $self->{data}, "\n", $self->{pos} ); + if( $lfpos < 0 ){ + $lfpos = length( $self->{data} ); + } + my $pos = $self->{pos}; + $self->{pos} = $lfpos + 1; + return substr( $self->{data}, $pos, $self->{pos} - $pos ); +} + +sub READ($@){ + my $self = shift(); + my $bufref = \$_[0]; + my( undef, $len, $offset ) = @_; + if( $offset ){ + die( "offset beyond end of buffer\n" ) + if ! defined( $$bufref ) || $offset > length( $$bufref ); + } else { + $$bufref = ''; + $offset = 0; + } + my $remlen = length( $self->{data} ) - $self->{pos}; + $len = $remlen if $remlen < $len; + return 0 unless $len; + substr( $$bufref, $offset, $len ) = + substr( $self->{data}, $self->{pos}, $len ); + $self->{pos} += $len; + return $len; +} + +sub TELL($){ + my $self = shift(); + return $self->{pos}; +} + +sub CLOSE($){ + my( $self ) = @_; + $self->{pos} = 0; +} + +1; + +package main; + +use strict; +use Test::More; +use Config qw(%Config); + +use B::Asmdata qw( %insn_data ); +use B::Assembler qw( &assemble_fh ); +use B::Disassembler qw( &disassemble_fh &get_header ); + +my( %opsByType, @code2name ); +my( $lineno, $dbg, $firstbadline, @descr ); +$dbg = 0; # debug switch + +# $SIG{__WARN__} handler to catch Assembler error messages +# +my $warnmsg; +sub catchwarn($){ + $warnmsg = $_[0]; + print "error: $warnmsg\n" if $dbg; +} + +# Callback for writing assembled bytes. This is where we check +# that we do get an error. +# +sub putobj($){ + if( ++$lineno >= $firstbadline ){ + ok( $warnmsg && $warnmsg =~ /^\d+:\s/, $descr[$lineno] ); + undef( $warnmsg ); + } else { + my $l = syswrite( OBJ, $_[0] ); + } +} + +# Callback for writing a disassembled statement. +# +sub putdis(@){ + my $line = join( ' ', @_ ); + ++$lineno; + print DIS "$line\n"; + printf "%5d %s\n", $lineno, $line if $dbg; +} + +# Generate assembler instructions from a hash of operand types: each +# existing entry contains a list of good or bad operand values. The +# corresponding opcodes can be found in %opsByType. +# +sub gen_type($$$){ + my( $href, $descref, $text ) = @_; + for my $odt ( keys( %opsByType ) ){ + my $opcode = $opsByType{$odt}->[0]; + my $sel = $odt; + $sel =~ s/^GET_//; + die( "no operand list for $sel\n" ) unless exists( $href->{$sel} ); + if( defined( $href->{$sel} ) ){ + if( @{$href->{$sel}} ){ + for my $od ( @{$href->{$sel}} ){ + ++$lineno; + $descref->[$lineno] = "$text: $code2name[$opcode] $od"; + print ASM "$code2name[$opcode] $od\n"; + printf "%5d %s %s\n", $lineno, $code2name[$opcode], $od if $dbg; + } + } else { + ++$lineno; + $descref->[$lineno] = "$text: $code2name[$opcode]"; + print ASM "$code2name[$opcode]\n"; + printf "%5d %s\n", $lineno, $code2name[$opcode] if $dbg; + } + } + } +} + +# Interesting operand values +# +my %goodlist = ( +comment_t => [ '"a comment"' ], # no \n +none => [], +svindex => [ 0x7fffffff, 0 ], +opindex => [ 0x7fffffff, 0 ], +pvindex => [ 0x7fffffff, 0 ], +U32 => [ 0xffffffff, 0 ], +U8 => [ 0xff, 0 ], +PV => [ '""', '"a string"', ], +I32 => [ -0x80000000, 0x7fffffff ], +IV64 => [ '0x000000000', '0x0ffffffff', '0x000000001' ], # disass formats 0x%09x +IV => $Config{ivsize} == 4 ? + [ -0x80000000, 0x7fffffff ] : + [ '0x000000000', '0x0ffffffff', '0x000000001' ], +NV => [ 1.23456789E3 ], +U16 => [ 0xffff, 0 ], +pvcontents => [], +strconst => [ '""', '"another string"' ], # no NUL +op_tr_array => [ join( ',', 0..255 ) ], + ); + +# Erronous operand values +# +my %badlist = ( +comment_t => [ '"multi-line\ncomment"' ], # no \n +none => [ '"spurious arg"' ], +svindex => [ 0xffffffff * 2, -1 ], +opindex => [ 0xffffffff * 2, -2 ], +pvindex => [ 0xffffffff * 2, -3 ], +U32 => [ 0xffffffff * 2, -4 ], +U16 => [ 0x5ffff, -5 ], +U8 => [ 0x6ff, -6 ], +PV => [ 'no quote"' ], +I32 => [ -0x80000001, 0x80000000 ], +IV64 => undef, # PUT_IV64 doesn't check - no integrity there +IV => $Config{ivsize} == 4 ? + [ -0x80000001, 0x80000000 ] : undef, +NV => undef, # PUT_NV accepts anything - it shouldn't, real-ly +pvcontents => [ '"spurious arg"' ], +strconst => [ 'no quote"', '"with NUL '."\0".' char"' ], # no NUL +op_tr_array => [ join( ',', 1..42 ) ], + ); + + +# Determine all operand types from %Asmdata::insn_data +# +for my $opname ( keys( %insn_data ) ){ + my ( $opcode, $put, $getname ) = @{$insn_data{$opname}}; + push( @{$opsByType{$getname}}, $opcode ); + $code2name[$opcode] = $opname; +} + + +# Write instruction(s) for correct operand values each operand type class +# +$lineno = 0; +tie( *ASM, 'VirtFile' ); +gen_type( \%goodlist, \@descr, 'round trip' ); + +# Write one instruction for each opcode. +# +for my $opcode ( 0..$#code2name ){ + next unless defined( $code2name[$opcode] ); + my $sel = $insn_data{$code2name[$opcode]}->[2]; + $sel =~ s/^GET_//; + die( "no operand list for $sel\n" ) unless exists( $goodlist{$sel} ); + if( defined( $goodlist{$sel} ) ){ + ++$lineno; + if( @{$goodlist{$sel}} ){ + my $od = $goodlist{$sel}[0]; + $descr[$lineno] = "round trip: $code2name[$opcode] $od"; + print ASM "$code2name[$opcode] $od\n"; + printf "%5d %s %s\n", $lineno, $code2name[$opcode], $od if $dbg; + } else { + $descr[$lineno] = "round trip: $code2name[$opcode]"; + print ASM "$code2name[$opcode]\n"; + printf "%5d %s\n", $lineno, $code2name[$opcode] if $dbg; + } + } +} + +# Write instruction(s) for incorrect operand values each operand type class +# +$firstbadline = $lineno + 1; +gen_type( \%badlist, \@descr, 'asm error' ); + +# invalid opcode is an odd-man-out ;-) +# +++$lineno; +$descr[$lineno] = "asm error: Gollum"; +print ASM "Gollum\n"; +printf "%5d %s\n", $lineno, 'Gollum' if $dbg; + +close( ASM ); + +# Now that we have defined all of our tests: plan +# +plan( tests => $lineno ); +print "firstbadline=$firstbadline\n" if $dbg; + +# assemble (guard against warnings and death from assembly errors) +# +$SIG{'__WARN__'} = \&catchwarn; + +$lineno = -1; # account for the assembly header +tie( *OBJ, 'VirtFile' ); +eval { assemble_fh( \*ASM, \&putobj ); }; +print "eval: $@" if $dbg; +close( ASM ); +close( OBJ ); +$SIG{'__WARN__'} = 'DEFAULT'; + +# disassemble +# +print "--- disassembling ---\n" if $dbg; +$lineno = 0; +tie( *DIS, 'VirtFile' ); +disassemble_fh( \*OBJ, \&putdis ); +close( OBJ ); +close( DIS ); + +# get header (for debugging only) +# +if( $dbg ){ + my( $magic, $archname, $blversion, $ivsize, $ptrsize, $byteorder ) = + get_header(); + printf "Magic: 0x%08x\n", $magic; + print "Architecture: $archname\n"; + print "Byteloader V: $blversion\n"; + print "ivsize: $ivsize\n"; + print "ptrsize: $ptrsize\n"; + print "Byteorder: $byteorder\n"; +} + +# check by comparing files line by line +# +print "--- checking ---\n" if $dbg; +$lineno = 0; +my( $asmline, $disline ); +while( defined( $asmline = <ASM> ) ){ + $disline = <DIS>; + ++$lineno; + last if $lineno eq $firstbadline; # bail out where errors begin + ok( $asmline eq $disline, $descr[$lineno] ); + printf "%5d %s\n", $lineno, $asmline if $dbg; +} +close( ASM ); +close( DIS ); + +__END__ diff --git a/lib/lib.t b/lib/lib.t new file mode 100644 index 0000000000..9a86ac7424 --- /dev/null +++ b/lib/lib.t @@ -0,0 +1,75 @@ +#!./perl -w + +BEGIN { + chdir 't'; + @INC = '../lib'; + @OrigINC = @INC; +} + +use Test::More tests => 12; +use Config; +use File::Spec; +use File::Path; + +#set up files and directories +my @lib_dir; +my $Lib_Dir; +my $Arch_Dir; +my $Auto_Dir; +my $Module; +BEGIN { + # lib.pm is documented to only work with Unix filepaths. + @lib_dir = qw(stuff moo); + $Lib_Dir = join "/", @lib_dir; + $Arch_Dir = join "/", @lib_dir, $Config{archname}; + + # create the auto/ directory and a module + $Auto_Dir = File::Spec->catdir(@lib_dir, $Config{archname},'auto'); + $Module = File::Spec->catfile(@lib_dir, 'Yup.pm'); + + mkpath [$Auto_Dir]; + + open(MOD, ">$Module") || DIE $!; + print MOD <<'MODULE'; +package Yup; +$Plan = 9; +return '42'; +MODULE + + close MOD; +} + +END { + # cleanup the auto/ directory we created. + rmtree([$lib_dir[0]]); +} + + +use lib $Lib_Dir; +use lib $Lib_Dir; + +BEGIN { use_ok('Yup') } + +BEGIN { + is( $INC[1], $Lib_Dir, 'lib adding at end of @INC' ); + print "# \@INC == @INC\n"; + is( $INC[0], $Arch_Dir, ' auto/ dir in front of that' ); + is( grep(/^\Q$Lib_Dir\E$/, @INC), 1, ' no duplicates' ); + + # Yes, %INC uses Unixy filepaths. + is( $INC{'Yup.pm'}, join("/",$Lib_Dir, 'Yup.pm'), '%INC set properly' ); + + is( eval { do 'Yup.pm' }, 42, 'do() works' ); + ok( eval { require Yup; }, ' require()' ); + ok( eval "use Yup; 1;", ' use()' ); + is( $@, '' ); + + is_deeply(\@OrigINC, \@lib::ORIG_INC, '@lib::ORIG_INC' ); +} + +no lib $Lib_Dir; + +BEGIN { + is( grep(/stuff/, @INC), 0, 'no lib' ); + ok( !do 'Yup.pm', ' do() effected' ); +} diff --git a/lib/lib_pm.PL b/lib/lib_pm.PL index 2c9eb6654d..d7786732b7 100644 --- a/lib/lib_pm.PL +++ b/lib/lib_pm.PL @@ -171,6 +171,15 @@ can say @INC = @lib::ORIG_INC; +=head1 CAVEATS + +In order to keep lib.pm small and simple, it only works with Unix +filepaths. This doesn't mean it only works on Unix, but non-Unix +users must first translate their file paths to Unix conventions. + + # VMS users wanting to put [.stuff.moo] into + # their @INC would write + use lib 'stuff/moo'; =head1 SEE ALSO diff --git a/t/op/glob.t b/t/op/glob.t index bc43323375..079919deca 100755 --- a/t/op/glob.t +++ b/t/op/glob.t @@ -5,7 +5,7 @@ BEGIN { @INC = '../lib'; } -print "1..8\n"; +print "1..9\n"; @oops = @ops = <op/*>; @@ -58,3 +58,10 @@ print $i == 2 ? "ok 7\n" : "not ok 7\n"; my $ok = "not ok 8\n"; $ok = "ok 8\n" while my $var = glob("0"); print $ok; + +# The formerly-broken test for the situation above would accidentally +# test definedness for an assignment with a LOGOP on the right: +my $f=0; +$ok="ok 9\n"; +$ok="not ok 9\n", undef $f while $x = $f||$f; +print $ok @@ -255,7 +255,7 @@ Perl_utf8n_to_uvuni(pTHX_ U8 *s, STRLEN curlen, STRLEN *retlen, U32 flags) UV uv = *s, ouv = 0; STRLEN len = 1; bool dowarn = ckWARN_d(WARN_UTF8); - U8 startbyte = *s; + UV startbyte = *s; STRLEN expectlen = 0; U32 warning = 0; |