Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

How to preserve the value of STDIN

by Ovid (Cardinal)
on Sep 22, 2000 at 03:00 UTC ( [id://33582]=perlquestion: print w/replies, xml ) Need Help??

Ovid has asked for the wisdom of the Perl Monks concerning the following question:

Here's the problem. I'm the new guy at a company and walked into discover that, amongst other things, they don't use CGI.pm for CGI scripts. They have a rather limited in-house script that is insufficient for our needs. I need to allow users to upload files images to our server, but their script won't handle it, so I need to use CGI.pm. However, for various reasons, we need to call their script first because it does a lot of funky stuff with the data that fits their in-house work. Naturally, since their script clobbers STDIN, CGI.pm can't get to the data on a post (which is what I need when I use multipart/form-data).

So the question is, how do I preserve what's in STDIN so CGI.pm can read it? Here's Fastolfe's suggestion:

local($/); $data = <STDIN>; my $A = IO::String->new ($data); my $B = IO::String->new ($data);
Later, CGI.pm would be called like the following:
use CGI ($B);
Any comments/suggestions? The IS manager agrees that we need to convert everything to CGI.pm, however, we probably have about 15,000 lines of code to go through and we can't do this before the site roll-out :( In short, I need to get a quick, ugly hack together and then fix this later.

Cheers,
Ovid

Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

Replies are listed 'Best First'.
Re (tilly) 1: How to preserve the value of STDIN
by tilly (Archbishop) on Sep 22, 2000 at 03:22 UTC
    Ick.

    Untested:

    use IO::Scalar; my $data; tie *HACK, 'IO::Scalar', \$data; print HACK <STDIN>; tied(*HACK)->setpos(0); *STDIN = *HACK;
    Now if you don't destroy anything, reading from STDIN gives you what is already in $data which is what was in STDIN.

    UPDATE
    The idea was good but apparently copying tied stuff like that does not maintain the tie. (I shoulda known that, sorry.) Try this code instead:

    use IO::Scalar; $data = join '', <STDIN>; my $s; tie *STDIN, 'IO::Scalar', \$s; print STDIN $data; tied(*STDIN)->setpos(0);
    I tested this by adding
    print $data; print <STDIN>;
    after it, running it, and typing into it.

    My apologies for the initial mistake.

        I don't understand why it works, this is pure magic
Re: How to preserve the value of STDIN
by chromatic (Archbishop) on Sep 22, 2000 at 03:08 UTC
    If you can copy STDIN before anything reads from it, you might have luck. The following code works for me under Linux:
    #!/usr/bin/perl -w use strict; open (NEWIN, "<&STDIN") or die "$!"; open (STDIN, "/dev/null"); print while (<NEWIN>);
    I saved it as 'dup.pl' and called it with cat dup.pl | ./dup.pl.

    (Find out about <& at open.)

    Of course, you can pass a reference to a typeglob containing the NEWIN fh to the CGI.pm constructor...

      This is still only a one-shot deal. <STDIN> now immediately returns an EOF (since we're reading from /dev/null now) as will any subsequent read from <NEWIN> (since we've read everything from what was once STDIN). We're not gaining anything here, in other words. He needs his in-house stuff to parse STDIN *as well* as CGI.pm. Both of them are written to read from STDIN, and only the first will succeed.

      If this were a normal file handle, we could seek(STDIN, 0, 0) to return it to a sane, starting state, but you can't do this with STDIN, because it's actually more like a pipe than a file.

Re: How to preserve the value of STDIN
by Fastolfe (Vicar) on Sep 22, 2000 at 03:08 UTC
    Note that this would still destroy STDIN, but at least you have the data available to the two parts of your application that need it. They just need to be re-written to use <$A> and/or <$B> instead of <STDIN>.

    You could actually even do without the 2nd variable:

    my $A = new IO::String ($data); &exhaust_file_handle($A); # read everything from $A $A->setpos(0); # rewind &also_exhaust($A); # 2nd process reads everything from $A
    Since $A isn't a native file handle, you can't seek() on it, but this will do just as well and should be indistinguishable from your two separate processes.

    You will also need to do this in a BEGIN { } block, so that all of this mangling of STDIN is done before use CGI ($A) is called.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://33582]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (2)
As of 2024-04-19 19:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found