[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

[MacPerl] I/O bug in recent MacPerls - exposed?



A while back, I reported a possible problem with Matthias' new I/O routines
in versions of MacPerl later than 5.1.3r2. At the time, I couldn't
reproduce the apparent bug in a simple fashion. I've now managed to work up
a test script which I believe demonstrates the problem. Could I ask
Matthias (and anyone else who's interested) to run the script and see if
they observe the same thing? If you do, and if it is genuinely a bug in
MacPerl, rather than something wrong with my code, any chance of a fix? It
effectively cripples the homebrew macro-processor I use to manage my
websites, so I'm stuck using 5.1.3r2 until I can get a fix or a workaround.

Thanks in advance,

			A

About the 'bug'
---------------

The problem I'm seeing is associated with redirection of STDOUT and STDIN.
If you redirect STDOUT, and then redirect and close STDIN repeatedly,
output that should go to STDOUT goes missing. The problem only seems to
manifest itself with repeated redirections/closes of STDIN.

It is of course possible that it isn't a bug in MacPerl, and that I'm doing
something lame-brained, in which case I'd welcome any tactful corrections
from the Wise Ones. However, the test script does behave differently on
different MacPerl versions (tests done on a PowerMac 7600/120 under MacOS 8
and a 8600/180 under System 7.5.5 with MacPerl 5.1.3r2 and 5.1.8r4), so I
suspect it may be genuine.

About the script
----------------

The script below redirects STDOUT to a file (after saving it first). It
then calls a recursive function which opens an input file and prints its
contents to STDOUT. If the input file contains a line that begins with the
word 'slurp', the subroutine will read in that file recursively, then
resume processing the file it was working on. To make this possible, it
keeps a stack of known filenames and file positions. When it's called, it
first adds the details for the current file to that stack, closes STDIN,
processes the file it was called with, and then restores STDIN by opening
it again on the previous file and seeking to the last recorded position. In
this way, the output can contain embedded files within files.

How to run it
-------------

Create a few text files. The first one should be called File1, but the
others can be called anything you like (I find the names File2 and File3
really appealing, but that's a personal choice). The files can contain
anything you like, but all - except the last file - should contain at least
one occurrence of the word 'slurp' (flush against the left margin) followed
by the name of another file. Put them where MacPerl can get at them, and
run the script.

What you should see
-------------------

The script prints each line it reads to both STDERR and STDOUT. On STDERR,
you should see the entire contents of all the files, with the contents of
nested files embedded appropriately. When the script has run, you should
also have a newly created file called 'File1-3'. If you run the script on
MacPerl 5.1.3r2, this file will contain exactly the same text as was
printed on STDERR, i.e. the sum total of all the text in all the files. If
you run the script on a later version, it won't. Or at least it doesn't
when I run it. Lines up to and including a 'slurp' line will typically be
missing. And it is this which I believe is a bug.

The script
----------

#!/usr/local/bin/perl5

$currentfile = "";
@filestack = ();
@posnstack = ();

open(SAVEOUT,">&STDOUT");
open(STDOUT,">File1-3") || die "can't open 'File1-3' for output: $!";
open(SAVEIN,"<&STDIN");

&slurp_file("File1");

open(STDIN,"<&SAVEIN");
close(STDOUT);
open(STDOUT,">&SAVEOUT");

sub slurp_file {
    my($filename) = shift;
    my($lastfile);

    if($currentfile) {
        push(@filestack,$currentfile);
        push(@posnstack,tell(STDIN));
    }
    close(STDIN);

    open(STDIN,$filename) || die "can't open '$filename' for input: $!";
    $currentfile = $filename;
    while(<STDIN>) {
        print STDERR $_;
        print $_;
        if (/^slurp (.*)/) { &slurp_file($1); }
    }

    close(STDIN);
    $lastfile = pop(@filestack);
    if ($lastfile) {
        open(STDIN,$lastfile) || "can't reopen '$lastfile' for input: $!";
        seek(STDIN,pop(@posnstack),0);
    }
}


--
angus@pobox.com                                   http://pobox.com/~angus/

    "Sick and twisted would be the first two words that come to mind," he
     said. "But at the same time, it's kind of neat." [Richard Grenier]



***** Want to unsubscribe from this list?
***** Send mail with body "unsubscribe" to mac-perl-request@iis.ee.ethz.ch