Re: [perl #18048] read \*FH, ... returns undef but doesn' t set $! if \*FH not open
Slaven Rezic [Thu, 24 Oct 2002 00:44:35 +0000 (02:44 +0200)]
Message-ID: <87vg3sixm4.fsf@vran.herceg.de>

p4raw-id: //depot/perl@18115

pod/perldiag.pod
pod/perlfunc.pod
pp_sys.c
t/io/binmode.t
t/io/print.t
t/io/read.t
t/lib/warnings/pp_sys

index 20d9d91..e59eee3 100644 (file)
@@ -3093,6 +3093,14 @@ are outside the range which can be represented by integers internally.
 One possible workaround is to force Perl to use magical string increment
 by prepending "0" to your numbers.
 
+=item read() on closed filehandle %s
+
+(W closed) You tried to read from a closed filehandle.
+
+=item read() on unopened filehandle %s
+
+(W unopened) You tried to read from a filehandle that was never opened.
+
 =item readline() on closed filehandle %s
 
 (W closed) The filehandle you're reading from got itself closed sometime
@@ -3567,6 +3575,14 @@ or "my $var" or "our $var".
 
 (F) The final summary message when a C<perl -c> succeeds.
 
+=item sysread() on closed filehandle %s
+
+(W closed) You tried to read from a closed filehandle.
+
+=item sysread() on unopened filehandle %s
+
+(W unopened) You tried to read from a filehandle that was never opened.
+
 =item System V %s is not implemented on this machine
 
 (F) You tried to do something with a function beginning with "sem",
index d1d6469..8a745ef 100644 (file)
@@ -453,7 +453,7 @@ Arranges for FILEHANDLE to be read or written in "binary" or "text"
 mode on systems where the run-time libraries distinguish between
 binary and text files.  If FILEHANDLE is an expression, the value is
 taken as the name of the filehandle.  Returns true on success,
-C<undef> on failure.
+otherwise it returns C<undef> and sets C<$!> (errno).
 
 If LAYER is omitted or specified as C<:raw> the filehandle is made
 suitable for passing binary data. This includes turning off possible CRLF
@@ -1805,11 +1805,11 @@ C<formline> always returns true.  See L<perlform> for other examples.
 =item getc
 
 Returns the next character from the input file attached to FILEHANDLE,
-or the undefined value at end of file, or if there was an error.
-If FILEHANDLE is omitted, reads from STDIN.  This is not particularly
-efficient.  However, it cannot be used by itself to fetch single
-characters without waiting for the user to hit enter.  For that, try
-something more like:
+or the undefined value at end of file, or if there was an error (in
+the latter case C<$!> is set).  If FILEHANDLE is omitted, reads from
+STDIN.  This is not particularly efficient.  However, it cannot be
+used by itself to fetch single characters without waiting for the user
+to hit enter.  For that, try something more like:
 
     if ($BSD_STYLE) {
        system "stty cbreak </dev/tty >/dev/tty 2>&1";
@@ -3767,13 +3767,13 @@ with the wrong number of RANDBITS.)
 
 Attempts to read LENGTH I<characters> of data into variable SCALAR
 from the specified FILEHANDLE.  Returns the number of characters
-actually read, C<0> at end of file, or undef if there was an error.
-SCALAR will be grown or shrunk to the length actually read.  If SCALAR
-needs growing, the new bytes will be zero bytes.  An OFFSET may be
-specified to place the read data into some other place in SCALAR than
-the beginning.  The call is actually implemented in terms of either
-Perl's or system's fread() call.  To get a true read(2) system call,
-see C<sysread>.
+actually read, C<0> at end of file, or undef if there was an error (in
+the latter case C<$!> is also set).  SCALAR will be grown or shrunk to
+the length actually read.  If SCALAR needs growing, the new bytes will
+be zero bytes.  An OFFSET may be specified to place the read data into
+some other place in SCALAR than the beginning.  The call is actually
+implemented in terms of either Perl's or system's fread() call.  To
+get a true read(2) system call, see C<sysread>.
 
 Note the I<characters>: depending on the status of the filehandle,
 either (8-bit) bytes or characters are read.  By default all
@@ -5519,14 +5519,15 @@ See L<perlopentut> for a kinder, gentler explanation of opening files.
 
 =item sysread FILEHANDLE,SCALAR,LENGTH
 
-Attempts to read LENGTH I<characters> of data into variable SCALAR from
-the specified FILEHANDLE, using the system call read(2).  It bypasses
-buffered IO, so mixing this with other kinds of reads, C<print>,
-C<write>, C<seek>, C<tell>, or C<eof> can cause confusion because
-stdio usually buffers data.  Returns the number of characters actually
-read, C<0> at end of file, or undef if there was an error.  SCALAR
-will be grown or shrunk so that the last byte actually read is the
-last byte of the scalar after the read.
+Attempts to read LENGTH I<characters> of data into variable SCALAR
+from the specified FILEHANDLE, using the system call read(2).  It
+bypasses buffered IO, so mixing this with other kinds of reads,
+C<print>, C<write>, C<seek>, C<tell>, or C<eof> can cause confusion
+because stdio usually buffers data.  Returns the number of characters
+actually read, C<0> at end of file, or undef if there was an error (in
+the latter case C<$!> is also set).  SCALAR will be grown or shrunk so
+that the last byte actually read is the last byte of the scalar after
+the read.
 
 Note the I<characters>: depending on the status of the filehandle,
 either (8-bit) bytes or characters are read.  By default all
@@ -5644,9 +5645,10 @@ is not specified, writes whole SCALAR.  It bypasses buffered IO, so
 mixing this with reads (other than C<sysread())>, C<print>, C<write>,
 C<seek>, C<tell>, or C<eof> may cause confusion because stdio usually
 buffers data.  Returns the number of characters actually written, or
-C<undef> if there was an error.  If the LENGTH is greater than the
-available data in the SCALAR after the OFFSET, only as much data as is
-available will be written.
+C<undef> if there was an error (in this case the errno variable C<$!>
+is also set).  If the LENGTH is greater than the available data in the
+SCALAR after the OFFSET, only as much data as is available will be
+written.
 
 An OFFSET may be specified to write the data from some part of the
 string other than the beginning.  A negative OFFSET specifies writing
index 2d27d86..2939e90 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -734,6 +734,7 @@ PP(pp_binmode)
     if (!(io = GvIO(gv)) || !(fp = IoIFP(io))) {
        if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
            report_evil_fh(gv, io, PL_op->op_type);
+       SETERRNO(EBADF,RMS_IFI);
         RETPUSHUNDEF;
     }
 
@@ -1177,6 +1178,7 @@ PP(pp_getc)
        if (ckWARN2(WARN_UNOPENED,WARN_CLOSED)
                && (!io || (!IoIFP(io) && IoTYPE(io) != IoTYPE_WRONLY)))
            report_evil_fh(gv, io, PL_op->op_type);
+       SETERRNO(EBADF,RMS_IFI);
        RETPUSHUNDEF;
     }
     TAINT;
@@ -1571,8 +1573,12 @@ PP(pp_sysread)
     else
        offset = 0;
     io = GvIO(gv);
-    if (!io || !IoIFP(io))
+    if (!io || !IoIFP(io)) {
+       if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
+           report_evil_fh(gv, io, PL_op->op_type);
+       SETERRNO(EBADF,RMS_IFI);
        goto say_undef;
+    }
     if ((fp_utf8 = PerlIO_isutf8(IoIFP(io))) && !IN_BYTES) {
        buffer = SvPVutf8_force(bufsv, blen);
        /* UTF8 may not have been set if they are all low bytes */
@@ -1813,6 +1819,7 @@ PP(pp_send)
        retval = -1;
        if (ckWARN(WARN_CLOSED))
            report_evil_fh(gv, io, PL_op->op_type);
+       SETERRNO(EBADF,RMS_IFI);
        goto say_undef;
     }
 
index 3775290..f50d0f7 100644 (file)
@@ -3,12 +3,13 @@
 BEGIN {
     chdir 't' if -d 't';
     @INC = qw(. ../lib);
+    require './test.pl';
 }
 
 use Config;
+use Errno;
 
-require "test.pl";
-plan(tests => 8);
+plan(tests => 9);
 
 ok( binmode(STDERR),            'STDERR made binary' );
 if (find PerlIO::Layer 'perlio') {
@@ -28,3 +29,12 @@ if (find PerlIO::Layer 'perlio') {
 }
 ok( binmode(STDOUT, ":raw"),    '  raw' );
 ok( binmode(STDOUT, ":crlf"),   '  and crlf' );
+
+SKIP: {
+    skip "no EBADF", 1 if (!exists &Errno::EBADF);
+
+    no warnings 'io';
+    $! = 0;
+    binmode(B);
+    ok($! == &Errno::EBADF);
+}
index 0578ee6..f33aa66 100755 (executable)
@@ -1,8 +1,16 @@
 #!./perl
 
-print "1..18\n";
+BEGIN {
+    chdir 't' if -d 't';
+    @INC = '../lib';
+}
+
+use strict 'vars';
+use Errno;
+
+print "1..19\n";
 
-$foo = 'STDOUT';
+my $foo = 'STDOUT';
 print $foo "ok 1\n";
 
 print "ok 2\n","ok 3\n","ok 4\n";
@@ -14,7 +22,7 @@ print foo "ok 6\n";
 printf "ok %d\n",7;
 printf("ok %d\n",8);
 
-@a = ("ok %d%c",9,ord("\n"));
+my @a = ("ok %d%c",9,ord("\n"));
 printf @a;
 
 $a[1] = 10;
@@ -25,10 +33,19 @@ $\ = "\n";
 
 print "ok","11";
 
-@x = ("ok","12\nok","13\nok");
-@y = ("15\nok","16");
+my @x = ("ok","12\nok","13\nok");
+my @y = ("15\nok","16");
 print @x,"14\nok",@y;
 {
     local $\ = "ok 17\n# null =>[\000]\nok 18\n";
     print "";
 }
+
+if (!exists &Errno::EBADF) {
+    print "ok 19 # skipped: no EBADF\n";
+} else {
+    $! = 0;
+    print NONEXISTENT "foo";
+    print "not " if ($! != &Errno::EBADF);
+    print "ok 19\n";
+}
index b27fde1..ea2672d 100755 (executable)
@@ -2,13 +2,22 @@
 
 # $RCSfile$
 
-print "1..1\n";
+BEGIN {
+    chdir 't' if -d 't';
+    @INC = '../lib';
+    require './test.pl';
+}
+
+use strict;
+use Errno;
+
+plan tests => 2;
 
 open(A,"+>a");
 print A "_";
 seek(A,0,0);
 
-$b = "abcd"; 
+my $b = "abcd"; 
 $b = "";
 
 read(A,$b,1,4);
@@ -17,10 +26,14 @@ close(A);
 
 unlink("a");
 
-if ($b eq "\000\000\000\000_") {
-       print "ok 1\n";
-} else { # Probably "\000bcd_"
-       print "not ok 1\n";
-}
+is($b,"\000\000\000\000_"); # otherwise probably "\000bcd_"
 
 unlink 'a';
+
+SKIP: {
+    skip "no EBADF", 1 if (!exists &Errno::EBADF);
+
+    $! = 0;
+    read(B,$b,1);
+    ok($! == &Errno::EBADF);
+}
index be8bb62..881e81e 100644 (file)
@@ -389,9 +389,18 @@ my $a = sysread(F, $a,10) ;
 no warnings 'io' ;
 my $a = sysread(F, $a,10) ;
 close F ;
+use warnings 'io' ;
+sysread(F, $a, 10);
+read(F, $a, 10);
+sysread(NONEXISTENT, $a, 10);
+read(NONEXISTENT, $a, 10);
 unlink $file ;
 EXPECT
 Filehandle F opened only for output at - line 12.
+sysread() on closed filehandle F at - line 17.
+read() on closed filehandle F at - line 18.
+sysread() on unopened filehandle NONEXISTENT at - line 19.
+read() on unopened filehandle NONEXISTENT at - line 20.
 ########
 # pp_sys.c [pp_binmode]
 use warnings 'unopened' ;