=encoding utf8

=head1 TITLE

DRAFT: Synopsis 32: Setting Library - IO

=head1 AUTHORS

    The authors of the related Perl 5 docs
    Rod Adams <rod@rodadams.net>
    Larry Wall <larry@wall.org>
    Aaron Sherman <ajs@ajs.com>
    Mark Stosberg <mark@summersault.com>
    Carl Mäsak <cmasak@gmail.com>
    Moritz Lenz <moritz@faui2k3.org>
    Tim Nelson <wayland@wayland.id.au>
    Daniel Ruoso <daniel@ruoso.com>
    Lyle Hopkins <webmaster@cosmicperl.com>

=head1 VERSION

    Created: 19 Feb 2009 extracted from S29-functions.pod; added stuff from S16-IO later

    Last Modified: 4 July 2010
    Version: 13

The document is a draft.

If you read the HTML version, it is generated from the Pod in the specs
repository under
so edit it there in the git repository if you would like to make changes.

=head2 IO

[Note: if a method declaration indicates a method name qualified by
type, it should be taken as shorthand to say which role or class the
method is actually declared in.]

=over 4

=item open

    multi open (Str $name,
        Bool :$rw = False,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        Any  :$nl = "\n",
        Bool :$chomp = True,
        --> IO
    ) is export

A convenience method/function that hides most of the OO complexity.
It will only open normal files.  Text is the default.  Note that
the "Unicode" encoding implies figuring out which actual UTF is
in use, either from a BOM or other heuristics.  If heuristics are
inconclusive, UTF-8 will be assumed.  (No 8-bit encoding will ever
be picked implicitly.)  A file opened with C<:bin> may still be
processed line-by-line, but IO will be in terms of C<Buf> rather
than C<Str> types.

TODO: document read/write/append modes (:r, :w, :a)

=item dir

    multi dir($directory = '.', Mu :$test = none('.', '..')) { ... }

Returns a lazy list of file names in the C<$directory>. By default the current
and the parent directory are excluded, which can be controlled with the
C<$test> named paramater. Only items that smart-match against this test are

=item getc

    method getc (Int $chars = 1 --> Char)

See below for details.

=item print

    method print (*@LIST --> Bool)
    multi print (*@LIST --> Bool)
    method Str::print (IO $io --> Bool)
    method Array::print (IO $io --> Bool)
    method Hash::print (IO $io --> Bool)

See below for details.

=item say

    method say (*@LIST --> Bool)
    multi say (*@LIST --> Bool)
    method Str::say (IO $io --> Bool)
    method Array::say (IO $io --> Bool)
    method Hash::say (IO $io --> Bool)

See below for details.

=item note

    multi note (*@LIST --> Bool)

See below for details.

=item printf

    method printf (Str $fmt, *@LIST --> Bool)
    multi printf (Str $fmt, *@LIST --> Bool)

See below for details.

=item uri

    method uri(Str $uri --> IO::Streamable);
    sub uri(Str $uri --> IO::Streamable);

Returns an appropriate C<IO::Streamable> descendant, with the type depending on the uri
passed in.  Here are some example mappings:

    URI type IO type
    ======== =======
    file:    IO::File or IO::Directory
    ftp:     IO::Socket::INET (data channel)
    http:    IO::Socket::INET

These can naturally be overridden or added to by other modules.

=item %*PROTOCOLS dynamic variable

For each protocol, stores a type name that should be instantiated by calling the C<uri>
constructor on that type, and passing in the appropriate uri.


=head1 Roles

The functionality of C<IO> objects is broken down into several roles,
which should identify the features each object supports.

=head2 IO

The base role only tags that this is an C<IO> object for more generic
purposes. It doesn't specify any methods or attributes.

=head2 IO::Readable

This role provides unbuffered read access to the data stream.

    role IO::Readable {
        has $.isReadable;
        method read(Int $bytes --> Buf)

When the C<$.isReadable> is set, it tries to change the readability of the filehandle.  This
is not always possible, but can be done in a number of cases.  C<IO::Socket> can remove
readability by calling C<shutdown>, for example.


=item method read(Int $bytes --> Buf)

Tries to read C<$bytes> bytes and return it as a C<Buf>. The C<Buf> may be
shorter than the actual specified number of C<$bytes>.

This is "raw" read. You're going to
have plain octets stored in C<$buf>. If what you want is a C<Str>,
you're going to need to C<.decode> it after C<read>ing, or use "getc" or other
C<IO::Readable::Encoded> methods.


=head2 IO::Writeable

This role provides unbuffered write access to the data stream.

    role IO::Writeable {
        has $.isWriteable;
        method write(Buf $buf --> Int)

When the C<$.isWriteable> is set, it tries to change the writeability of the filehandle.
This is not always possible, but can be done in a number of cases.  C<IO::Socket> can remove
writeability by calling shutdown(), for example.


=item method write(Buf $buf --> Int)

Tries to write C<$buf>. The actual number of bytes
written is returned. It might return unthrown failures, to be
specified by each C<IO> implementation.

This is "raw" write. C<$buf> contains plain octets. If you want to C<write>
a C<Str>, you should C<.encode> it first, or use "print" or other
C<IO::Writeable::Encoded> methods.


=head2 IO::Seekable


=item method eoi( --> Bool)

EOI = End Of Input -- equivalent to End Of File, but applies to other kinds of sockets as

Returns true if it's the end of the input (i.e. end of file or whatever), returns false if
not, fails if we can't say for certain.

=item method seek(Int $position --> Bool)

Position this stream into C<$position>. The meaning of this position is
always in "octets".

=item method tell( --> Int)

Returns the current raw position in the stream in number of "octets".


=head2 IO::Buffered

Indicates that this object performs buffering. The management of the
buffer is completely implementation specific.


=item method flush( --> Bool)

Flushes the buffers associated with this object.

=item method autoflush( --> Bool) is rw

Forces this object to keep its buffers empty

If set to nonzero, forces a flush right away and after every write
or print on the currently selected output channel.
Default is 0 (regardless of whether the channel is really buffered
by the system or not;
C<$OUT_FH.autoflush> tells you only whether you've asked Perl
explicitly to flush after each write).
C<$*OUT> will typically be line buffered if output is to the
terminal and block buffered otherwise.
Setting this variable is useful primarily when you are
outputting to a pipe or socket,
such as when you are running a Perl program under rsh
and want to see the output as it's happening.
This has no effect on input buffering.


=head2 IO::Streamable

This role represents objects that depend on some external resource,
which means that data might not be available at request.

    role IO::Streamable does IO {...}


=item new()

    method new(
        Bool :$NoOpen,
        Bool :$Blocking,
        --> IO::Streamable
    ) {...}

Unless the NoOpen option is passed, an open will be done on the C<IO> object when it is

If blocking is passed in, .blocking() is called (see below).

=item method blocking( --> Bool) is rw

This allows the user to control whether this object should do a
blocking wait or immediately return in the case of not having data

=item uri

    method uri(Str $uri --> IO::Streamable) {...}

This should be callable on the class, and act like a kind of "new()" function.  When given
a URI, it returns an C<IO::Streamable> of the appropriate type, and throws an error when an
inappropriate type is passed in.  For example, calling C<IO::File.uri('http://....')> will
throw an error (but will suggest using just uri('http://...') instead).


=head2 IO::Encoded

This is a generic role for encoded data streams.


=item method encoding( --> Str) is rw

=item method locale( --> Str) is rw

Encoding and locale are required for sane conversions.


=head2 IO::Readable::Encoded

This role provides encoded access to a readable data stream, implies
C<IO::Encoded>. Might imply C<IO::Buffered>, but that's not a requirement.


=item method ins( --> Int)

Returns the number of lines or records that have been input.
Now with cleaned-up localization usage.

=item method input-line-separator( --> Str) is rw

This regulates how "get" and "lines" behave.

The input line (record) separator, newline by default.
This influences Perl's idea of what a ``line'' is.
Works like awk's RS variable, including treating empty lines
as a terminator if set to the null string.
(An empty line cannot contain any spaces or tabs.)
You may set it to a multi-character string to match a multi-character
terminator, or to Nil to read through the end of file.
Setting it to "\n\n" means something slightly different
than setting to "", if the file contains consecutive empty lines.
Setting to "" will treat two or more consecutive empty lines
as a single empty line. Setting to "\n\n" will blindly assume
that the next input character belongs to the next paragraph,
even if it's a newline.

You may also set it to a regular expression.  The value of C<$/>
will be (temporarily) set to the matched separator upon input,
if you care about the contents of the separator.

=item method input-field-separator( --> Str) is rw


=item method input-escape( --> Str) is rw


=item method get( --> Str)

Reads the stream before it finds a C<$.input-line-separator> and
returns it (autochomped by default).

=item method readfield( --> Str)

[Deprecated. Use split or comb or an ILS regex.]

=item method getc( --> Char)

Reads the next character in the set C<$.encoding>,
or C<Failure> at end of file, or if there was
an error (in either case C<$!> is set).  Note that this
function cannot be used interactively as a C<readkey()> function, since under
Unicode you can't tell the end of a grapheme until you
see the beginning of the next one.

[TODO someone needs to define something like C<readkey()> for terminal IO.
Though most event-based programs will just want to feed keystrokes into the
event queue.]

=item multi method comb ( Regex $matcher, Int $limit = * )

Reads everything into a string, and calls C<.comb> on it with the same
parameters. See C<Str::comb>.


=head2 IO::Writeable::Encoded

This role provides encoded access to a writeable data stream, implies
C<IO::Encoded>. Might imply C<IO::Buffered>, but that's not a requirement.

If these are called in their non-object form, they operate on C<$*OUT>, except in the
case of warn(), which operates on C<$*ERR>.  The form with leading dot prints C<$_> to
the appropriate handle unless C<$_> happens to be a filehandle.


=item Int method outs()

Returns the number of lines or records that have been output so far.

=item method output-line-separator( --> Str) is rw

This regulates how say behaves.

=item method output-field-separator( --> Str) is rw


=item method output-escape( --> Str) is rw


=item method Str::print (IO $io = $*OUT --> Bool)

=item method Str::say (IO $io = $*OUT --> Bool)

=item method Array::print(IO $io = $*OUT --> Bool)

=item method Array::say(IO $io = $*OUT --> Bool)

=item method Hash::print(IO $io = $*OUT --> Bool)

=item method Hash::say(IO $io = $*OUT --> Bool)

Stringifies the invocant (if necessary) and then sends it to the output.
C<say> should add an additional C<$.output-line-separator>.

=item method print (*@LIST --> Bool)

=item multi print (*@LIST --> Bool)

Stringifies each element, concatenates those strings, and sends the
result to the output.
Returns C<Bool::True> if successful, C<Failure> otherwise.

The compiler will warn you if use a bare C<print> without arguments.
(However, it's fine if you have an explicit argument list that evaluates to
the empty list at runtime.)

    print;             # warns
    if $_ { print }    # warns
    if $_ { print() }  # ok, but does nothing
    if $_ { print () } # ok, but does nothing

=item method say (*@LIST --> Bool)

=item multi say (*@LIST --> Bool)

This is identical to print() except that it auto-appends the C<output-line-separator> after
the final argument.

    Was:    print "Hello, world!\n";
    Now:    say   "Hello, world!";

As with C<print>, the compiler will warn you if you use a bare C<say> without

=item multi note (*@LIST --> Bool)

Does a "say" to C<$*ERR>, more or less.  Like C<warn>, it adds a
newline only if the message does not already end in newline.  Unlike
C<warn>, it is not trappable as a resumable exception because it
outputs directly to C<$*ERR>.  You can suppress notes in a lexical
scope by declaring:

    only note(*@) {}

=item method printf ($self: Str $fmt, *@LIST --> Bool)

=item multi printf (Str $fmt, *@LIST --> Bool)

The function form works as in Perl 5 and always prints to C<$*OUT>.


For any handle marked as textual, all these output calls intercept any newline
character and translate it to the current C<output-line-separator> if it
is defined as something other than newline.  No such translation is done on
binary handles, though you may still specify a record separator.  In any case,
escaping separators is the responsibility of the programmer.

=head2 IO::Closeable

This role indicates that this object can be closed.


=item method close( --> Bool)

Closes the file or pipe associated with the object.

Returns C<True> on success, but might return an unthrown C<Failure>.
Returns true only if C<IO> buffers are successfully flushed and closes the system
file descriptor.

Unlike in Perl 5, an C<IO> object is not a special symbol table entry
neither this object is available magically anywhere else. But as in
Perl 5, unless stated otherwise, C<IO::Closeable> objects always close
themselves during destruction.


=head2 IO::Socket

    role IO::Socket
        does IO::Closeable
        does IO::Readable
        does IO::Writeable
        does IO::Streamable
        has %.options;
        has Bool $.Listener;

Accessing the C<%.options> would on Unix be done with I<getsockopt(2)>/I<setsockopt(2)>.

The $.Listener attribute indicates whether the socket will be a listening socket when
opened, rather than indicating whether it is currently listening.


=item new

    method new(
        :$Listener, # initialises $.Listener

The initial value of the $.Listener attribute is defined according to the following rules:

 * If $Listener is passed to .new(), then that value is used
 * If neither a local address nor a remote address are passed in, throw an exception
 * If no remote address is passed, then $.Listener is set to SOMAXCONN
 * If no local address is used, then $Listener is set to 0
 * If both local and remote addresses are used, throw an exception that asks people to
   specify $Listener

=item open

    method open()

If $.Listener is true, does a I<bind(2)> and a I<listen(2)>, otherwise does a

It's end-user use case is intended for the case where NoOpen is passed to .new().  .new()
itself will presumably also call it.

=item close

    method close()

Implements the close() function from IO::Closeable by doing a shutdown on the connection
(see below) with @how set to ('Readable', 'Writeable').

=item shutdown

    method shutdown(Str @how)

Does a I<shutdown(2)> on the connection.  See also IO::Readable.isReadable and

$how can contain 1 or more of the strings 'Readable' and 'Writeable'.

=item accept

    method accept( --> IO::Socket)

=item method read($buf is rw, Int $bytes --> Int)

Implements the IO::Readable interface by doing a I<recv(2)>.

=item method write($buf, Int $bytes --> Int)

Implements the IO::Writeable interface by doing  a I<send(2)>.

=item getpeername


=head2 IO::FileDescriptor

This role indicates that this object actually represents an open file
descriptor in the os level.


=item method int fileno()

File descriptors are always native integers, conforming to C89.


=head1 Classes

=head2 IO::File

This does file input and output.

    class IO::File does IO::Streamable {


=item new

    method new(
        Path :$Path,
        Bool :$NoOpen,

The C<Path> and C<fd> options are mutually exclusive.  

C<NoOpen> is passed to C<IO::Streamable.new()>


    # Read, no interpolation
    $fobj = IO::File.new(Path => qp{/path/to/file});

    # Write, interpolation
    $fobj = IO::File.new(
        Path => p:qq{$filename},
        Writeable => 1

    # Read using file descriptor
    $fobj = IO::File.new(fd => $fd);

This final example associates an C<IO> object with an already-open file descriptor,
presumably passed in from the parent process.

=item open()

This function opens a file that had the C<NoOpen> option passed to the C<new> method.

=item IO.truncate

=item IO.fcntl

Available only as a handle method.


=head2 IO::Directory

    role IO::Directory does IO::Streamable {


=item open

        Str  :$enc = "Unicode",

Opens a directory for processing, if the C<new> method was passed the C<NoOpen> option.
Makes the directory looks like
a list of autochomped lines, so just use ordinary C<IO> operators after the open.


=head2 IO::FileSystems

This represents the file systems mounted on the current machine (i.e. accessible via a 
filesystem path).  

    class IO::FileSystems {
        has Str $.illegal-chars; # i.e. /\x0
        has Int $.max-path;
        has Int $.max-path-element;

=over 4

=item chdir FILENAME
X<chdir> X<cd>

=item chdir

Changes the current working directory to the one specified by FILENAME.
If it succeeds it returns true, otherwise it returns C<Failure> and
sets C<$!> (errno).  Note, though, that chdir affects only the system 
directory; most things in Perl 6 that need a current directory depend
on their thread's copy of $*CWD, so you probably want to set $*CWD
instead of using chdir().  

=item find

Returns C<Path> objects.  Path.Encoding is set to $?ENC unless the 
$Encoding parameter is passed in (see Path for further discussion of

=item glob

Returns C<Path> objects.  Path.Encoding is set to $?ENC unless the 
Encoding parameter is passed in (see Path for further discussion of

=item rename


=head2 Path

The "Path" role covers both the path to the file, and the file metadata.  They
are usually created with the qp{/path/to/file} syntax.  It could be a directory,
file, link, or something else OS-specific.  

    role Path does Str does Array {
        has Str $.Type;
        has Str @.Elements;
        has Str $.Encoding;
        has Buf $.Binary;
        has IO::ACL @.ACLs;
        has %.times;

C<$.Type> can be C<File>, C<Directory>, C<Link>, or C<Other>.  See 
C<.create()> method documentation for how it is set.  

The C<@.Elements> array is a list of Str that contain the path elements, but
all are checked before being pushed onto the array.  Note that @.Elements
can not be accessed unless $.Encoding is defined.  

The C<%.times> has keys that can be e.g. C<ctime>, C<Modification>, and 
C<Access> (and maybe others on other operating systems), and the values are 
all C<Instant> objects.

When a Path is used as a Str, it allows some operations, so that it can 
be concatenated easily with other strings.  When used as an Array, it 
acts as an array of path elements.  

=head3 Methods

=over 4

=item new

While new Path objects will normally be created with the qp{/path/to/file} 
syntax, there are also OO-related alternatives.  

This is called automatically on object creation.

    multi method new(
        Stringy :$Path,
        Str :@PathElements,
        Str :$Encoding,

        Str :@Constraints, 
        Str :$Protocol,

        Str :$Target,
        Str :$LinkType,
        Str :$Type,

Path and PathElements are mutually exclusive.  

If the $Encoding parameter is not defined, then, if Path is a Buf, 
the $.Encoding attribute remains undefined, otherwise it is set to 
$?ENC.  There are
a number of features that don't work without the encoding being set.  

$Constraints determines whether the $Path and $Target strings should be
assumed to be Unix-style, Windows-style, or something else.  

If the Type option is not passed in, the Path.Type attribute is initialised 
as follows:

    Value        Condition
    =====        =========
    Directory    $Path ends in a separator (i.e. /)
    Link         $Target is specified
    Other        $Protocol is specified
    Undefined    All other cases

If the $.Type attribute is read (which will happen in a number of cases,
including when you read $.Target and $.LinkType), but is still undefined, 
then an attempt is 
made to determine what its type should be from the filesystem.  If no 
answers are found using this method, then it defaults to "File".  

The C<Target> and C<LinkType> options are only relevant for links that have
not been created yet, or are to be overwritten; in all other cases, 
they will be determined from the filesystem.  If Target is not specified,
this Path is assumed not to be a link.  If LinkType is not specified, 
then the default is used (symbolic, on a Unix system).  


    # These three do the same thing (on a Unix machine)
    $path = qp{/home/wayland};
    $path = Path.new(PathElements => ['home', 'wayland']);
    $path = Path.new(Constraints => ['Unix'], Path => qp{/home/wayland});
    $path = Path.new(Path => qp{/home/wayland});

    # This creates a symlink from /home/wayland/m to /home/wayland/Music
    $path = Path.new(
        Path => qp{/home/wayland/m},
        Target => qp{/home/wayland/Music},

=item path

method path( --> Str);

Returns @.elements concatenated together for use as a string.  Usually this 
is the path that it was originally created with.  

=item canonpath

    method canonpath( --> Str);

No physical check on the filesystem, but a logical cleanup of a path.

=item realpath

    method realpath( --> Str);

Gets the real path to the object, resolving softlinks/shortcuts, etc

=item resolvepath

    method resolvepath(Str :@Types --> Str);

@Types can contain "real" and "canon", in any order, and the
method will run realpath and canonpath in the order specified.


    multi method ACCEPTS(Path $filename);

Test whether the specified filename is the same file as this file.  On a 
Unix system, this would presumably be done by comparing inode numbers or 

=item create
X<mkdir> X<md> X<directory, create> X<touch>

    method create(
        Bool :$Recursive,
        Bool :$Truncate,

Creates/touches the specified path.  In the case of a link or a directory, no 
parameters are required.  If a file doesn't exist, then no parameters are 
required.  If the path already exists, then an exception is thrown, unless
the file is an ordinary file or a link, and $Truncate is true.  

The $Recursive option specifies that any necessary parent directories should
also be created.  

=item touch

Update timestamps on a file.  

=item delete

X<rmdir> X<rd> X<directory, remove>

    method delete(Bool :$Recursive --> Int);

This deletes the C<Path> from the filesystem.  If the node has children, it 
throws an error unless the C<Recursive> option is specified.  It returns the 
number of nodes deleted, and may throw an exception.  

=item get

    multi get () 

Returns the next line from $*ARGFILES.  (Note that other C<get> functions
and methods are operations on any iterator, not just an IO handle.)

=item lines

    method lines ($handle:
        Any  $limit = *,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        Any  :$nl = "\n",
        Bool :$chomp = True,
        --> List

    multi lines (IO $fh = $*ARGFILES,
        Any  $limit = *,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        Any  :$nl = "\n",
        Bool :$chomp = True,
        --> List

    # See also Str.lines and lines(Str)

Returns some or all the lines of a file or entries in a directory
as a C<List> regardless of context.
See also C<slurp>.  Note that lists are lazy by default, but you
can always ask for C<eager lines>.  Note that the limit semantics cannot be
duplicated by subscripting, since


reads all the lines before the subscript gives you the first five,


reads only five lines from the handle.  Note that


is equivalent to


If fewer lines are available than the limit, it is not an error;
you just get the number of lines available.

=item slurp

    method slurp ($handle:
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf
    multi slurp (IO $fh = $*ARGFILES,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf
    multi slurp (Str $filename,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf

Slurps the entire file into a C<Str> (or C<Buf> if C<:bin>) regardless of context.
(See also C<lines>.)

In the case of a directory, it uses "\n" to separate entries.  


=head3 Other things

=over 4

=item IO ~~ :X

=item EXPR ~~ :X

  $file ~~ :X

A file test, where X is one of the letters listed below.  This unary
operator takes one argument, either a filename or a filehandle, and
tests the associated file to see if something is true about it.

A C<Pair> used as a pattern is treated as a file test.

    :r  File is readable by effective uid/gid.
    :w  File is writable by effective uid/gid.
    :x  File is executable by effective uid/gid.
    :o  File is owned by effective uid.

    :R  File is readable by real uid/gid.
    :W  File is writable by real uid/gid.
    :X  File is executable by real uid/gid.
    :O  File is owned by real uid.

    :e  File exists.
    :s  File has a size > 0 bytes

    :f  File is a plain file.
    :d  File is a directory.
    :l  File is a symbolic link.
    :p  File is a named pipe (FIFO), or Filehandle is a pipe.
    :S  File is a socket.
    :b  File is a block special file.
    :c  File is a character special file.
    :t  Filehandle is opened to a tty.

    :u  File has setuid bit set.
    :g  File has setgid bit set.
    :k  File has sticky bit set.

Each of these is redirected (by C<Pair.ACCEPTS>) to the
corresponding method name on an IO object.  (These methods are not
defined on bare strings).  Each test returns a boolean, and may be
negated with a C<!> after the colon.  They maybe ANDed and ORed using
junctional logic.  In fact, this is the primary reason for writing
them as a pattern match; if you only want one test, you could just call
the individual IO method directly and more efficiently.  In any case,
you must call the C<.s> method to return the file's size in bytes.

There is no <.z> method, so just write C<:!s> to test a file for zero size.
Likewise, just call C<.s> directly if you actually want to know the file's
size, since C<~~ :s> only returns a boolean.

The C<.T> and C<.B> methods will be replaced by some filetype guessing
methods more appropriate to the age of Unicode.  There are likely methods
to return the various ages of the file corresponding to Perl 5's C<-M>,
C<-A>, and C<-C> times, but they make no sense as booleans, so also call
those methods directly (whatever they end up being named).

The interpretation of the file permission operators C<:r>, C<:R>,
C<:w>, C<:W>, C<:x>, and C<:X> is by default based on:


=item * The mode of the file and the uids and gids of the user

=item * ACLs (access control lists)

=item * read-only filesystems


There may be other reasons you can't actually read, write, or execute
the file.  Such reasons may be for example network filesystem access
controls and unrecognized executable formats.

Also note that, for the superuser on the local filesystems, the C<:r>,
C<:R>, C<:w>, and C<:W> tests always return 1, and C<:x> and C<:X> return 1
if any execute bit is set in the mode.  Scripts run by the superuser
may thus need to do a C<stat> to determine the actual mode of the file,
or temporarily set their effective uid to something else.

You can test multiple features using junctions:

  if $filename.IO ~~ :r & :w & :x  {...}


=head2 IO::ACL

This is a basic abstraction; for better control, use the operating-system specific
interfaces, over which this is a thin veneer.

    class IO::ACL {
        has Str $.type; # "User", "Group", "Everyone", ???
        has Str $.id; # username or groupname; unused for $type eq "Everyone"
        has %.permissions;
                # Unsupported values may (or may not) throw
                # UnsupportedPermission when set or read
        has Path $.owningObject;

The permissions used in C<%permissions> are:


=item Readable

Should be supported by all filesystems as an item to read from the hash for the group

=item Writeable

Should be supported by all filesystems as an item to read from the hash for the group

=item Executable

Supported on most Unix systems, anyway.  Windows should be able to guess when this is
read, and throw an exception if written to.

=item Default

An ACL of User,fred,Default sets the user "fred" to be the owner of the file.  This can be
done with groups too.  Works on Unix, at least.


The C<$.owningObject> attribute of C<ACL> shows what the ACL is set on.  On a
Windows system, this can be a parent directory, as permissions are inherited.

=head2 IO::Socket::INET

    class IO::Socket::INET does IO::Socket {
        has Int $.Version = 4; # Whether to use IPv4 or IPv6
        has Str $.Protocol = 'TCP';
        has Str $.RemoteHost;
        has Int $.RemotePort;
        has Str $.LocalHost;
        has Int $.LocalPort;


=item new

    method new(
        Str  :$RemoteHost, # Initialises $.RemoteHost
        Str  :$RemotePort, # Initialises $.RemotePort (if it's not a numeric string, use getservbyname)
        Str  :$LocalHost,  # Initialises $.LocalHost
        Str  :$LocalPort,  # Initialises $.LocalPort (if it's not a numeric string, use getservbyname)
        Str  :$Protocol,   # Initialises $.Protocol
        Int  :$Version,    # Initialises $.Version (IPv4 vs. IPv6)

        Bool :$Listener,   # Passed to IO::Socket.new()

        Bool :$Blocking,   # Passed to IO::Streamable.new()
        Bool :$NoOpen,     # Passed to IO::Streamable.new()

        --> IO::Socket::INET
    ) {...}


=head2 IO::Pipe

    class IO::Pipe does IO::Streamable does IO::Readable does IO::Writable {

Will need to set IO::Readable.isReadable and IO::Writable.isWriteable depending on opening


=item close()

If the file handle came from a piped open, C<close> will additionally
return C<Failure> (aliased to C<$!>) if one of the other system calls involved fails, or if the
program exits with non-zero status.  The exception object will contain any
pertinent information.  Closing a pipe
also waits for the process executing on the pipe to complete, in case you
want to look at the output of the pipe afterwards, and
implicitly puts the exit status value into the C<Failure> object if necessary.

=item IO::Pipe.to

    method to(Str $command, *%opts --> Bool)
    method to(Str *@command, *%opts --> Bool)

Opens a one-way pipe writing to C<$command>.  C<IO> redirection for
stderr is specified with C<:err(IO)> or C<< :err<Str> >>.  Other C<IO> redirection
is done with feed operators. XXX how to specify "2>&1"?

=item IO::Pipe.from

    method from(Str $command, *%opts --> Bool)
    method from(Str *@command, *%opts --> Bool)

Opens a one-way pipe reading from $command.  C<IO> redirection for
stderr is specified with C<:err(IO)> or C<< :err<Str> >>.  Other C<IO> redirection
is done with feed operators. XXX how to specify "2>&1"?

=item IO::Pipe.pair

    method pair(--> List of IO::Pipe)

A wrapper for I<pipe(2)>, returns a pair of C<IO> objects representing the
reader and writer ends of the pipe.

   ($r, $w) = IO::Pipe.pair;


=head1 OS-specific classes

=head2 Unix

=head2 Path::Unix


=item chown

    multi chown ($uid = -1, $gid = -1, *@files --> Int)

Changes the owner (and group) of a list of files.  The first
two elements of the list must be the numeric uid and gid, in
that order.  A value of -1 in either position is interpreted by
most systems to leave that value unchanged.  Returns the number
of files successfully changed.

    $count = chown $uid, $gid, 'foo', 'bar';
    chown $uid, $gid, @filenames;

On systems that support C<fchown>, you might pass file handles
among the files.  On systems that don't support C<fchown>, passing
file handles produces a fatal error at run time.

Here's an example that looks up nonnumeric uids in the passwd

   $user = prompt "User: ";
   $pattern = prompt "Files: ";

   ($login,$pass,$uid,$gid) = getpwnam($user)
       or die "$user not in passwd file";

   @ary = glob($pattern);      # expand filenames
   chown $uid, $gid, @ary;

On most systems, you are not allowed to change the ownership of
the file unless you're the superuser, although you should be
able to change the group to any of your secondary groups.  On
insecure systems, these restrictions may be relaxed, but this
is not a portable assumption.  On POSIX systems, you can detect
this condition this way:

    use POSIX qw(sysconf _PC_CHOWN_RESTRICTED);
    $can-chown-giveaway = not sysconf(_PC_CHOWN_RESTRICTED);

=item chmod LIST
X<chmod> X<permission> X<mode>

Changes the permissions of a list of files.  The first element of the
list must be the numerical mode, which should probably be an octal
number, and which definitely should I<not> be a string of octal digits:
C<0o644> is okay, C<0644> is not.  Returns the number of files
successfully changed.

    $count = chmod 0o755, 'foo', 'bar';
    chmod 0o755, @executables;
    $mode = '0644'; chmod $mode, 'foo';      # !!! sets mode to --w----r-T
    $mode = '0o644'; chmod $mode, 'foo';     # this is better
    $mode = 0o644;   chmod $mode, 'foo';     # this is best

=item stat

=item IO.stat

    $node.stat(Bool :$link); # :link does an lstat instead

Returns a stat buffer.  If the lstat succeeds, the stat buffer evaluates
to true, and additional file tests may be performed on the value.  If
the stat fails, all subsequent tests on the stat buffer also evaluate
to false.


=head2 IO::Socket::Unix

    role IO::Socket::Unix does IO::Socket {
        has Str $.RemoteAddr, # Remote Address
        has Str $.LocalAddr,  # Local Address


=item new

    method new(
        Str  :$RemoteAddr,
        Str  :$LocalAddr,

        Bool :$Listener,   # Passed to IO::Socket.new()

        Bool :$Blocking,   # Passed to IO::Streamable.new()
        Bool :$NoOpen,     # Passed to IO::Streamable.new()

        --> IO::Socket::Unix
    ) {...}

=item pair

    method pair(Int $domain, Int $type, Int $protocol --> List of IO)

A wrapper for I<socketpair(2)>, returns a pair of C<IO> objects representing the
reader and writer ends of the socket.

   use IO::Socket;
   ($r, $w) = IO::Socket::Unix.pair(AF_UNIX, SOCK_STREAM, PF_UNSPEC);


=head2 IO::POSIX

Indicates that this object can perform standard posix C<IO>
operations. It implies C<IO::Readable> and C<IO::Writeable>.


=item method dup( --> IO)

=item has Bool $.blocking is rw

=item method flock(:$r,:$w --> Bool)

=item method funlock( --> Bool)

=item ...


=head1 Unfiled

=over 4

=item IO.ioctl

Available only as a handle method.

=item alarm

=item prompt

    multi prompt (Str $prompt --> Str)

Should there be an IO::Interactive role?

=item Str.readpipe

=item sysopen

=item IO.sysseek

=item umask


=head1 Removed functions


=item IO.eof

Gone, see eoi C<IO::Seekable>.

=item IO.fileno

See C<IO::FileDescriptor>.

=item /(get|set)(host|net|proto|serv|sock).*/

Should be implemented by an external library.

=item lstat

Use C<stat> with the C<:link> option.

=item IO.name

Changed to C<.path>, but we haven't gotten around to specifying this on all of them.

The C<.name> method returns the name of the file/socket/uri the handle
was opened with, if known.  Returns Nil otherwise.  There is no
corresponding C<name()> function.

=item pipe

Gone, see Pipe.pair

=item select(both)

Gone.  (Note: for sub-second sleep, just use sleep with a fractional argument.)

=item IO.shutdown()

Gone, see C<IO::Socket.close()>, C<$IO::Readable.isReadable>, and C<$IO::Writeable.isWriteable>

=item socketpair

Gone, see Socket.pair

=item IO.sysread

Gone, see C<IO::Readable.read()>.

=item IO.syswrite

Gone, see C<IO::Writeable.read()>.

=item utime

Gone, see C<Path.times>.


=head1 Additions

Please post errors and feedback to perl6-language.  If you are making
a general laundry list, please separate messages by topic.

=for vim:set expandtab sw=4: