This is Info file perl.info, produced by Makeinfo version 1.68 from the
input file bigperl.texi.

   settitle perl


File: perl.info,  Node: perlopentut,  Next: perlvar,  Prev: perlfunc,  Up: Top

tutorial on opening things in Perl
**********************************

NAME
====

   perlopentut - tutorial on opening things in Perl

DESCRIPTION
===========

   Perl has two simple, built-in ways to open files: the shell way for
convenience, and the C way for precision.  The choice is yours.

Open E<agrave> la shell
=======================

   Perl's open function was designed to mimic the way command-line
redirection in the shell works.  Here are some basic examples from the
shell:

     $ myprogram file1 file2 file3
     $ myprogram    <  inputfile
     $ myprogram    >  outputfile
     $ myprogram    >> outputfile
     $ myprogram    |  otherprogram
     $ otherprogram |  myprogram

   And here are some more advanced examples:

     $ otherprogram      | myprogram f1 - f2
     $ otherprogram 2>&1 | myprogram -
     $ myprogram     <&3
     $ myprogram     >&4

   Programmers accustomed to constructs like those above can take comfort
in learning that Perl directly supports these familiar constructs using
virtually the same syntax as the shell.

Simple Opens
------------

   The open function takes two arguments: the first is a filehandle, and
the second is a single string comprising both what to open and how to open
it.  open returns true when it works, and when it fails, returns a false
value and sets the special variable $! to reflect the system error.  If
the filehandle was previously opened, it will be implicitly closed first.

   For example:

     open(INFO,      "datafile") || die("can't open datafile: $!");
     open(INFO,   "<  datafile") || die("can't open datafile: $!");
     open(RESULTS,">  runstats") || die("can't open runstats: $!");
     open(LOG,    ">> logfile ") || die("can't open logfile:  $!");

   If you prefer the low-punctuation version, you could write that this
way:

     open INFO,   "<  datafile"  or die "can't open datafile: $!";
     open RESULTS,">  runstats"  or die "can't open runstats: $!";
     open LOG,    ">> logfile "  or die "can't open logfile:  $!";

   A few things to notice.  First, the leading less-than is optional.  If
omitted, Perl assumes that you want to open the file for reading.

   The other important thing to notice is that, just as in the shell, any
white space before or after the filename is ignored.  This is good,
because you wouldn't want these to do different things:

     open INFO,   "<datafile"
     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:

     $filename = <INFO>;         # oops, \n still there
     open(EXTRA, "< $filename") || die "can't open $filename: $!";

   This is not a bug, but a feature.  Because open mimics the shell in its
style of using redirection arrows to specify how to open the file, it also
does so with respect to extra white space around the filename itself as
well.  For accessing files with naughty names, see `"Dispelling the
Dweomer"' in this node.

Pipe Opens
----------

   In C, when you want to open a file using the standard I/O library, you
use the fopen function, but when opening a pipe, you use the `popen'
function.  But in the shell, you just use a different redirection
character.  That's also the case for Perl.  The open call remains the
same-just its argument differs.

   If the leading character is a pipe symbol, open starts up a new command
and open 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:

     open(PRINTER, "| lpr -Plp1")    || die "cannot fork: $!";
     print PRINTER "stuff\n";
     close(PRINTER)                  || die "can't close lpr: $!";

   If the trailing character is a pipe, you start up a new command and
open a read-only filehandle leading out of that command.  This lets
whatever that command writes to its standard output show up on your handle
for reading.  For example:

     open(NET, "netstat -i -n |")    || die "cannot fork: $!";
     while (<NET>) { }               # do something with input
     close(NET)                      || die "can't close netstat: $!";

   What happens if you try to open a pipe to or from a non-existent
command?  In most systems, such an open will not return an error. That's
because in the traditional fork/exec model, running the other program
happens only in the forked child process, which means that the failed exec
can't be reflected in the return value of open.  Only a failed fork shows
up there.  See `"Why doesn't open() return an error when a pipe open
fails?"', *Note Perlfaq8: perlfaq8, to see how to cope with this.  There's
also an explanation in `"Why doesn't open() return an error when a pipe
open fails?"', *Note Perlipc: perlipc,.

   If you would like to open a bidirectional pipe, the IPC::Open2 library
will handle this for you.  Check out `"Bidirectional Communication with
Another Process"', *Note Perlipc: perlipc,

The Minus File
--------------

   Again following the lead of the standard shell utilities, Perl's open
function treats a file whose name is a single minus, "-", in a special
way.  If you open minus for reading, it really means to access the
standard input.  If you open minus for writing, it really means to access
the standard output.

   If minus can be used as the default input or default output, what
happens if you open a pipe into or out of minus?  What's the default
command it would run?  The same script as you're currently running!  This
is actually a stealth fork hidden inside an open call.  See `"Safe Pipe
Opens"', *Note Perlipc: perlipc, for details.

Mixing Reads and Writes
-----------------------

   It is possible to specify both read and write access.  All you do is
add a "+" symbol in front of the redirection.  But as in the shell, using
a less-than on a file never creates a new file; it only opens an existing
one.  On the other hand, using a greater-than always clobbers (truncates
to zero length) an existing file, or creates a brand-new one if there
isn't an old one.  Adding a "+" for read-write doesn't affect whether it
only works on existing files or always clobbers existing ones.

     open(WTMP, "+< /usr/adm/wtmp")
         || die "can't open /usr/adm/wtmp: $!";

     open(SCREEN, "+> /tmp/lkscreen")
         || die "can't open /tmp/lkscreen: $!";

     open(LOGFILE, "+>> /tmp/applog"
         || die "can't open /tmp/applog: $!";

   The first one won't create a new file, and the second one will always
clobber an old one.  The third one will create a new file if necessary and
not clobber an old one, and it will allow you to read at any point in the
file, but all writes will always go to the end.  In short, the first case
is substantially more common than the second and third cases, which are
almost always wrong.  (If you know C, the plus in Perl's open is
historically derived from the one in C's fopen(3S), which it ultimately
calls.)

   In fact, when it comes to updating a file, unless you're working on a
binary file as in the WTMP case above, you probably don't want to use this
approach for updating.  Instead, Perl's -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 on the end:

     $ perl -i.orig -pe 's/\bfoo\b/bar/g' *.[Cchy]

   This is a short cut for some renaming games that are really the best
way to update textfiles.  See the second question in *Note Perlfaq5:
perlfaq5, for more details.

Filters
-------

   One of the most common uses for open is one you never even notice.
When you process the ARGV filehandle using `< <ARGV' >>, Perl actually
does an implicit open on each file in @ARGV.  Thus a program called like
this:

     $ myprogram file1 file2 file3

   Can have all its files opened and processed one at a time using a
construct no more complex than:

     while (<>) {
         # do something with $_
     }

   If @ARGV is empty when the loop first begins, Perl pretends you've
opened up minus, that is, the standard input.  In fact, $ARGV, the
currently open file during `< <ARGV' >> processing, is even set to "-" in
these circumstances.

   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.

     use Getopt::Std;

     # -v, -D, -o ARG, sets $opt_v, $opt_D, $opt_o
     getopts("vDo:");

     # -v, -D, -o ARG, sets $args{v}, $args{D}, $args{o}
     getopts("vDo:", \%args);

   Or the standard Getopt::Long module to permit named arguments:

     use Getopt::Long;
     GetOptions( "verbose"  => \$verbose,        # --verbose
                 "Debug"    => \$debug,          # --Debug
                 "output=s" => \$output );
     	    # --output=somestring or --output somestring

   Another reason for preprocessing arguments is to make an empty argument
list default to all files:

     @ARGV = glob("*") unless @ARGV;

   You could even filter out all but plain, text files.  This is a bit
silent, of course, and you might prefer to mention them on the way.

     @ARGV = grep { -f && -T } @ARGV;

   If you're using the -n or -p command-line options, you should put
changes to @ARGV in a `BEGIN{}' block.

   Remember that a normal open has special properties, in that it might
call fopen(3S) or it might called popen(3S), depending on what its
argument looks like; that's why it's sometimes called "magic open".
Here's an example:

     $pwdinfo = `domainname` =~ /^(\(none\))?$/
                     ? '< /etc/passwd'
                     : 'ypcat passwd |';

     open(PWD, $pwdinfo)
                 or die "can't open $pwdinfo: $!";

   This sort of thing also comes into play in filter processing.  Because
`< <ARGV' >> processing employs the normal, shell-style Perl open, it
respects all the special things we've already seen:

     $ myprogram f1 "cmd1|" - f2 "cmd2|" f3 < tmpfile

   That program will read from the file `f1', the process `cmd1', standard
input (tmpfile in this case), the `f2' file, the `cmd2' command, and
finally the `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 open.
You'll need to pass them as "./-" much as you would for the rm program.
Or you could use 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 files
by decompressing them with *gzip*:

     @ARGV = map { /^\.(gz|Z)$/ ? "gzip -dc $_ |" : $_  } @ARGV;

   Or, if you have the GET program installed from LWP, you can fetch URLs
before processing them:

     @ARGV = map { m#^\w+://# ? "GET $_ |" : $_ } @ARGV;

   It's not for nothing that this is called magic `< <ARGV' >>.  Pretty
nifty, eh?

Open E<agrave> la C
===================

   If you want the convenience of the shell, then Perl's 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
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.

   sysopen takes 3 (or 4) arguments.

     sysopen HANDLE, PATH, FLAGS, [MASK]

   The HANDLE argument is a filehandle just as with open.  The PATH is a
literal path, one that doesn't pay attention to any greater-thans or
less-thans or pipes or minuses, nor ignore white space.  If it's there,
it's part of the path.  The FLAGS argument contains one or more values
derived from the Fcntl module that have been or'd together using the
bitwise "|" operator.  The final argument, the MASK, is optional; if
present, it is combined with the user's current umask for the creation
mode of the file.  You should usually omit this.

   Although the traditional values of read-only, write-only, and read-write
are 0, 1, and 2 respectively, this is known not to hold true on some
systems.  Instead, it's best to load in the appropriate constants first
from the Fcntl module, which supplies the following standard flags:

     O_RDONLY            Read only
     O_WRONLY            Write only
     O_RDWR              Read and write
     O_CREAT             Create the file if it doesn't exist
     O_EXCL              Fail if the file already exists
     O_APPEND            Append to the file
     O_TRUNC             Truncate the file
     O_NONBLOCK          Non-blocking access

   Less common flags that are sometimes available on some operating
systems include `O_BINARY', `O_TEXT', `O_SHLOCK', `O_EXLOCK', `O_DEFER',
`O_SYNC', `O_ASYNC', `O_DSYNC', `O_RSYNC', `O_NOCTTY', `O_NDELAY' and
`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 added to the sysopen() flags because large
files are the the default.)

   Here's how to use sysopen to emulate the simple open calls we had
before.  We'll omit the `|| die $!' checks for clarity, but make sure you
always check the return values in real code.  These aren't quite the same,
since open will trim leading and trailing white space, but you'll get the
idea:

   To open a file for reading:

     open(FH, "< $path");
     sysopen(FH, $path, O_RDONLY);

   To open a file for writing, creating a new file if needed or else
truncating an old file:

     open(FH, "> $path");
     sysopen(FH, $path, O_WRONLY | O_TRUNC | O_CREAT);

   To open a file for appending, creating one if necessary:

     open(FH, ">> $path");
     sysopen(FH, $path, O_WRONLY | O_APPEND | O_CREAT);

   To open a file for update, where the file must already exist:

     open(FH, "+< $path");
     sysopen(FH, $path, O_RDWR);

   And here are things you can do with sysopen that you cannot do with a
regular open.  As you 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 exist:

     sysopen(FH, $path, O_WRONLY | O_EXCL | O_CREAT);

   To open a file for appending, where that file must already exist:

     sysopen(FH, $path, O_WRONLY | O_APPEND);

   To open a file for update, creating a new file if necessary:

     sysopen(FH, $path, O_RDWR | O_CREAT);

   To open a file for update, where that file must not already exist:

     sysopen(FH, $path, O_RDWR | O_EXCL | O_CREAT);

   To open a file without blocking, creating one if necessary:

     sysopen(FH, $path, O_WRONLY | O_NONBLOCK | O_CREAT);

Permissions E<agrave> la mode
-----------------------------

   If you omit the MASK argument to sysopen, Perl uses the octal value
0666.  The normal MASK to use for executables and directories should be
0777, and for anything else, 0666.

   Why so permissive?  Well, it isn't really.  The MASK will be modified
by your process's current umask.  A umask is a number representing
disabled permissions bits; that is, bits that will not be turned on in the
created files' permissions field.

   For example, if your 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 sysopen
0666 would create a file with mode 0640, since `0666 &~ 027' is 0640.

   You should seldom use the MASK argument to `sysopen()'.  That takes
away the user's freedom to choose what permission new files will have.
Denying choice is almost always a bad thing.  One exception would be for
cases where sensitive or private data is being stored, such as with mail
folders, cookie files, and internal temporary files.

Obscure Open Tricks
===================

Re-Opening Files (dups)
-----------------------

   Sometimes you already have a filehandle open, and want to make another
handle that's a duplicate of the first one.  In the shell, we place an
ampersand in front of a file descriptor number when doing redirections.
For example, `< 2'&1 >> makes descriptor 2 (that's STDERR in Perl) be
redirected into descriptor 1 (which is usually Perl's STDOUT).  The same
is essentially true in Perl: a filename that begins with an ampersand is
treated instead as a file descriptor if a number, or as a filehandle if a
string.

     open(SAVEOUT, ">&SAVEERR") || die "couldn't dup SAVEERR: $!";
     open(MHCONTEXT, "<&4")     || die "couldn't dup fd4: $!";

   That means that if a function is expecting a filename, but you don't
want to give it a filename because you already have the file open, you can
just pass the filehandle with a leading ampersand.  It's best to use a
fully qualified handle though, just in case the function happens to be in
a different package:

     somefunction("&main::LOGFILE");

   This way if somefunction() is planning on opening its argument, it can
just use the already opened handle.  This differs from passing a handle,
because with a handle, you don't open the file.  Here you have something
you can pass to open.

   If you have one of those tricky, newfangled I/O objects that the C++
folks are raving about, then this doesn't work because those aren't a
proper filehandle in the native Perl sense.  You'll have to use fileno()
to pull out the proper descriptor number, assuming you can:

     use IO::Socket;
     $handle = IO::Socket::INET->new("www.perl.com:80");
     $fd = $handle->fileno;
     somefunction("&$fd");  # not an indirect function call

   It can be easier (and certainly will be faster) just to use real
filehandles though:

     use IO::Socket;
     local *REMOTE = IO::Socket::INET->new("www.perl.com:80");
     die "can't connect" unless defined(fileno(REMOTE));
     somefunction("&main::REMOTE");

   If the filehandle or descriptor number is preceded not just with a
simple "&" but rather with a "&=" combination, then Perl will not create a
completely new descriptor opened to the same place using the dup(2) system
call.  Instead, it will just make something of an alias to the existing
one using the fdopen(3S) library call  This is slightly more parsimonious
of systems resources, although this is less a concern these days.  Here's
an example of that:

     $fd = $ENV{"MHCONTEXTFD"};
     open(MHCONTEXT, "<&=$fd")   or die "couldn't fdopen $fd: $!";

   If you're using magic `< <ARGV' >>, you could even pass in as a command
line argument in @ARGV something like `"<&=$MHCONTEXTFD"', but we've never
seen anyone actually do this.

Dispelling the Dweomer
----------------------

   Perl is more of a DWIMmer language than something like Java-where DWIM
is an acronym for "do what I mean".  But this principle sometimes leads to
more hidden magic than one knows what to do with.  In this way, Perl is
also filled with *dweomer*, an obscure word meaning an enchantment.
Sometimes, Perl's DWIMmer is just too much like dweomer for comfort.

   If magic open is a bit too magical for you, you don't have to turn to
sysopen.  To open a file with arbitrary weird characters in it, it's
necessary to protect any leading and trailing whitespace.  Leading
whitespace is protected by inserting a `"./"' in front of a filename that
starts with whitespace.  Trailing whitespace is protected by appending an
ASCII NUL byte (`"\0"') at the end off the string.

     $file =~ s#^(\s)#./$1#;
     open(FH, "< $file\0")   || die "can't open $file: $!";

   This assumes, of course, that your system considers dot the current
working directory, slash the directory separator, and disallows ASCII NULs
within a valid filename.  Most systems follow these conventions, including
all POSIX systems as well as proprietary Microsoft systems.  The only
vaguely popular system that doesn't work this way is the proprietary
Macintosh system, which uses a colon where the rest of us use a slash.
Maybe sysopen isn't such a bad idea after all.

   If you want to use `< <ARGV' >> processing in a totally boring and
non-magical way, you could do this first:

     #   "Sam sat on the ground and put his head in his hands.
     #   'I wish I had never come here, and I don't want to see
     #   no more magic,' he said, and fell silent."
     for (@ARGV) {
         s#^([^./])#./$1#;
         $_ .= "\0";
     }
     while (<>) {
         # now process $_
     }

   But be warned that users will not appreciate being unable to use "-" to
mean standard input, per the standard convention.

Paths as Opens
--------------

   You've probably noticed how Perl's warn and die functions can produce
messages like:

     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?

   If you aren't running with `strict refs', or if you've turn them off
temporarily, then all you have to do is this:

     open($path, "< $path") || die "can't open $path: $!";
     while (<$path>) {
         # whatever
     }

   Since you're using the pathname of the file as its handle, you'll get
warnings more like

     Some warning at scriptname line 29, </etc/motd> line 7.

Single Argument Open
--------------------

   Remember how we said that Perl's open took two arguments?  That was a
passive prevarication.  You see, it can also take just one argument.  If
and only if the variable is a global variable, not a lexical, you can pass
open just one argument, the filehandle, and it will get the path from the
global scalar variable of the same name.

     $FILE = "/etc/motd";
     open FILE or die "can't open $FILE: $!";
     while (<FILE>) {
         # whatever
     }

   Why is this here?  Someone has to cater to the hysterical porpoises.
It's something that's been in Perl since the very beginning, if not before.

Playing with STDIN and STDOUT
-----------------------------

   One clever move with STDOUT is to explicitly close it when you're done
with the program.

     END { close(STDOUT) || die "can't close stdout: $!" }

   If you don't do this, and your program fills up the disk partition due
to a command line redirection, it won't report the error exit with a
failure status.

   You don't have to accept the STDIN and STDOUT you were given.  You are
welcome to reopen them if you'd like.

     open(STDIN, "< datafile")
     	|| die "can't open datafile: $!";

     open(STDOUT, "> output")
     	|| die "can't open output: $!";

   And then these can be read directly or passed on to subprocesses.  This
makes it look as though the program were initially invoked with those
redirections from the command line.

   It's probably more interesting to connect these to pipes.  For example:

     $pager = $ENV{PAGER} || "(less || more)";
     open(STDOUT, "| $pager")
     	|| die "can't fork a pager: $!";

   This makes it appear as though your program were called with its stdout
already piped into your pager.  You can also use this kind of thing in
conjunction with an implicit fork to yourself.  You might do this if you
would rather handle the post processing in your own program, just in a
different process:

     head(100);
     while (<>) {
         print;
     }

     sub head {
         my $lines = shift || 20;
         return unless $pid = open(STDOUT, "|-");
         die "cannot fork: $!" unless defined $pid;
         while (<STDIN>) {
             print;
             last if --$lines < 0;
         }
         exit;
     }

   This technique can be applied to repeatedly push as many filters on your
output stream as you wish.

Other I/O Issues
================

   These topics aren't really arguments related to open or sysopen, but
they do affect what you do with your open files.

Opening Non-File Files
----------------------

   When is a file not a file?  Well, you could say when it exists but
isn't a plain file.   We'll check whether it's a symbolic link first, just
in case.

     if (-l $file || ! -f _) {
         print "$file is not a plain file\n";
     }

   What other kinds of files are there than, well, files?  Directories,
symbolic links, named pipes, Unix-domain sockets, and block and character
devices.  Those are all files, too-just not *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 -f and -T
file tests.

   To open a directory, you should use the opendir function, then process
it with readdir, carefully restoring the directory name if necessary:

     opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
     while (defined($file = readdir(DIR))) {
         # do something with "$dirname/$file"
     }
     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.

     @ARGV = qw(.) unless @ARGV;
     use File::Find;
     find sub { print $File::Find::name, -d && '/', "\n" }, @ARGV;

   This finds all bogus symbolic links beneath a particular directory:

     find sub { print "$File::Find::name\n" if -l && !-e }, $dir;

   As you see, with symbolic links, you can just pretend that it is what
it points to.  Or, if you want to know *what* it points to, then readlink
is called for:

     if (-l $file) {
         if (defined($whither = readlink($file))) {
             print "$file points to $whither\n";
         } else {
             print "$file points nowhere: $!\n";
         }
     }

   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 `"Named Pipes"', *Note Perlipc:
perlipc,.  Unix-domain sockets are rather different beasts as well; they're
described in `"Unix-Domain TCP Clients and Servers"', *Note Perlipc:
perlipc,.

   When it comes to opening devices, it can be easy and it can 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
described in `"How do I read and write the serial port?"', *Note Perlfaq8:
perlfaq8, It's often enough to open them carefully:

     sysopen(TTYIN, "/dev/ttyS1", O_RDWR | O_NDELAY | O_NOCTTY)
     		# (O_NOCTTY no longer needed on POSIX systems)
         or die "can't open /dev/ttyS1: $!";
     open(TTYOUT, "+>&TTYIN")
         or die "can't dup TTYIN: $!";

     $ofh = select(TTYOUT); $| = 1; select($ofh);

     print TTYOUT "+++at\015";
     $answer = <TTYIN>;

   With descriptors that you haven't opened using sysopen, such as a
socket, you can set them to be non-blocking using fcntl:

     use Fcntl;
     fcntl(Connection, F_SETFL, O_NONBLOCK)
         or die "can't set non blocking: $!";

   Rather than losing yourself in a morass of twisting, turning ioctls,
all dissimilar, if you're going to manipulate ttys, it's best to make
calls out to the stty(1) program if you have it, or else use the portable
POSIX interface.  To figure this all out, you'll need to read the
termios(3) manpage, which describes the POSIX interface to tty devices,
and then *Note POSIX: (pm.info)POSIX,, which describes Perl's interface to
POSIX.  There are also some high-level modules on CPAN that can help you
with these games.  Check out Term::ReadKey and Term::ReadLine.

   What else can you open?  To open a connection using sockets, you won't
use one of Perl's two open functions.  See `"Sockets: Client', *Note
Perlipc: perlipc, for that.  Here's an example.  Once you have it, you can
use FH as a bidirectional filehandle.

     use IO::Socket;
     local *FH = IO::Socket::INET->new("www.perl.com:80");

   For opening up a URL, the LWP modules from CPAN are just what the
doctor ordered.  There's no filehandle interface, but it's still easy to
get the contents of a document:

     use LWP::Simple;
     $doc = get('http://www.linpro.no/lwp/');

Binary Files
------------

   On certain legacy systems with what could charitably be called
terminally convoluted (some would say broken) I/O models, a file isn't a
file-at least, not with respect to the C standard I/O library.  On these
old systems whose libraries (but not kernels) distinguish between text and
binary streams, to get files to behave properly you'll have to bend over
backwards to avoid nasty problems.  On such infelicitous systems, sockets
and pipes are already opened in binary mode, and there is currently no way
to turn that off.  With files, you have more options.

   Another option is to use the binmode function on the appropriate
handles before doing regular I/O on them:

     binmode(STDIN);
     binmode(STDOUT);
     while (<STDIN>) { print }

   Passing 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 binmodeing on the handle.

     sysopen(BINDAT, "records.data", O_RDWR | O_BINARY)
         || die "can't open records.data: $!";

   Now you can use read and print on that handle without worrying about
the system non-standard 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.

   On systems with exotic I/O systems, it turns out that, astonishingly
enough, even unbuffered I/O using sysread and syswrite might do sneaky
data mutilation behind your back.

     while (sysread(WHENCE, $buf, 1024)) {
         syswrite(WHITHER, $buf, length($buf));
     }

   Depending on the vicissitudes of your runtime system, even these calls
may need binmode or `O_BINARY' first.  Systems known to be free of such
difficulties include Unix, the Mac OS, Plan9, and Inferno.

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 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 `-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.

   Perl's most portable locking interface is via the 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 it all works,
so you should learn how flock is implemented on your system's port of Perl.

   File locking *does not* lock out another process that would like to do
I/O.  A file lock only locks out others trying to get a lock, not
processes trying to do I/O.  Because locks are advisory, if one process
uses locking and another doesn't, all bets are off.

   By default, the flock call will block until a lock is granted.  A
request for a shared lock will be granted as soon as there is no exclusive
locker.  A request for a exclusive lock will be granted as soon as there
is no locker of any kind.  Locks are on file descriptors, not file names.
You can't lock a file until you open it, and you can't hold on to a lock
once the file has been closed.

   Here's how to get a blocking shared lock on a file, typically used for
reading:

     use 5.004;
     use Fcntl qw(:DEFAULT :flock);
     open(FH, "< filename")  or die "can't open filename: $!";
     flock(FH, LOCK_SH) 	    or die "can't lock filename: $!";
     # now read from FH

   You can get a non-blocking lock by using `LOCK_NB'.

     flock(FH, LOCK_SH | LOCK_NB)
         or die "can't lock filename: $!";

   This can be useful for producing more user-friendly behaviour by warning
if you're going to be blocking:

     use 5.004;
     use Fcntl qw(:DEFAULT :flock);
     open(FH, "< filename")  or die "can't open filename: $!";
     unless (flock(FH, LOCK_SH | LOCK_NB)) {
     	$| = 1;
     	print "Waiting for lock...";
     	flock(FH, LOCK_SH)  or die "can't lock filename: $!";
     	print "got it.\n"
     }
     # now read from FH

   To get an exclusive lock, typically used for writing, you have to be
careful.  We sysopen the file so it can be locked before it gets emptied.
You can get a nonblocking version using `LOCK_EX | LOCK_NB'.

     use 5.004;
     use Fcntl qw(:DEFAULT :flock);
     sysopen(FH, "filename", O_WRONLY | O_CREAT)
         or die "can't open filename: $!";
     flock(FH, LOCK_EX)
         or die "can't lock filename: $!";
     truncate(FH, 0)
         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:

     use Fcntl qw(:DEFAULT :flock);

     sysopen(FH, "numfile", O_RDWR | O_CREAT)
         or die "can't open numfile: $!";
     # autoflush FH
     $ofh = select(FH); $| = 1; select ($ofh);
     flock(FH, LOCK_EX)
         or die "can't write-lock numfile: $!";

     $num = <FH> || 0;
     seek(FH, 0, 0)
         or die "can't rewind numfile : $!";
     print FH $num+1, "\n"
         or die "can't write numfile: $!";

     truncate(FH, tell(FH))
         or die "can't truncate numfile: $!";
     close(FH)
         or die "can't close numfile: $!";

SEE ALSO
========

   The open and sysopen function in perlfunc(1); the standard open(2),
dup(2), fopen(3), and fdopen(3) manpages; the POSIX documentation.

AUTHOR and COPYRIGHT
====================

   Copyright 1998 Tom Christiansen.

   When included as part of the Standard Version of Perl, or as part of
its complete documentation whether printed or otherwise, this work may be
distributed only under the terms of Perl's Artistic License.  Any
distribution of this file or derivatives thereof outside of that package
require that special arrangements be made with copyright holder.

   Irrespective of its distribution, all code examples in these files are
hereby placed into the public domain.  You are permitted and encouraged to
use this code in your own programs for fun or for profit as you see fit.
A simple comment in the code giving credit would be courteous but is not
required.

HISTORY
=======

   First release: Sat Jan  9 08:09:11 MST 1999


File: perl.info,  Node: perlos2,  Next: perlos390,  Prev: perlmachten,  Up: Top

Perl under OS/2, DOS, Win0.3*, Win0.95 and WinNT.
*************************************************

NAME
====

   perlos2 - Perl under OS/2, DOS, Win0.3*, Win0.95 and WinNT.

SYNOPSIS
========

   One can read this document in the following formats:

     man perlos2
     view perl perlos2
     explorer perlos2.html
     info perlos2

   to list some (not all may be available simultaneously), or it may be
read *as is*: either as `README.os2', or `pod/perlos2.pod'.

   To read the `.INF' version of documentation (*very* recommended)
outside of OS/2, one needs an IBM's reader (may be available on IBM ftp
sites (?)  (URL anyone?)) or shipped with PC DOS 7.0 and IBM's Visual Age
C++ 3.5.

   A copy of a Win* viewer is contained in the "Just add OS/2 Warp" package

     ftp://ftp.software.ibm.com/ps/products/os2/tools/jaow/jaow.zip

   in `?:\JUST_ADD\view.exe'. This gives one an access to EMX's `.INF'
docs as well (text form is available in `/emx/doc' in EMX's distribution).

   Note that if you have `lynx.exe' installed, you can follow WWW links
from this document in `.INF' format. If you have EMX docs installed
correctly, you can follow library links (you need to have `view emxbook'
working by setting `EMXBOOK' environment variable as it is described in
EMX docs).

Target
------

   The target is to make OS/2 the best supported platform for
using/building/developing Perl and *Perl applications*, as well as make
Perl the best language to use under OS/2. The secondary target is to try
to make this work under DOS and Win* as well (but not *too* hard).

   The current state is quite close to this target. Known limitations:

   * Some *nix programs use fork() a lot, but currently fork() is not
     supported after useing dynamically loaded extensions.

   * You need a separate perl executable `perl__.exe' (see `perl__.exe' in
     this node) to use PM code in your application (like the forthcoming
     Perl/Tk).

   * There is no simple way to access WPS objects. The only way I know is
     via `OS2::REXX' extension (see `OS2::REXX' in this node), and we do
     not have access to convenience methods of Object-REXX. (Is it
     possible at all? I know of no Object-REXX API.)

   Please keep this list up-to-date by informing me about other items.

Other OSes
----------

   Since OS/2 port of perl uses a remarkable EMX environment, it can run
(and build extensions, and - possibly - be build itself) under any
environment which can run EMX. The current list is DOS, DOS-inside-OS/2,
Win0.3*, Win0.95 and WinNT. Out of many perl flavors, only one works, see
`"perl_.exe"' in this node.

   Note that not all features of Perl are available under these
environments. This depends on the features the *extender* - most probably
RSX - decided to implement.

   Cf. `Prerequisites' in this node.

Prerequisites
-------------

EMX
     EMX runtime is required (may be substituted by RSX). Note that it is
     possible to make `perl_.exe' to run under DOS without any external
     support by binding `emx.exe'/`rsx.exe' to it, see `emxbind' in this
     node. Note that under DOS for best results one should use RSX
     runtime, which has much more functions working (like fork, `popen'
     and so on). In fact RSX is required if there is no VCPI present. Note
     the RSX requires DPMI.

     Only the latest runtime is supported, currently `0.9c'. Perl may run
     under earlier versions of EMX, but this is not tested.

     One can get different parts of EMX from, say

          ftp://ftp.cdrom.com/pub/os2/emx09c/
          ftp://hobbes.nmsu.edu/os2/unix/emx09c/

     The runtime component should have the name `emxrt.zip'.

     NOTE. It is enough to have `emx.exe'/`rsx.exe' on your path. One does
     not need to specify them explicitly (though this

          emx perl_.exe -de 0

     will work as well.)

RSX
     To run Perl on DPMI platforms one needs RSX runtime. This is needed
     under DOS-inside-OS/2, Win0.3*, Win0.95 and WinNT (see `"Other OSes"'
     in this node). RSX would not work with VCPI only, as EMX would, it
     requires DMPI.

     Having RSX and the latest `sh.exe' one gets a fully functional
     **nix*-ish environment under DOS, say, fork, ```' and pipe-open work.
     In fact, MakeMaker works (for static build), so one can have Perl
     development environment under DOS.

     One can get RSX from, say

          ftp://ftp.cdrom.com/pub/os2/emx09c/contrib
          ftp://ftp.uni-bielefeld.de/pub/systems/msdos/misc
          ftp://ftp.leo.org/pub/comp/os/os2/leo/devtools/emx+gcc/contrib

     Contact the author on `rainer@mathematik.uni-bielefeld.de'.

     The latest `sh.exe' with DOS hooks is available at

          ftp://ftp.math.ohio-state.edu/pub/users/ilya/os2/sh_dos.zip

HPFS
     Perl does not care about file systems, but to install the whole perl
     library intact one needs a file system which supports long file names.

     Note that if you do not plan to build the perl itself, it may be
     possible to fool EMX to truncate file names. This is not supported,
     read EMX docs to see how to do it.

pdksh
     To start external programs with complicated command lines (like with
     pipes in between, and/or quoting of arguments), Perl uses an external
     shell. With EMX port such shell should be named <sh.exe>, and located
     either in the wired-in-during-compile locations (usually `F:/bin'),
     or in configurable location (see `"PERL_SH_DIR"' in this node).

     For best results use EMX pdksh. The soon-to-be-available standard
     binary (5.2.12?) runs under DOS (with `RSX' in this node) as well,
     meanwhile use the binary from

          ftp://ftp.math.ohio-state.edu/pub/users/ilya/os2/sh_dos.zip

Starting Perl programs under OS/2 (and DOS and...)
--------------------------------------------------

   Start your Perl program `foo.pl' with arguments `arg1 arg2 arg3' the
same way as on any other platform, by

     perl foo.pl arg1 arg2 arg3

   If you want to specify perl options `-my_opts' to the perl itself (as
opposed to to your program), use

     perl -my_opts foo.pl arg1 arg2 arg3

   Alternately, if you use OS/2-ish shell, like CMD or 4os2, put the
following at the start of your perl script:

     extproc perl -S -my_opts

   rename your program to `foo.cmd', and start it by typing

     foo arg1 arg2 arg3

   Note that because of stupid OS/2 limitations the full path of the perl
script is not available when you use `extproc', thus you are forced to use
-S perl switch, and your script should be on path. As a plus side, if you
know a full path to your script, you may still start it with

     perl ../../blah/foo.cmd arg1 arg2 arg3

   (note that the argument `-my_opts' is taken care of by the `extproc'
line in your script, see ``extproc' in this node on the first line').

   To understand what the above magic does, read perl docs about -S switch
- see *Note Perlrun: perlrun,, and cmdref about `extproc':

     view perl perlrun
     man perlrun
     view cmdref extproc
     help extproc

   or whatever method you prefer.

   There are also endless possibilities to use *executable extensions* of
4os2, associations of WPS and so on... However, if you use *nixish shell
(like `sh.exe' supplied in the binary distribution), you need to follow
the syntax specified in `"Switches"', *Note Perlrun: perlrun,.

   Note that -S switch enables a search with additional extensions `.cmd',
`.btm', `.bat', `.pl' as well.

Starting OS/2 (and DOS) programs under Perl
-------------------------------------------

   This is what system() (see `system', *Note Perlfunc: perlfunc,), ```'
(see `"I', *Note Perlop: perlop,), and *open pipe* (see `open', *Note
Perlfunc: perlfunc,) are for. (Avoid exec() (see `exec', *Note Perlfunc:
perlfunc,) unless you know what you do).

   Note however that to use some of these operators you need to have a
sh-syntax shell installed (see `"Pdksh"' in this node, `"Frequently asked
questions"' in this node), and perl should be able to find it (see
`"PERL_SH_DIR"' in this node).

   The cases when the shell is used are:

  1. One-argument system() (see `system', *Note Perlfunc: perlfunc,),
     exec() (see `exec', *Note Perlfunc: perlfunc,) with redirection or
     shell meta-characters;

  2. Pipe-open (see `open', *Note Perlfunc: perlfunc,) with the command
     which contains redirection or shell meta-characters;

  3. Backticks ```' (see `"I', *Note Perlop: perlop,) with the command
     which contains redirection or shell meta-characters;

  4. If the executable called by system()/exec()/pipe-open()/```' is a
     script with the "magic" #! line or `extproc' line which specifies
     shell;

  5. If the executable called by system()/exec()/pipe-open()/```' is a
     script without "magic" line, and `$ENV{EXECSHELL}' is set to shell;

  6. If the executable called by system()/exec()/pipe-open()/```' is not
     found;

  7. For globbing (see `glob', *Note Perlfunc: perlfunc,, `"I', *Note
     Perlop: perlop,).

        For the sake of speed for a common case, in the above algorithms
backslashes in the command name are not considered as shell metacharacters.

   Perl starts scripts which begin with cookies `extproc' or #! directly,
without an intervention of shell.  Perl uses the same algorithm to find
the executable as pdksh: if the path on #! line does not work, and
contains /, then the executable is searched in . and on PATH.  To find
arguments for these scripts Perl uses a different algorithm than pdksh: up
to 3 arguments are recognized, and trailing whitespace is stripped.

   If a script does not contain such a cooky, then to avoid calling
`sh.exe', Perl uses the same algorithm as pdksh: if `$ENV{EXECSHELL}' is
set, the script is given as the first argument to this command, if not
set, then `$ENV{COMSPEC} /c' is used (or a hardwired guess if
`$ENV{COMSPEC}' is not set).

   If starting scripts directly, Perl will use exactly the same algorithm
as for the search of script given by -S command-line option: it will look
in the current directory, then on components of `$ENV{PATH}' using the
following order of appended extensions: no extension, `.cmd', `.btm',
`.bat', `.pl'.

   Note that Perl will start to look for scripts only if OS/2 cannot start
the specified application, thus `system 'blah'' will not look for a script
if there is an executable file `blah.exe' *anywhere* on PATH.

   Note also that executable files on OS/2 can have an arbitrary extension,
but `.exe' will be automatically appended if no dot is present in the name.
The workaround as as simple as that:  since `blah.' and `blah' denote the
same file, to start an executable residing in file `n:/bin/blah' (no
extension) give an argument `n:/bin/blah.' to system().

   The last note is that currently it is not straightforward to start PM
programs from VIO (=text-mode) Perl process and visa versa.  Either ensure
that shell will be used, as in `system 'cmd /c epm'', or start it using
optional arguments to system() documented in `OS2::Process' module.  This
is considered a bug and should be fixed soon.

Frequently asked questions
==========================

I cannot run external programs
------------------------------


     Did you run your programs with -w switch? See `Starting OS' in this
     node.


     Do you try to run internal shell commands, like ``copy a b`'
     (internal for `cmd.exe'), or ``glob a*b`' (internal for ksh)? You
     need to specify your shell explicitly, like ``cmd /c copy a b`',
     since Perl cannot deduce which commands are internal to your shell.

I cannot embed perl into my program, or use `perl.dll' from my program.
-----------------------------------------------------------------------

Is your program EMX-compiled with `-Zmt -Zcrtdll'?
     If not, you need to build a stand-alone DLL for perl. Contact me, I
     did it once. Sockets would not work, as a lot of other stuff.

Did you use *Note ExtUtils/Embed: (pm.info)ExtUtils/Embed,?
     I had reports it does not work. Somebody would need to fix it.

```' and pipe-open do not work under DOS.
-----------------------------------------

   This may a variant of just `"I cannot run external programs"' in this
node, or a deeper problem. Basically: you *need* RSX (see
`"Prerequisites"' in this node) for these commands to work, and you may
need a port of `sh.exe' which understands command arguments. One of such
ports is listed in `"Prerequisites"' in this node under RSX. Do not forget
to set variable ``"PERL_SH_DIR"' in this node' as well.

   DPMI is required for RSX.

Cannot start `find.exe "pattern" file'
--------------------------------------

   Use one of

     system 'cmd', '/c', 'find "pattern" file';
     `cmd /c 'find "pattern" file'`

   This would start `find.exe' via `cmd.exe' via `sh.exe' via `perl.exe',
but this is a price to pay if you want to use non-conforming program. In
fact `find.exe' cannot be started at all using C library API only.
Otherwise the following command-lines were equivalent:

     find "pattern" file
     find pattern file

INSTALLATION
============

Automatic binary installation
-----------------------------

   The most convenient way of installing perl is via perl installer
`install.exe'. Just follow the instructions, and 99% of the installation
blues would go away.

   Note however, that you need to have `unzip.exe' on your path, and EMX
environment running. The latter means that if you just installed EMX, and
made all the needed changes to `Config.sys', you may need to reboot in
between. Check EMX runtime by running

     emxrev

   A folder is created on your desktop which contains some useful objects.

   *Things not taken care of by automatic binary installation:*

PERL_BADLANG
     may be needed if you change your codepage after perl installation,
     and the new value is not supported by EMX. See `"PERL_BADLANG"' in
     this node.

`PERL_BADFREE'
     see `"PERL_BADFREE"' in this node.

Config.pm
     This file resides somewhere deep in the location you installed your
     perl library, find it out by

          perl -MConfig -le "print $INC{'Config.pm'}"

     While most important values in this file *are* updated by the binary
     installer, some of them may need to be hand-edited. I know no such
     data, please keep me informed if you find one.

   NOTE. Because of a typo the binary installer of 5.00305 would install a
variable `PERL_SHPATH' into `Config.sys'. Please remove this variable and
put ``PERL_SH_DIR' in this node' instead.

Manual binary installation
--------------------------

   As of version 5.00305, OS/2 perl binary distribution comes split into
11 components. Unfortunately, to enable configurable binary installation,
the file paths in the zip files are not absolute, but relative to some
directory.

   Note that the extraction with the stored paths is still necessary
(default with unzip, specify -d to pkunzip). However, you need to know
where to extract the files. You need also to manually change entries in
`Config.sys' to reflect where did you put the files. Note that if you have
some primitive unzipper (like pkunzip), you may get a lot of
warnings/errors during unzipping. Upgrade to `(w)unzip'.

   Below is the sample of what to do to reproduce the configuration on my
machine:

Perl VIO and PM executables (dynamically linked)
          unzip perl_exc.zip *.exe *.ico -d f:/emx.add/bin
          unzip perl_exc.zip *.dll -d f:/emx.add/dll

     (have the directories with `*.exe' on PATH, and `*.dll' on LIBPATH);

Perl_ VIO executable (statically linked)
          unzip perl_aou.zip -d f:/emx.add/bin

     (have the directory on PATH);

Executables for Perl utilities
          unzip perl_utl.zip -d f:/emx.add/bin

     (have the directory on PATH);

Main Perl library
          unzip perl_mlb.zip -d f:/perllib/lib

     If this directory is preserved, you do not need to change anything.
     However, for perl to find it if it is changed, you need to `set
     PERLLIB_PREFIX' in `Config.sys', see `"PERLLIB_PREFIX"' in this node.

Additional Perl modules
          unzip perl_ste.zip -d f:/perllib/lib/site_perl

     If you do not change this directory, do nothing. Otherwise put this
     directory and subdirectory `./os2' in PERLLIB or PERL5LIB variable.
     Do not use PERL5LIB unless you have it set already. See
     `"ENVIRONMENT"', *Note Perl: perl,.

Tools to compile Perl modules
          unzip perl_blb.zip -d f:/perllib/lib

     If this directory is preserved, you do not need to change anything.
     However, for perl to find it if it is changed, you need to `set
     PERLLIB_PREFIX' in `Config.sys', see `"PERLLIB_PREFIX"' in this node.

Manpages for Perl and utilities
          unzip perl_man.zip -d f:/perllib/man

     This directory should better be on `MANPATH'. You need to have a
     working man to access these files.

Manpages for Perl modules
          unzip perl_mam.zip -d f:/perllib/man

     This directory should better be on `MANPATH'. You need to have a
     working man to access these files.

Source for Perl documentation
          unzip perl_pod.zip -d f:/perllib/lib

     This is used by by perldoc program (see `perldoc' in this node), and
     may be used to generate HTML documentation usable by WWW browsers, and
     documentation in zillions of other formats: info, `LaTeX', `Acrobat',
     `FrameMaker' and so on.

Perl manual in `.INF' format
          unzip perl_inf.zip -d d:/os2/book

     This directory should better be on `BOOKSHELF'.

Pdksh
          unzip perl_sh.zip -d f:/bin

     This is used by perl to run external commands which explicitly
     require shell, like the commands using *redirection* and *shell
     metacharacters*. It is also used instead of explicit `/bin/sh'.

     Set PERL_SH_DIR (see `"PERL_SH_DIR"' in this node) if you move
     `sh.exe' from the above location.

     *Note.* It may be possible to use some other sh-compatible shell
     (*not tested*).

   After you installed the components you needed and updated the
`Config.sys' correspondingly, you need to hand-edit Config.pm. This file
resides somewhere deep in the location you installed your perl library,
find it out by

     perl -MConfig -le "print $INC{'Config.pm'}"

   You need to correct all the entries which look like file paths (they
currently start with `f:/').

Warning
-------

   The automatic and manual perl installation leave precompiled paths
inside perl executables. While these paths are overwriteable (see
`"PERLLIB_PREFIX"' in this node, `"PERL_SH_DIR"' in this node), one may
get better results by binary editing of paths inside the executables/DLLs.

Accessing documentation
=======================

   Depending on how you built/installed perl you may have (otherwise
identical) Perl documentation in the following formats:

OS/2 `.INF' file
----------------

   Most probably the most convenient form. Under OS/2 view it as

     view perl
     view perl perlfunc
     view perl less
     view perl ExtUtils::MakeMaker

   (currently the last two may hit a wrong location, but this may improve
soon). Under Win* see `"SYNOPSIS"' in this node.

   If you want to build the docs yourself, and have *OS/2 toolkit*, run

     pod2ipf > perl.ipf

   in `/perllib/lib/pod' directory, then

     ipfc /inf perl.ipf

   (Expect a lot of errors during the both steps.) Now move it on your
BOOKSHELF path.

Plain text
----------

   If you have perl documentation in the source form, perl utilities
installed, and GNU groff installed, you may use

     perldoc perlfunc
     perldoc less
     perldoc ExtUtils::MakeMaker

   to access the perl documentation in the text form (note that you may get
better results using perl manpages).

   Alternately, try running pod2text on `.pod' files.

Manpages
--------

   If you have man installed on your system, and you installed perl
manpages, use something like this:

     man perlfunc
     man 3 less
     man ExtUtils.MakeMaker

   to access documentation for different components of Perl. Start with

     man perl

   Note that dot (.) is used as a package separator for documentation for
packages, and as usual, sometimes you need to give the section - 3 above -
to avoid shadowing by the *less(1) manpage*.

   Make sure that the directory above the directory with manpages is on
our `MANPATH', like this

     set MANPATH=c:/man;f:/perllib/man

HTML
----

   If you have some WWW browser available, installed the Perl
documentation in the source form, and Perl utilities, you can build HTML
docs. Cd to directory with `.pod' files, and do like this

     cd f:/perllib/lib/pod
     pod2html

   After this you can direct your browser the file `perl.html' in this
directory, and go ahead with reading docs, like this:

     explore file:///f:/perllib/lib/pod/perl.html

   Alternatively you may be able to get these docs prebuilt from CPAN.

GNU info files
--------------

   Users of Emacs would appreciate it very much, especially with `CPerl'
mode loaded. You need to get latest `pod2info' from CPAN, or, alternately,
prebuilt info pages.

`.PDF' files
------------

   for `Acrobat' are available on CPAN (for slightly old version of perl).

`LaTeX' docs
------------

   can be constructed using `pod2latex'.

BUILD
=====

   Here we discuss how to build Perl under OS/2. There is an alternative
(but maybe older) view on `http:' in this node.

Prerequisites
-------------

   You need to have the latest EMX development environment, the full GNU
tool suite (gawk renamed to awk, and GNU `find.exe' earlier on path than
the OS/2 `find.exe', same with `sort.exe', to check use

     find --version
     sort --version

   ). You need the latest version of pdksh installed as `sh.exe'.

   Check that you have *BSD* libraries and headers installed, and -
optionally - Berkeley DB headers and libraries, and crypt.

   Possible locations to get this from are

     ftp://hobbes.nmsu.edu/os2/unix/
     ftp://ftp.cdrom.com/pub/os2/unix/
     ftp://ftp.cdrom.com/pub/os2/dev32/
     ftp://ftp.cdrom.com/pub/os2/emx09c/

   It is reported that the following archives contain enough utils to
build perl: gnufutil.zip, gnusutil.zip, gnututil.zip, gnused.zip,
gnupatch.zip, gnuawk.zip, gnumake.zip and ksh527rt.zip.  Note that all
these utilities are known to be available from LEO:

     ftp://ftp.leo.org/pub/comp/os/os2/leo/gnu

   Make sure that no copies or perl are currently running.  Later steps of
the build may fail since an older version of perl.dll loaded into memory
may be found.

   Also make sure that you have `/tmp' directory on the current drive, and
. directory in your `LIBPATH'. One may try to correct the latter condition
by

     set BEGINLIBPATH .

   if you use something like `CMD.EXE' or latest versions of `4os2.exe'.

   Make sure your gcc is good for `-Zomf' linking: run `omflibs' script in
`/emx/lib' directory.

   Check that you have link386 installed. It comes standard with OS/2, but
may be not installed due to customization. If typing

     link386

   shows you do not have it, do *Selective install*, and choose `Link
object modules' in *Optional system utilities/More*. If you get into
link386, press `Ctrl-C'.

Getting perl source
-------------------

   You need to fetch the latest perl source (including developers
releases). With some probability it is located in

     http://www.perl.com/CPAN/src/5.0
     http://www.perl.com/CPAN/src/5.0/unsupported

   If not, you may need to dig in the indices to find it in the directory
of the current maintainer.

   Quick cycle of developers release may break the OS/2 build time to
time, looking into

     http://www.perl.com/CPAN/ports/os2/ilyaz/

   may indicate the latest release which was publicly released by the
maintainer. Note that the release may include some additional patches to
apply to the current source of perl.

   Extract it like this

     tar vzxf perl5.00409.tar.gz

   You may see a message about errors while extracting Configure. This is
because there is a conflict with a similarly-named file configure.

   Change to the directory of extraction.

Application of the patches
--------------------------

   You need to apply the patches in `./os2/diff.*' like this:

     gnupatch -p0 < os2\diff.configure

   You may also need to apply the patches supplied with the binary
distribution of perl.

   Note also that the `db.lib' and `db.a' from the EMX distribution are
not suitable for multi-threaded compile (note that currently perl is not
multithread-safe, but is compiled as multithreaded for compatibility with
XFree86-OS/2). Get a corrected one from

     ftp://ftp.math.ohio-state.edu/pub/users/ilya/os2/db_mt.zip

   To make -p filetest work, one may also need to apply the following patch
to EMX headers:

     --- /emx/include/sys/stat.h.orig	Thu May 23 13:48:16 1996
     +++ /emx/include/sys/stat.h	Sun Jul 12 14:11:32 1998
     @@ -53,7 +53,7 @@ struct stat
      #endif

     #if !defined (S_IFMT)
       -#define S_IFMT   0160000  /* Mask for file type */
       +#define S_IFMT   0170000  /* Mask for file type */
     #define S_IFIFO  0010000  /* Pipe */
     #define S_IFCHR  0020000  /* Character device */
     #define S_IFDIR  0040000  /* Directory */

Hand-editing
------------

   You may look into the file `./hints/os2.sh' and correct anything wrong
you find there. I do not expect it is needed anywhere.

Making
------

     sh Configure -des -D prefix=f:/perllib

   prefix means: where to install the resulting perl library. Giving
correct prefix you may avoid the need to specify `PERLLIB_PREFIX', see
`"PERLLIB_PREFIX"' in this node.

   *Ignore the message about missing `ln', and about -c option to tr*. In
fact if you can trace where the latter spurious warning comes from, please
inform me.

   Now

     make

   At some moment the built may die, reporting a *version mismatch* or
*unable to run `perl'*. This means that most of the build has been
finished, and it is the time to move the constructed `perl.dll' to some
*absolute* location in LIBPATH. After this is done the build should finish
without a lot of fuss. *One can avoid the interruption if one has the
correct prebuilt version of `perl.dll' on LIBPATH, but probably this is
not needed anymore, since `miniperl.exe' is linked statically now.*

   Warnings which are safe to ignore: *mkfifo() redefined* inside
`POSIX.c'.

Testing
-------

   If you haven't yet moved perl.dll onto LIBPATH, do it now
(alternatively, if you have a previous perl installation you'd rather not
disrupt until this one is installed, copy perl.dll to the t directory).

   Now run

     make test

   All tests should succeed (with some of them skipped).  Note that on one
of the systems I see intermittent failures of `io/pipe.t' subtest 9.  Any
help to track what happens with this test is appreciated.

   Some tests may generate extra messages similar to

A lot of `bad free'
     in database tests related to Berkeley DB. This is a confirmed bug of
     DB. You may disable this warnings, see `"PERL_BADFREE"' in this node.

     There is not much we can do with it (but apparently it does not cause
     any real error with data).

Process terminated by SIGTERM/SIGINT
     This is a standard message issued by OS/2 applications. *nix
     applications die in silence. It is considered a feature. One can
     easily disable this by appropriate sighandlers.

     However the test engine bleeds these message to screen in unexpected
     moments. Two messages of this kind should be present during testing.

   Two `lib/io_*' tests may generate popups (system error `SYS3175'), but
should succeed anyway.  This is due to a bug of EMX related to fork()ing
with dynamically loaded libraries.

   I submitted a patch to EMX which makes it possible to fork() with EMX
dynamic libraries loaded, which makes `lib/io*' tests pass without
skipping offended tests. This means that soon the number of skipped tests
may decrease yet more.

   To get finer test reports, call

     perl t/harness

   The report with `io/pipe.t' failing may look like this:

     Failed Test  Status Wstat Total Fail  Failed  List of failed
     ------------------------------------------------------------
     io/pipe.t                    12    1   8.33%  9
     7 tests skipped, plus 56 subtests skipped.
     Failed 1/195 test scripts, 99.49% okay. 1/6542 subtests failed, 99.98% okay.

   The reasons for most important skipped tests are:

`op/fs.t'
       1. Checks atime and mtime of stat() - unfortunately, HPFS provides
          only 2sec time granularity (for compatibility with FAT?).

       2. Checks `truncate()' on a filehandle just opened for write - I do
          not know why this should or should not work.


`lib/io_pipe.t'
     Checks IO::Pipe module. Some feature of EMX - test fork()s with
     dynamic extension loaded - unsupported now.

`lib/io_sock.t'
     Checks IO::Socket module. Some feature of EMX - test fork()s with
     dynamic extension loaded - unsupported now.

`op/stat.t'
     Checks stat(). Tests:

       1. Checks atime and mtime of stat() - unfortunately, HPFS provides
          only 2sec time granularity (for compatibility with FAT?).


`lib/io_udp.t'
     It never terminates, apparently some bug in storing the last socket
     from which we obtained a message.

Installing the built perl
-------------------------

   If you haven't yet moved perl.dll onto LIBPATH, do it now.

   Run

     make install

   It would put the generated files into needed locations. Manually put
`perl.exe', `perl__.exe' and `perl___.exe' to a location on your PATH,
`perl.dll' to a location on your LIBPATH.

   Run

     make cmdscripts INSTALLCMDDIR=d:/ir/on/path

   to convert perl utilities to `.cmd' files and put them on PATH. You
need to put `.EXE'-utilities on path manually. They are installed in
`$prefix/bin', here `$prefix' is what you gave to Configure, see `Making'
in this node.

`a.out'-style build
-------------------

   Proceed as above, but make `perl_.exe' (see `"perl_.exe"' in this node)
by

     make perl_

   test and install by

     make aout_test
     make aout_install

   Manually put `perl_.exe' to a location on your PATH.

   Since `perl_' has the extensions prebuilt, it does not suffer from the
*dynamic extensions + fork()* syndrome, thus the failing tests look like

     Failed Test  Status Wstat Total Fail  Failed  List of failed
     ---------------------------------------------------------------
     io/fs.t                      26   11  42.31%  2-5, 7-11, 18, 25
     op/stat.t                    56    5   8.93%  3-4, 20, 35, 39
     Failed 2/118 test scripts, 98.31% okay. 16/2445 subtests failed, 99.35% okay.

   *Note.* The build process for `perl_' *does not know* about all the
dependencies, so you should make sure that anything is up-to-date, say, by
doing

     make perl.dll

   first.

Build FAQ
=========

Some / became \ in pdksh.
-------------------------

   You have a very old pdksh. See `Prerequisites' in this node.

`'errno'' - unresolved external
-------------------------------

   You do not have MT-safe `db.lib'. See `Prerequisites' in this node.

Problems with tr or sed
-----------------------

   reported with very old version of tr and sed.

Some problem (forget which ;-)
------------------------------

   You have an older version of `perl.dll' on your LIBPATH, which broke
the build of extensions.

Library ... not found
---------------------

   You did not run `omflibs'. See `Prerequisites' in this node.

Segfault in make
----------------

   You use an old version of GNU make. See `Prerequisites' in this node.

Specific (mis)features of OS/2 port
===================================

setpriority, getpriority
------------------------

   Note that these functions are compatible with *nix, not with the older
ports of '94 - 95. The priorities are absolute, go from 32 to -95, lower
is quicker. 0 is the default priority.

`system()'
----------

   Multi-argument form of `system()' allows an additional numeric
argument. The meaning of this argument is described in *Note OS2/Process:
(pm.info)OS2/Process,.

`extproc' on the first line
---------------------------

   If the first chars of a script are `"extproc "', this line is treated
as #!-line, thus all the switches on this line are processed (twice if
script was started via cmd.exe).

Additional modules:
-------------------

   *Note OS2/Process: (pm.info)OS2/Process,, `OS2::REXX' in this node,
`OS2::PrfDB' in this node, `OS2::ExtAttr' in this node. These modules
provide access to additional numeric argument for system and to the list
of the running processes, to DLLs having functions with REXX signature and
to REXX runtime, to OS/2 databases in the `.INI' format, and to Extended
Attributes.

   Two additional extensions by Andreas Kaiser, `OS2::UPM', and
`OS2::FTP', are included into my ftp directory, mirrored on CPAN.

Prebuilt methods:
-----------------

`File::Copy::syscopy'
     used by `File::Copy::copy', see *Note File/Copy: (pm.info)File/Copy,.

`DynaLoader::mod2fname'
     used by DynaLoader for DLL name mangling.

`Cwd::current_drive()'
     Self explanatory.

`Cwd::sys_chdir(name)'
     leaves drive as it is.

`Cwd::change_drive(name)'
`Cwd::sys_is_absolute(name)'
     means has drive letter and is_rooted.

`Cwd::sys_is_rooted(name)'
     means has leading `[/\\]' (maybe after a drive-letter:).

`Cwd::sys_is_relative(name)'
     means changes with current dir.

`Cwd::sys_cwd(name)'
     Interface to cwd from EMX. Used by `Cwd::cwd'.

`Cwd::sys_abspath(name, dir)'
     Really really odious function to implement. Returns absolute name of
     file which would have name if CWD were dir.  Dir defaults to the
     current dir.

`Cwd::extLibpath([type])'
     Get current value of extended library search path. If type is present
     and *true*, works with END_LIBPATH, otherwise with `BEGIN_LIBPATH'.

`Cwd::extLibpath_set( path [, type ] )'
     Set current value of extended library search path. If type is present
     and *true*, works with END_LIBPATH, otherwise with `BEGIN_LIBPATH'.

   (Note that some of these may be moved to different libraries -
eventually).

Misfeatures
-----------


     Since `flock(3)' in this node is present in EMX, but is not
     functional, it is emulated by perl.  To disable the emulations, set
     environment variable `USE_PERL_FLOCK=0'.


     Here is the list of things which may be "broken" on EMX (from EMX
     docs):

        * The functions `recvmsg(3)' in this node, `sendmsg(3)' in this
          node, and `socketpair(3)' in this node are not implemented.

        * `sock_init(3)' in this node is not required and not implemented.

        * `flock(3)' in this node is not yet implemented (dummy function).
          (Perl has a workaround.)

        * `kill(3)' in this node:  Special treatment of PID=0, PID=1 and
          PID=-1 is not implemented.

        * `waitpid(3)' in this node:

               WUNTRACED
               	      Not implemented.
               waitpid() is not implemented for negative values of PID.

     Note that `kill -9' does not work with the current version of EMX.


     Since `sh.exe' is used for globing (see `glob', *Note Perlfunc:
     perlfunc,), the bugs of `sh.exe' plague perl as well.

     In particular, uppercase letters do not work in `[...]'-patterns with
     the current pdksh.

Modifications
-------------

   Perl modifies some standard C library calls in the following ways:

`popen'
     `my_popen' uses `sh.exe' if shell is required, cf. `"PERL_SH_DIR"' in
     this node.

tmpnam
     is created using `TMP' or `TEMP' environment variable, via tempnam.

tmpfile
     If the current directory is not writable, file is created using
     modified tmpnam, so there may be a race condition.

ctermid
     a dummy implementation.

stat
     `os2_stat' special-cases `/dev/tty' and `/dev/con'.

flock
     Since `flock(3)' in this node is present in EMX, but is not
     functional, it is emulated by perl.  To disable the emulations, set
     environment variable `USE_PERL_FLOCK=0'.

Perl flavors
============

   Because of idiosyncrasies of OS/2 one cannot have all the eggs in the
same basket (though EMX environment tries hard to overcome this
limitations, so the situation may somehow improve). There are 4
executables for Perl provided by the distribution:

`perl.exe'
----------

   The main workhorse. This is a chimera executable: it is compiled as an
`a.out'-style executable, but is linked with `omf'-style dynamic library
`perl.dll', and with dynamic CRT DLL. This executable is a VIO application.

   It can load perl dynamic extensions, and it can fork(). Unfortunately,
with the current version of EMX it cannot fork() with dynamic extensions
loaded (may be fixed by patches to EMX).

   *Note.* Keep in mind that fork() is needed to open a pipe to yourself.

`perl_.exe'
-----------

   This is a statically linked `a.out'-style executable. It can fork(),
but cannot load dynamic Perl extensions. The supplied executable has a lot
of extensions prebuilt, thus there are situations when it can perform
tasks not possible using `perl.exe', like fork()ing when having some
standard extension loaded. This executable is a VIO application.

   *Note.* A better behaviour could be obtained from `perl.exe' if it were
statically linked with standard *Perl extensions*, but dynamically linked
with the *Perl DLL* and CRT DLL. Then it would be able to fork() with
standard extensions, and would be able to dynamically load arbitrary
extensions. Some changes to Makefiles and hint files should be necessary
to achieve this.

   *This is also the only executable with does not require OS/2.* The
friends locked into `M$' world would appreciate the fact that this
executable runs under DOS, Win0.3*, Win0.95 and WinNT with an appropriate
extender. See `"Other OSes"' in this node.

`perl__.exe'
------------

   This is the same executable as `perl___.exe', but it is a PM
application.

   *Note.* Usually STDIN, STDERR, and STDOUT of a PM application are
redirected to `nul'. However, it is possible to see them if you start
`perl__.exe' from a PM program which emulates a console window, like
*Shell mode* of Emacs or EPM. Thus it *is possible* to use Perl debugger
(see *Note Perldebug: perldebug,) to debug your PM application.

   This flavor is required if you load extensions which use PM, like the
forthcoming `Perl/Tk'.

`perl___.exe'
-------------

   This is an `omf'-style executable which is dynamically linked to
`perl.dll' and CRT DLL. I know no advantages of this executable over
`perl.exe', but it cannot fork() at all. Well, one advantage is that the
build process is not so convoluted as with `perl.exe'.

   It is a VIO application.

Why strange names?
------------------

   Since Perl processes the #!-line (cf.  `DESCRIPTION', *Note Perlrun:
perlrun,, `Switches', *Note Perlrun: perlrun,, `"Not a perl script"',
*Note Perldiag: perldiag,, `"No Perl script found in input"', *Note
Perldiag: perldiag,), it should know when a program *is a Perl*. There is
some naming convention which allows Perl to distinguish correct lines from
wrong ones. The above names are almost the only names allowed by this
convention which do not contain digits (which have absolutely different
semantics).

Why dynamic linking?
--------------------

   Well, having several executables dynamically linked to the same huge
library has its advantages, but this would not substantiate the additional
work to make it compile. The reason is stupid-but-quick "hard" dynamic
linking used by OS/2.

   The address tables of DLLs are patched only once, when they are loaded.
The addresses of entry points into DLLs are guaranteed to be the same for
all programs which use the same DLL, which reduces the amount of runtime
patching - once DLL is loaded, its code is read-only.

   While this allows some performance advantages, this makes life terrible
for developers, since the above scheme makes it impossible for a DLL to be
resolved to a symbol in the .EXE file, since this would need a DLL to have
different relocations tables for the executables which use it.

   However, a Perl extension is forced to use some symbols from the perl
executable, say to know how to find the arguments provided on the perl
internal evaluation stack. The solution is that the main code of
interpreter should be contained in a DLL, and the `.EXE' file just loads
this DLL into memory and supplies command-arguments.

   This *greatly* increases the load time for the application (as well as
the number of problems during compilation). Since interpreter is in a DLL,
the CRT is basically forced to reside in a DLL as well (otherwise
extensions would not be able to use CRT).

Why chimera build?
------------------

   Current EMX environment does not allow DLLs compiled using Unixish
`a.out' format to export symbols for data. This forces `omf'-style compile
of `perl.dll'.

   Current EMX environment does not allow `.EXE' files compiled in `omf'
format to fork(). fork() is needed for exactly three Perl operations:

explicit fork()
     in the script, and

open FH, "|-"
open FH, "-|"
     opening pipes to itself.

   While these operations are not questions of life and death, a lot of
useful scripts use them. This forces `a.out'-style compile of `perl.exe'.

ENVIRONMENT
===========

   Here we list environment variables with are either OS/2- and DOS- and
Win*-specific, or are more important under OS/2 than under other OSes.

`PERLLIB_PREFIX'
----------------

   Specific for EMX port. Should have the form

     path1;path2

   or

     path1 path2

   If the beginning of some prebuilt path matches `path1', it is
substituted with `path2'.

   Should be used if the perl library is moved from the default location
in preference to `PERL(5)LIB', since this would not leave wrong entries in
@INC.  Say, if the compiled version of perl looks for @INC in
`f:/perllib/lib', and you want to install the library in `h:/opt/gnu', do

     set PERLLIB_PREFIX=f:/perllib/lib;h:/opt/gnu

PERL_BADLANG
------------

   If 1, perl ignores setlocale() failing. May be useful with some strange
locales.

`PERL_BADFREE'
--------------

   If 1, perl would not warn of in case of unwarranted free(). May be
useful in conjunction with the module DB_File, since Berkeley DB memory
handling code is buggy.

PERL_SH_DIR
-----------

   Specific for EMX port. Gives the directory part of the location for
`sh.exe'.

`USE_PERL_FLOCK'
----------------

   Specific for EMX port. Since `flock(3)' in this node is present in EMX,
but is not functional, it is emulated by perl.  To disable the emulations,
set environment variable `USE_PERL_FLOCK=0'.

`TMP' or `TEMP'
---------------

   Specific for EMX port. Used as storage place for temporary files, most
notably -e scripts.

Evolution
=========

   Here we list major changes which could make you by surprise.

Priorities
----------

   setpriority and getpriority are not compatible with earlier ports by
Andreas Kaiser. See `"setpriority, getpriority"'.

DLL name mangling
-----------------

   With the release 5.003_01 the dynamically loadable libraries should be
rebuilt. In particular, DLLs are now created with the names which contain
a checksum, thus allowing workaround for OS/2 scheme of caching DLLs.

Threading
---------

   As of release 5.003_01 perl is linked to multithreaded CRT DLL.  If
perl itself is not compiled multithread-enabled, so will not be perl
malloc(). However, extensions may use multiple thread on their own risk.

   Needed to compile `Perl/Tk' for XFree86-OS/2 out-of-the-box.

Calls to external programs
--------------------------

   Due to a popular demand the perl external program calling has been
changed wrt Andreas Kaiser's port.  If perl needs to call an external
program *via shell*, the `f:/bin/sh.exe' will be called, or whatever is
the override, see `"PERL_SH_DIR"' in this node.

   Thus means that you need to get some copy of a `sh.exe' as well (I use
one from pdksh). The drive `F:' above is set up automatically during the
build to a correct value on the builder machine, but is overridable at
runtime,

   *Reasons:* a consensus on `perl5-porters' was that perl should use one
non-overridable shell per platform. The obvious choices for OS/2 are
`cmd.exe' and `sh.exe'. Having perl build itself would be impossible with
`cmd.exe' as a shell, thus I picked up `sh.exe'. Thus assures almost 100%
compatibility with the scripts coming from *nix. As an added benefit this
works as well under DOS if you use DOS-enabled port of pdksh (see
`"Prerequisites"' in this node).

   *Disadvantages:* currently `sh.exe' of pdksh calls external programs
via fork()/exec(), and there is no functioning exec() on OS/2. exec() is
emulated by EMX by asyncroneous call while the caller waits for child
completion (to pretend that the pid did not change). This means that 1
*extra* copy of `sh.exe' is made active via fork()/exec(), which may lead
to some resources taken from the system (even if we do not count extra
work needed for fork()ing).

   Note that this a lesser issue now when we do not spawn `sh.exe' unless
needed (metachars found).

   One can always start `cmd.exe' explicitly via

     system 'cmd', '/c', 'mycmd', 'arg1', 'arg2', ...

   If you need to use `cmd.exe', and do not want to hand-edit thousands of
your scripts, the long-term solution proposed on p5-p is to have a
directive

     use OS2::Cmd;

   which will override system(), exec(), ```', and `open(,'...|')'. With
current perl you may override only system(), readpipe() - the explicit
version of ```', and maybe exec(). The code will substitute the
one-argument call to system() by `CORE::system('cmd.exe', '/c', shift)'.

   If you have some working code for `OS2::Cmd', please send it to me, I
will include it into distribution. I have no need for such a module, so
cannot test it.

   For the details of the current situation with calling external programs,
see `Starting OS' in this node.


     External scripts may be called by name.  Perl will try the same
     extensions as when processing -S command-line switch.

Memory allocation
-----------------

   Perl uses its own malloc() under OS/2 - interpreters are usually
malloc-bound for speed, but perl is not, since its malloc is
lightning-fast.  Perl-memory-usage-tuned benchmarks show that Perl's
malloc is 5 times quickier than EMX one.  I do not have convincing data
about memory footpring, but a (pretty random) benchmark showed that Perl
one is 5% better.

   Combination of perl's malloc() and rigid DLL name resolution creates a
special problem with library functions which expect their return value to
be free()d by system's free(). To facilitate extensions which need to call
such functions, system memory-allocation functions are still available with
the prefix `emx_' added. (Currently only DLL perl has this, it should
propagate to `perl_.exe' shortly.)

Threads
-------

   One can build perl with thread support enabled by providing `-D
usethreads' option to Configure.  Currently OS/2 support of threads is very
preliminary.

   Most notable problems:

`COND_WAIT'
     may have a race condition.  Needs a reimplementation (in terms of
     chaining waiting threads, with linker list stored in per-thread
     structure?).

`os2.c'
     has a couple of static variables used in OS/2-specific functions.
     (Need to be moved to per-thread structure, or serialized?)

   Note that these problems should not discourage experimenting, since they
have a low probability of affecting small programs.

AUTHOR
======

   Ilya Zakharevich, ilya@math.ohio-state.edu

SEE ALSO
========

   perl(1).


