Read from filehandle opened for appending

Discussion in 'Perl Misc' started by Sisyphus, Apr 4, 2006.

  1. Sisyphus

    Sisyphus Guest

    Hi,
    If I try to read from a filehandle opened for appending, I get no warning
    about the fact that the filehandle is not readable. Why is that ?

    Here's the demo script:

    use warnings;

    # Create a test file:

    open(WR, '>', 'temp.txt') or die "Can't open for writing: $!";
    print WR "line 1\nline2\n\nline4\nline5\n";
    close(WR) or die "Can't close after writing: $!";

    # Open for appending, then try to read:

    open($fh, '>>', 'temp.txt') or die "Can't open: $!";
    seek($fh, 0, 0);
    @lines = <$fh>;
    close($fh) or die "Can't close: $!";
    print for @lines;
    __END__

    @lines is empty as it should be, but no warning gets issued.
    If I replace the '>>' with a '+>>', then @lines is filled with the contents
    of the file.

    Even at the XS level, we are unable to tell if a filehandle opened for
    appending is readable or not:

    use warnings;
    use Inline C => Config =>
    BUILD_NOISY => 1;

    use Inline C => <<'EOC';

    void my_fmode(SV * handle) {
    int x;
    IO *io;
    io = sv_2io(handle);
    x = IoTYPE(io);
    if (x == IoTYPE_RDONLY) printf ("read only\n");
    if (x == IoTYPE_WRONLY) printf ("write only\n");
    if (x == IoTYPE_RDWR) printf ("read_write\n");
    if (x == IoTYPE_APPEND) printf ("append\n");
    }

    EOC

    open($fh1, '+>>', 'temp.txt')
    or die "Can't open fh1 for reading and appending: $!";

    open($fh2, '>>', 'temp.txt')
    or die "Can't open fh2 for appending: $!";

    my_fmode($fh1);
    my_fmode($fh2);

    close($fh1) or die "Can't close fh1: $!";
    close($fh2) or die "Can't close fh2: $!";
    __END__

    For both filehandles, x is set to the same value (ie to IoTYPE_APPEND) so we
    have no chance of determining whether it's a '>>' filehandle or a '+>>'
    filehandle.

    Are these oversights, or are there sound reasons for these behaviours ?

    I don't really know why anyone would open a file for appending only and then
    try to read from it .... but I would have thought that such an action should
    be detectable/reportable in some way.

    Cheers,
    Rob
     
    Sisyphus, Apr 4, 2006
    #1
    1. Advertisements

  2. Sisyphus wrote :
    Because you don't ask for it

    perldoc -f seek
    seek FILEHANDLE,POSITION,WHENCE
    ...
    Returns 1 upon success, 0 otherwise.

    HTH

    Best regards
    Martin
     
    Martin Kißner, Apr 4, 2006
    #2
    1. Advertisements

  3. [ snipped ... ]


    It seems IoTYPE returns only a single character (see sv.h)
    and so it can't indicate that a handle is open for
    both read and append in the case of your $fh1, above.

    I seem to have more luck with using the macros and
    functions from perliol.h. I'm running perl 5.8.8 --
    I can't guarantee that this won't break on earlier
    versions:

    # with slight modifications to your code:

    use warnings;
    use Inline C => Config =>
    BUILD_NOISY => 1;

    use Inline C => <<'EOC';

    #include <perliol.h>

    void my_fmode(SV * handle) {
    IO *io;
    PerlIO *f;
    io = sv_2io(handle);
    f = IoIFP(io);
    if (PerlIOValid(f))
    {
    const IV flags = PerlIOBase(f)->flags;
    if (flags & PERLIO_F_CANWRITE) printf ("can write\n");
    if (flags & PERLIO_F_CANREAD) printf ("can read\n");
    if (flags & PERLIO_F_APPEND) printf ("append\n");
    }
    }

    EOC

    open($fh1, '+>>', 'temp.txt')
    or die "Can't open fh1 for reading and appending: $!";

    open($fh2, '>>', 'temp.txt')
    or die "Can't open fh2 for appending: $!";

    my_fmode($fh1);
    print "=" x 72, "\n";
    my_fmode($fh2);

    close($fh1) or die "Can't close fh1: $!";
    close($fh2) or die "Can't close fh2: $!";
    __END__

    can write
    can read
    append
    ========================================================================
    can write
    append
     
    attn.steven.kuo, Apr 4, 2006
    #3
  4. Sisyphus

    Sisyphus Guest

    Yes - but if I'm wondering why I don't get a warning from having tried to
    *read* the file.

    I get a warning if I:

    open(WR, '>', 'temp.txt') or die "$!";
    @lines = <WR>;

    I would expect a similar warning if I:

    open(WR, '>>', 'temp.txt') or die "$!";
    @lines = <WR>;

    but no warning eventuates. And when I look at what's happening at the XS
    level, I'm not surprised that no warning eventuates - because IoTYPE()
    doesn't know that the filehandle is not readable (because it can't
    distinguish between '>>' and '+>>') ..... but I'm not so sure my reasoning
    there is correct :)

    Cheers,
    Rob
     
    Sisyphus, Apr 4, 2006
    #4
  5. Sisyphus

    Sisyphus Guest

    ..
    ..
    Thanks for that. I can probably use it if it's reliable over perl 5.8.x
    (for all 'x').
    In any event, it's most interesting ..... and using a perl header file that
    has to be explicitly called ... how scary is that :)

    I'm a little bit intrigued by the fact that you can assign to 'f' using
    IoIFP(), even if the handle is write only and my_fmode() produces correct
    results. Otoh, if I instead assign to 'f' using IoOFP(), my_fmode() produces
    incorrect results if its fed a read only handle. Can you explain that ?

    Cheers,
    Rob
     
    Sisyphus, Apr 4, 2006
    #5
  6. Sisyphus

    Sisyphus Guest

    ..
    ..
    Perhaps I should have explained a bit better.

    If we do:

    f = IoIFP(io);

    then PerlIOValid(f) returns true, even if the handle is write only.

    But if we do:

    f = IoOFP(io);

    then PerlIOValid(f) returns false if the handle is read only.

    I'm puzzled as to how we can get away with the former, but not the latter.

    Cheers,
    Rob
     
    Sisyphus, Apr 4, 2006
    #6


  7. On my system PerlIOValid(f) returns true
    when given a read-only file handle.

    Tested with:

    open ($fh3, '<', $0)
    or die "Can't open fh3 for read: $!";

    my_fmode($fh3);

    # with the aforementioned XS code:

    void my_fmode(SV * handle) {
    IO *io;
    PerlIO *f;
    io = sv_2io(handle);
    f = IoIFP(io);
    if (PerlIOValid(f))
    {
    const IV flags = PerlIOBase(f)->flags;
    if (flags & PERLIO_F_CANWRITE) printf ("can write\n");
    if (flags & PERLIO_F_CANREAD) printf ("can read\n");
    if (flags & PERLIO_F_APPEND) printf ("append\n");
    }
    }



    In any case, the code is largely cribbed from the perl source:

    http://search.cpan.org/src/NWCLARK/perl-5.8.8/perlio.c

    Brief details of my system:

    $ perl -v

    This is perl, v5.8.8 built for darwin-2level

    Copyright 1987-2006, Larry Wall
    ....
     
    attn.steven.kuo, Apr 5, 2006
    #7
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.