--
'Andy Lester an...@petdance.com
Programmer/author petdance.com
Daddy parsley.org/quinn Jk'=~/.+/s;print((split//,$&)
[unpack'C*',"n2]3%+>\"34.'%&.'^%4+!o.'"])
> +=head2 Indirect Filehandles
> +
> +C<open>'s first argument can be a reference to a filehandle. If the
^ As of 5.6.0
> +argument is uninitialized, Perl will automatically create a filehandle
> +and put a reference to it in the first argument, like so:
> +
> + open( my $in, $infile ) or die "Couldn't read $infile: $!";
Seeing as we make a point later on of noting the time of introduction of
new features:
> manpage or its local equivalent for details. (Note: starting from
> -Perl release 5.6 the O_LARGEFILE flag, if available, is automatically
> +Perl release 5.6 the C<O_LARGEFILE> flag, if available, is automatically
> added to the sysopen() flags because large files are the default.)
Even if people think that my suggested change is worth making, it's not a
reason for holding back and making a patch #4. It can be made later.
Nicholas Clark
--
Even better than the real thing: http://nms-cgi.sourceforge.net/
There is probably room for more changes: for example, there is no initial
explanation of what all those shell redirection characters actually do.
Certainly also much of the text about protecting filenames for the 2-arg
form could be replaced with a reference to the 3-arg form (though you'd
still need some of it to allow pick'n'mix magic).
I've left in the one of Tom's polemics that you removed; feel free to
provide a more appropriate 'safe update' example if you want to find
an acceptable justification for removing it.
Hugo
==== //depot/perl/pod/perlopentut.pod#15 - /src/hv/perl/pod/perlopentut.pod ====
@@ -64,8 +74,8 @@
open INFO, "< datafile"
open INFO, "< datafile"
-Ignoring surround whitespace also helps for when you read a filename in
-from a different file, and forget to trim it before opening:
+Ignoring surrounding whitespace also helps for when you read a filename
+in from a different file, and forget to trim it before opening:
$filename = <INFO>; # oops, \n still there
open(EXTRA, "< $filename") || die "can't open $filename: $!";
@@ -76,6 +86,43 @@
as well. For accessing files with naughty names, see
L<"Dispelling the Dweomer">.
+There is also a 3-argument version of C<open>, which lets you put the
+special redirection characters into their own argument:
+
+ open( INFO, ">", $datafile ) || die "Can't create $datafile: $!";
+
+In this case, the filename to open is the actual string in C<$datafile>,
+so you don't have to worry about C<$datafile> containing characters
+that might influence the open mode, or whitespace at the beginning of
+the filename that would be absorbed in the 2-argument version. Also,
+any reduction of unnecessary string interpolation is a good thing.
+
+=head2 Indirect Filehandles
+
+C<open>'s first argument can be a reference to a filehandle. If the
+argument is uninitialized, Perl will automatically create a filehandle
+and put a reference to it in the first argument, like so:
+
+ open( my $in, $infile ) or die "Couldn't read $infile: $!";
+ while ( <$in> ) {
+ # do something with $_
+ }
+ close $in;
+
+Indirect filehandles make namespace management easier. Since filehandles
+are global to the current package, two subroutines trying to open
+C<INFILE> will clash. With two functions opening indirect filehandles
+like C<my $infile>, there's no clash and no need to worry about future
+conflicts.
+
+Another convenient behavior is that an indirect filehandle automatically
+closes when it goes out of scope or when you undefine it:
+
+ sub firstline {
+ open( my $in, shift ) && return scalar <$in>;
+ # no close() required
+ }
+
=head2 Pipe Opens
In C, when you want to open a file using the standard I/O library,
@@ -85,7 +132,7 @@
remains the same--just its argument differs.
If the leading character is a pipe symbol, C<open> starts up a new
-command and open a write-only filehandle leading into that command.
+command and opens a write-only filehandle leading into that command.
This lets you write into that handle and have what you write show up on
that command's standard input. For example:
@@ -98,7 +145,7 @@
command writes to its standard output show up on your handle for reading.
For example:
- open(NET, "netstat -i -n |") || die "can't fun netstat: $!";
+ open(NET, "netstat -i -n |") || die "can't fork netstat: $!";
while (<NET>) { } # do something with input
close(NET) || die "can't close netstat: $!";
@@ -164,7 +211,7 @@
use this approach for updating. Instead, Perl's B<-i> flag comes to
the rescue. The following command takes all the C, C++, or yacc source
or header files and changes all their foo's to bar's, leaving
-the old version in the original file name with a ".orig" tacked
+the old version in the original filename with a ".orig" tacked
on the end:
$ perl -i.orig -pe 's/\bfoo\b/bar/g' *.[Cchy]
@@ -197,7 +244,7 @@
You are welcome to pre-process your @ARGV before starting the loop to
make sure it's to your liking. One reason to do this might be to remove
command options beginning with a minus. While you can always roll the
-simple ones by hand, the Getopts modules are good for this.
+simple ones by hand, the Getopts modules are good for this:
use Getopt::Std;
@@ -250,10 +297,10 @@
input (F<tmpfile> in this case), the F<f2> file, the F<cmd2> command,
and finally the F<f3> file.
-Yes, this also means that if you have a file named "-" (and so on) in
-your directory, that they won't be processed as literal files by C<open>.
-You'll need to pass them as "./-" much as you would for the I<rm> program.
-Or you could use C<sysopen> as described below.
+Yes, this also means that if you have files named "-" (and so on) in
+your directory, they won't be processed as literal files by C<open>.
+You'll need to pass them as "./-", much as you would for the I<rm> program,
+or you could use C<sysopen> as described below.
One of the more interesting applications is to change files of a certain
name into pipes. For example, to autoprocess gzipped or compressed
@@ -273,7 +320,7 @@
If you want the convenience of the shell, then Perl's C<open> is
definitely the way to go. On the other hand, if you want finer precision
-than C's simplistic fopen(3S) provides, then you should look to Perl's
+than C's simplistic fopen(3S) provides you should look to Perl's
C<sysopen>, which is a direct hook into the open(2) system call.
That does mean it's a bit more involved, but that's the price of
precision.
@@ -310,14 +357,14 @@
C<O_DEFER>, C<O_SYNC>, C<O_ASYNC>, C<O_DSYNC>, C<O_RSYNC>,
C<O_NOCTTY>, C<O_NDELAY> and C<O_LARGEFILE>. Consult your open(2)
manpage or its local equivalent for details. (Note: starting from
-Perl release 5.6 the O_LARGEFILE flag, if available, is automatically
+Perl release 5.6 the C<O_LARGEFILE> flag, if available, is automatically
added to the sysopen() flags because large files are the default.)
Here's how to use C<sysopen> to emulate the simple C<open> calls we had
before. We'll omit the C<|| die $!> checks for clarity, but make sure
you always check the return values in real code. These aren't quite
the same, since C<open> will trim leading and trailing white space,
-but you'll get the idea:
+but you'll get the idea.
To open a file for reading:
@@ -341,7 +388,7 @@
sysopen(FH, $path, O_RDWR);
And here are things you can do with C<sysopen> that you cannot do with
-a regular C<open>. As you see, it's just a matter of controlling the
+a regular C<open>. As you'll see, it's just a matter of controlling the
flags in the third argument.
To open a file for writing, creating a new file which must not previously
@@ -379,7 +426,7 @@
For example, if your C<umask> were 027, then the 020 part would
disable the group from writing, and the 007 part would disable others
from reading, writing, or executing. Under these conditions, passing
-C<sysopen> 0666 would create a file with mode 0640, since C<0666 &~ 027>
+C<sysopen> 0666 would create a file with mode 0640, since C<0666 & ~027>
is 0640.
You should seldom use the MASK argument to C<sysopen()>. That takes
@@ -463,7 +510,7 @@
it, it's necessary to protect any leading and trailing whitespace.
Leading whitespace is protected by inserting a C<"./"> in front of a
filename that starts with whitespace. Trailing whitespace is protected
-by appending an ASCII NUL byte (C<"\0">) at the end off the string.
+by appending an ASCII NUL byte (C<"\0">) at the end of the string.
$file =~ s#^(\s)#./$1#;
open(FH, "< $file\0") || die "can't open $file: $!";
@@ -501,9 +548,9 @@
Some warning at scriptname line 29, <FH> line 7.
That's because you opened a filehandle FH, and had read in seven records
-from it. But what was the name of the file, not the handle?
+from it. But what was the name of the file, rather than the handle?
-If you aren't running with C<strict refs>, or if you've turn them off
+If you aren't running with C<strict refs>, or if you've turned them off
temporarily, then all you have to do is this:
open($path, "< $path") || die "can't open $path: $!";
@@ -608,7 +655,7 @@
symbolic links, named pipes, Unix-domain sockets, and block and character
devices. Those are all files, too--just not I<plain> files. This isn't
the same issue as being a text file. Not all text files are plain files.
-Not all plain files are textfiles. That's why there are separate C<-f>
+Not all plain files are text files. That's why there are separate C<-f>
and C<-T> file tests.
To open a directory, you should use the C<opendir> function, then
@@ -622,8 +669,8 @@
closedir(DIR);
If you want to process directories recursively, it's better to use the
-File::Find module. For example, this prints out all files recursively,
-add adds a slash to their names if the file is a directory.
+File::Find module. For example, this prints out all files recursively
+and adds a slash to their names if the file is a directory.
@ARGV = qw(.) unless @ARGV;
use File::Find;
@@ -645,13 +692,15 @@
}
}
+=head2 Opening Named Pipes
+
Named pipes are a different matter. You pretend they're regular files,
but their opens will normally block until there is both a reader and
a writer. You can read more about them in L<perlipc/"Named Pipes">.
Unix-domain sockets are rather different beasts as well; they're
described in L<perlipc/"Unix-Domain TCP Clients and Servers">.
-When it comes to opening devices, it can be easy and it can tricky.
+When it comes to opening devices, it can be easy and it can be tricky.
We'll assume that if you're opening up a block device, you know what
you're doing. The character devices are more interesting. These are
typically used for modems, mice, and some kinds of printers. This is
@@ -669,8 +718,8 @@
print TTYOUT "+++at\015";
$answer = <TTYIN>;
-With descriptors that you haven't opened using C<sysopen>, such as a
-socket, you can set them to be non-blocking using C<fcntl>:
+With descriptors that you haven't opened using C<sysopen>, such as
+sockets, you can set them to be non-blocking using C<fcntl>:
use Fcntl;
fcntl(Connection, F_SETFL, O_NONBLOCK)
@@ -685,6 +734,8 @@
also some high-level modules on CPAN that can help you with these games.
Check out Term::ReadKey and Term::ReadLine.
+=head2 Opening Sockets
+
What else can you open? To open a connection using sockets, you won't use
one of Perl's two open functions. See
L<perlipc/"Sockets: Client/Server Communication"> for that. Here's an
@@ -720,13 +771,13 @@
Passing C<sysopen> a non-standard flag option will also open the file in
binary mode on those systems that support it. This is the equivalent of
-opening the file normally, then calling C<binmode>ing on the handle.
+opening the file normally, then calling C<binmode> on the handle.
sysopen(BINDAT, "records.data", O_RDWR | O_BINARY)
|| die "can't open records.data: $!";
Now you can use C<read> and C<print> on that handle without worrying
-about the system non-standard I/O library breaking your data. It's not
+about the non-standard system I/O library breaking your data. It's not
a pretty picture, but then, legacy systems seldom are. CP/M will be
with us until the end of days, and after.
@@ -745,18 +796,20 @@
=head2 File Locking
In a multitasking environment, you may need to be careful not to collide
-with other processes who want to do I/O on the same files as others
+with other processes who want to do I/O on the same files as you
are working on. You'll often need shared or exclusive locks
on files for reading and writing respectively. You might just
pretend that only exclusive locks exist.
Never use the existence of a file C<-e $file> as a locking indication,
because there is a race condition between the test for the existence of
-the file and its creation. Atomicity is critical.
+the file and its creation. It's possible for another process to create
+a file in the slice of time between your existence check and your attempt
+to create the file. Atomicity is critical.
Perl's most portable locking interface is via the C<flock> function,
-whose simplicity is emulated on systems that don't directly support it,
-such as SysV or WindowsNT. The underlying semantics may affect how
+whose simplicity is emulated on systems that don't directly support it
+such as SysV or Windows. The underlying semantics may affect how
it all works, so you should learn how C<flock> is implemented on your
system's port of Perl.
@@ -842,8 +895,8 @@
In Perl 5.8.0 a new I/O framework called "PerlIO" was introduced.
This is a new "plumbing" for all the I/O happening in Perl; for the
-most part everything will work just as it did, but PerlIO brought in
-also some new features, like the capability of think of I/O as "layers".
+most part everything will work just as it did, but PerlIO also brought
+in some new features such as the ability to think of I/O as "layers".
One I/O layer may in addition to just moving the data also do
transformations on the data. Such transformations may include
compression and decompression, encryption and decryption, and transforming
@@ -856,7 +909,7 @@
=item *
-The three-(or more)-argument form of C<open()> is being used and the
+The three-(or more)-argument form of C<open> is being used and the
second argument contains something else in addition to the usual
C<< '<' >>, C<< '>' >>, C<< '>>' >>, C<< '|' >> and their variants,
for example:
@@ -865,7 +918,7 @@
=item *
-The two-argument form of C<binmode<open()> is being used, for example
+The two-argument form of C<binmode> is being used, for example
binmode($fh, ":encoding(utf16)");
@@ -876,8 +929,8 @@
=head1 SEE ALSO
-The C<open> and C<sysopen> function in perlfunc(1);
-the standard open(2), dup(2), fopen(3), and fdopen(3) manpages;
+The C<open> and C<sysopen> functions in perlfunc(1);
+the system open(2), dup(2), fopen(3), and fdopen(3) manpages;
the POSIX documentation.
=head1 AUTHOR and COPYRIGHT
I have no problem with the example. I have a problem with the
pointlessly aggressive discussion of it, and in a tutorial, no less.
(For those observing from the outside, here's the offending quote:
"Finally, due to the uncounted millions who cannot be dissuaded from
wasting cycles on useless vanity devices called hit counters, here's
how to increment a number in a file safely:")
The commentary provides no positive value, and very well likely has
negative value. Why do we want to insult our colleagues? Who are we
to say that hit counters have no value? And why do we have to be jerks
about it?
Perl does NOT need to make value judgments about those things.
> if you want to find an acceptable justification for removing it.
Removing text that intentionally insults our colleagues is reason enough.
xoa
I agree with this.
> (For those observing from the outside, here's the offending quote:
> "Finally, due to the uncounted millions who cannot be dissuaded from
> wasting cycles on useless vanity devices called hit counters, here's
> how to increment a number in a file safely:")
>
> The commentary provides no positive value, and very well likely has
> negative value. Why do we want to insult our colleagues? Who are we
> to say that hit counters have no value? And why do we have to be jerks
> about it?
>
> Perl does NOT need to make value judgments about those things.
>
>
> > if you want to find an acceptable justification for removing it.
>
> Removing text that intentionally insults our colleagues is reason enough.
Can it be rephrased? I believe there's scope for more subtle damning of
CGI hit counters that don't actually count properly than I managed :-)
Nicholas Clark
--
Even better than the real thing: http://nms-cgi.sourceforge.net/
--- pod/perlopentut.pod.orig Fri Sep 27 12:00:58 2002
+++ pod/perlopentut.pod Mon Sep 30 22:10:12 2002
@@ -868,9 +868,11 @@
or die "can't truncate filename: $!";
# now write to FH
-Finally, due to the uncounted millions who cannot be dissuaded from
-wasting cycles on useless vanity devices called hit counters, here's
-how to increment a number in a file safely:
+Finally, here's how to increment a number in a file safely, when more
+than one program might be running simultaneously, such as CGI scripts
+on a web server. For example, a hit counter that doesn't use locking
+like this will lose count (or worse, corrupt the file) if the web
+server runs two or more instances at the same time.
Well, perhaps it's just me, but I like Toms polemics. It draws a
smile on my face when reading an otherwise boring document.
I also think people should not be insulted too quickly. Otherwise,
I would be insulted - calling me a 'colleague' of people creating
web counters.
Abigail
Agreed.
> I also think people should not be insulted too quickly. Otherwise,
> I would be insulted - calling me a 'colleague' of people creating
> web counters.
Heh. Good point. I agree totally FWIW.
yves
I think it is an issue of the integrity of a person's contribution:
the original author put in the time to develop and explain the code
needed to perform the update correctly, but chose additionally to
annotate it with his opinions on the desire to do that. I consider
it quite unreasonable to keep the code, and so to take advantage of
the effort expended in its development, without also keeping that
additional annotation.
If the polemic were deemed unacceptable, the time to object to it
would have been before the tutorial was originally accepted as part
of the perl distribution; at that point it might have been reasonable
to negotiate with the author for something less severe in its
condemnation. But the text has been there since at least January 1999.
It is also true that I do not find the words unreasonable (though I'd
probably not have chosen to express my opinions quite like that), but
that has very little relevance to my decision to retain them.
Hugo
I understand, and even agree with, your point in this case, but I'm also
afraid of the atomicity of a "contribution". Where are the boundaries
of a contribution? Can no one but the original author change the
document? How about tweaking a word here or there?
> But the text has been there since at least January 1999.
That reads an awful lot like "That's the way we've always done it",
which I don't think is what you're saying.
Here's the real key in my mind: I consider it to be a bug in the
documentation that a tutorial insults the reader. There's more to what
we distribute than just technical correctness.
Personally, I don't think it's unreasonable to take advantage of effort
expended in the development of an example, without also keeping additional
annotation. The development of Perl is a collaborative process. People
who participate should be aware that their contributions will be reviewed
and changed by other participants making their own contributions.
> If the polemic were deemed unacceptable, the time to object to it
> would have been before the tutorial was originally accepted as part
> of the perl distribution; at that point it might have been reasonable
> to negotiate with the author for something less severe in its
> condemnation. But the text has been there since at least January 1999.
I know that backwards compatibility is a strong argument for changes to the
code, but I think this is the first time I've seen it applied to the
documentation. :)
I see this is an opportunity to improve the documentation. I think we
need a better reason not to do so than just 'the documentation has been
that way for several years'.
> It is also true that I do not find the words unreasonable (though I'd
> probably not have chosen to express my opinions quite like that), but
> that has very little relevance to my decision to retain them.
I don't think this editorialization is appropriate for the Perl
documentation, particularly because I find it overly harsh and elitist.
Ronald