From: Gurusamy Sarathy Date: Sun, 14 Feb 1999 05:51:56 +0000 (+0000) Subject: slurping an empty file should return '' rather than undef, with X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=fbad3eb55c1f8c84d1dfd0e484ecddeffc891e79;p=p5sagit%2Fp5-mst-13.2.git slurping an empty file should return '' rather than undef, with commensurate effects on ARGV processing p4raw-id: //depot/perl@2910 --- diff --git a/pod/perldelta.pod b/pod/perldelta.pod index efa52de..d858508 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -125,6 +125,25 @@ now correctly prints "3|a", instead of "2|a". The new format type 'Z' is useful for packing and unpacking null-terminated strings. See L. +=head1 Significant bug fixes + +=head2 EHANDLEE on empty files + +With C<$/> set to C, slurping an empty file returns a string of +zero length (instead of C, as it used to) for the first time the +HANDLE is read. Subsequent reads yield C. + +This means that the following will append "foo" to an empty file (it used +to not do anything before): + + perl -0777 -pi -e 's/^/foo/' empty_file + +Note that the behavior of: + + perl -pi -e 's/^/foo/' empty_file + +is unchanged (it continues to leave the file empty). + =head1 Supported Platforms =over 4 @@ -225,8 +244,25 @@ stat(2) might lie, while access(2) knows better. =head1 Utility Changes +=head2 New Modules + +=over + Todo. +=back + +=head2 Changes in existing modules + +=over + +=item Exporter + +Exporter::expand() takes an import list and returns the expanded +list of names. + +=back + =head1 Documentation Changes =over 4 diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod index 1495514..0d09e85 100644 --- a/pod/perlfunc.pod +++ b/pod/perlfunc.pod @@ -2841,10 +2841,17 @@ C there, it would have been testing the wrong file. =item readline EXPR -Reads from the filehandle whose typeglob is contained in EXPR. In scalar context, a single line -is read and returned. In list context, reads until end-of-file is -reached and returns a list of lines (however you've defined lines -with C<$/> or C<$INPUT_RECORD_SEPARATOR>). +Reads from the filehandle whose typeglob is contained in EXPR. In scalar +context, each call reads and returns the next line, until end-of-file is +reached, whereupon the subsequent call returns undef. In list context, +reads until end-of-file is reached and returns a list of lines. Note that +the notion of "line" used here is however you may have defined it +with C<$/> or C<$INPUT_RECORD_SEPARATOR>). See L. + +When C<$/> is set to C and when readline() is in a scalar +context (i.e. file slurp mode), it returns C<''> the first time, +followed by C subsequently. + This is the internal function implementing the CEXPRE> operator, but you can use it directly. The CEXPRE> operator is discussed in more detail in L. diff --git a/pod/perlop.pod b/pod/perlop.pod index b386651..73066c1 100644 --- a/pod/perlop.pod +++ b/pod/perlop.pod @@ -1445,6 +1445,7 @@ to change. =head2 I/O Operators There are several I/O operators you should know about. + A string enclosed by backticks (grave accents) first undergoes variable substitution just like a double quoted string. It is then interpreted as a command, and the output of that command is the value @@ -1462,9 +1463,12 @@ The generalized form of backticks is C. (Because backticks always undergo shell expansion as well, see L for security concerns.) -Evaluating a filehandle in angle brackets yields the next line from -that file (newline, if any, included), or C at end of file. -Ordinarily you must assign that value to a variable, but there is one +In a scalar context, evaluating a filehandle in angle brackets yields the +next line from that file (newline, if any, included), or C at +end-of-file. When C<$/> is set to C (i.e. file slurp mode), +it returns C<''> the first time, followed by C subsequently. + +Ordinarily you must assign the returned value to a variable, but there is one situation where an automatic assignment happens. I the input symbol is the only thing inside the conditional of a C or C loop, the value is automatically assigned to the variable @@ -1501,13 +1505,16 @@ The filehandles STDIN, STDOUT, and STDERR are predefined. (The filehandles C, C, and C will also work except in packages, where they would be interpreted as local identifiers rather than global.) Additional filehandles may be created with the open() -function. See L for details on this. +function. See L for details on this. If a EFILEHANDLEE is used in a context that is looking for a list, a list consisting of all the input lines is returned, one line per list element. It's easy to make a I data space this way, so use with care. +EFILEHANDLEE may also be spelt readline(FILEHANDLE). See +L. + The null filehandle EE is special and can be used to emulate the behavior of B and B. Input from EE comes either from standard input, or from each file listed on the command line. Here's diff --git a/pod/perlvar.pod b/pod/perlvar.pod index b9b0ce6..44124d6 100644 --- a/pod/perlvar.pod +++ b/pod/perlvar.pod @@ -250,8 +250,8 @@ line. Setting it to C<"\n\n"> will blindly assume that the next input character belongs to the next paragraph, even if it's a newline. (Mnemonic: / is used to delimit line boundaries when quoting poetry.) - undef $/; - $_ = ; # whole file now here + undef $/; # enable "slurp" mode + $_ = ; # whole file now here s/\n[ \t]+/ /g; Remember: the value of $/ is a string, not a regexp. AWK has to be diff --git a/pp_hot.c b/pp_hot.c index 27af29d..b1bf270 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -1297,8 +1297,18 @@ do_readline(void) sv = sv_2mortal(NEWSV(57, 80)); offset = 0; } + +/* flip-flop EOF state for a snarfed empty file */ +#define SNARF_EOF(gimme,rs,io,sv) \ + ((gimme != G_SCALAR || SvCUR(sv) \ + || (IoFLAGS(io) & IOf_NOLINE) || IoLINES(io) || !RsSNARF(rs)) \ + ? ((IoFLAGS(io) &= ~IOf_NOLINE), TRUE) \ + : ((IoFLAGS(io) |= IOf_NOLINE), FALSE)) + for (;;) { - if (!sv_gets(sv, fp, offset)) { + if (!sv_gets(sv, fp, offset) + && (type == OP_GLOB || SNARF_EOF(gimme, PL_rs, io, sv))) + { PerlIO_clearerr(fp); if (IoFLAGS(io) & IOf_ARGV) { fp = nextargv(PL_last_in_gv); diff --git a/sv.h b/sv.h index a08a9c8..456d01c 100644 --- a/sv.h +++ b/sv.h @@ -313,6 +313,7 @@ struct xpvio { #define IOf_FLUSH 4 /* this fp wants a flush after write op */ #define IOf_DIDTOP 8 /* just did top of form */ #define IOf_UNTAINT 16 /* consider this fp (and its data) "safe" */ +#define IOf_NOLINE 32 /* slurped a pseudo-line from empty file */ /* The following macros define implementation-independent predicates on SVs. */ diff --git a/t/io/argv.t b/t/io/argv.t index d99865e..cb2ffb3 100755 --- a/t/io/argv.t +++ b/t/io/argv.t @@ -1,10 +1,8 @@ #!./perl -# $RCSfile: argv.t,v $$Revision: 4.1 $$Date: 92/08/07 18:27:25 $ +print "1..6\n"; -print "1..5\n"; - -open(try, '>Io.argv.tmp') || (die "Can't open temp file."); +open(try, '>Io.argv.tmp') || (die "Can't open temp file: $!"); print try "a line\n"; close try; @@ -45,4 +43,17 @@ if ($y eq "1a line\n2a line\n3a line\n") else {print "not ok 5\n";} -unlink 'Io.argv.tmp'; +open(try, '>Io.argv.tmp') or die "Can't open temp file: $!"; +close try; +@ARGV = 'Io.argv.tmp'; +$^I = ''; +$/ = undef; +while (<>) { + s/^/ok 6\n/; + print; +} +open(try, '; +close try; + +END { unlink 'Io.argv.tmp' }