Simulating the open() command.

Discussion in 'Perl Misc' started by Chris Heller, Aug 24, 2004.

  1. Chris Heller

    Chris Heller Guest

    Is it possible to write a subroutine in Perl that would act just like
    a call to open()?

    I have a project which currently uses NFS for file storage. This being
    a web project, and NFS being what it is, the decision has been made to
    remove dependancy on NFS. Of course this needs to be done in the
    simplest possible manner, so I've devised a simple file-transfer
    protocol and server and thought it would be great if I could simply
    replace calls to open() and close() with myopen() and myclose().

    Consider this:

    sub myopen(*$$$){
    my ($sh, $fileop, $ip, $port ) = @_;

    socket($sh,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
    ...
    print $sh "$fileop\n";
    ...
    return 1;
    }

    myclose(*){
    my $fh = shift;
    ...
    close($fh);
    }

    The subroutines are declared using prototypes so that they will work
    just like open() and close() do when called with no parens around
    their arguments.

    myopen() takes a bareword, which I wish to turn into a socket handle,
    a string like ">/writetofile" just like open() does, and two
    additional arguments an IP address and a port.

    myclose() is the analog of close() but handles some extra bookkeeping
    and shutsdown the socket if needed.

    Now the trick is, I want myopen() to not have to explicitly return a
    filehandle in the return statement, I want this to work like open().

    So in my code you would see something like this:

    myopen FH,">fileop","127.0.0.1",4556;
    while(<FH>){
    print $_;
    }
    myclose FH;

    From what I've discovered in playing with this code is that the handle
    that I create in myopen() does not exist once I return from the
    subroutine.

    So the question I am stumped with is how can I pass a bareword into a
    sub routine and treat it like a reference so that and changes I make
    to it in the subroutine will persist after I return from that
    subroutine?

    Regards,
    C. Heller
    Chris Heller, Aug 24, 2004
    #1
    1. Advertising

  2. Also sprach Chris Heller:

    > Is it possible to write a subroutine in Perl that would act just like
    > a call to open()?


    Mostly, yes.

    > I have a project which currently uses NFS for file storage. This being
    > a web project, and NFS being what it is, the decision has been made to
    > remove dependancy on NFS. Of course this needs to be done in the
    > simplest possible manner, so I've devised a simple file-transfer
    > protocol and server and thought it would be great if I could simply
    > replace calls to open() and close() with myopen() and myclose().
    >
    > Consider this:
    >
    > sub myopen(*$$$){
    > my ($sh, $fileop, $ip, $port ) = @_;
    >
    > socket($sh,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
    > ...
    > print $sh "$fileop\n";
    > ...
    > return 1;
    > }
    >
    > myclose(*){
    > my $fh = shift;
    > ...
    > close($fh);
    > }
    >
    > The subroutines are declared using prototypes so that they will work
    > just like open() and close() do when called with no parens around
    > their arguments.
    >
    > myopen() takes a bareword, which I wish to turn into a socket handle,
    > a string like ">/writetofile" just like open() does, and two
    > additional arguments an IP address and a port.


    [...]

    > Now the trick is, I want myopen() to not have to explicitly return a
    > filehandle in the return statement, I want this to work like open().


    Using Symbol::qualify_to_ref() should work for you:

    use Symbol;
    ...
    sub myopen (*$$$) {
    my ($sh, $fileop, $ip, $port) = @_;
    my $ref = qualify_to_ref($sh);
    socket $ref, ...;
    ...
    }

    > So in my code you would see something like this:
    >
    > myopen FH,">fileop","127.0.0.1",4556;
    > while(<FH>){
    > print $_;
    > }
    > myclose FH;
    >
    > From what I've discovered in playing with this code is that the handle
    > that I create in myopen() does not exist once I return from the
    > subroutine.


    That is because $sh is a simple lexical variable. If you use such a
    variable as a filehandle, it gets closed once it falls out of scope.
    qualify_to_ref() on the other hand will turn it into a real
    GLOB-reference.

    Tassilo
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
    Tassilo v. Parseval, Aug 24, 2004
    #2
    1. Advertising

  3. Chris Heller

    Greg Bacon Guest

    In article <>,
    Chris Heller <> wrote:

    : [...]
    : So the question I am stumped with is how can I pass a bareword into a
    : sub routine and treat it like a reference so that and changes I make
    : to it in the subroutine will persist after I return from that
    : subroutine?

    Don't forget that you can scribble in other packages:

    use IO::Socket::INET;

    sub myopen(*$$$) {
    my($fh,$fileop,$ip,$port) = @_;

    no strict 'refs';

    my($pkg) = caller;
    my $sym = $pkg . "::" . $fh;

    *$sym = IO::Socket::INET->new(
    PeerAddr => "$ip:$port",
    );

    return unless *{$sym}{IO};

    print { *$sym } "$fileop\n";
    }

    sub myclose(*) {
    no strict 'refs';

    my $fh = shift;

    my($pkg) = caller;
    my $sym = $pkg . "::" . $fh;

    close *$sym;
    }

    Please keep in mind the following advice from the perlstyle manpage:
    "Just because you CAN do something a particular way doesn't mean that
    you SHOULD do it that way."

    Hope this helps,
    Greg
    --
    I write this on July 4, when we celebrate the ouster of a "tyrant" who
    taxed his subjects at the rate of about three percent.
    -- Doug Newman
    Greg Bacon, Aug 24, 2004
    #3
  4. In article <>,
    Chris Heller <> wrote:
    :Is it possible to write a subroutine in Perl that would act just like
    :a call to open()?

    Yes. In fact, instead of writing "myopen", you could override
    open() itself within your package, with your open() calling
    CORE::eek:pen() if you need to have the "real" open do something
    for you.


    :I have a project which currently uses NFS for file storage. This being
    :a web project, and NFS being what it is, the decision has been made to
    :remove dependancy on NFS. Of course this needs to be done in the
    :simplest possible manner, so I've devised a simple file-transfer
    :protocol and server and thought it would be great if I could simply
    :replace calls to open() and close() with myopen() and myclose().

    Consider using nget or curl instead of writing your own file
    transport protocols. But it depends in part on whether your
    application just needs to read the file, or needs to be able
    to update it.

    If it needs to be able to update the file, then consider looking at the
    perltie documentation for information on how to tie a filehandle so
    that behind the scenes you can substitute your own remote seek/read
    seek/write routines.
    --
    Cottleston, Cottleston, Cottleston pie.
    A bird can't whistle and neither can I. -- Pooh
    Walter Roberson, Aug 24, 2004
    #4
  5. Chris Heller

    Chris Heller Guest

    Tassilo,

    I tried your approach and it seems to work to a point, but I am
    noticing some strange effects. Perhaps this would be better in a new
    message, but I'll post here since it is realted to my original
    question still.

    here is the code as it stands now:

    sub myopen(*$$$$){
    my ($fh, $fileop, $ip, $port) = @_;
    my $fhr = qualify_to_ref($fh);

    socket($fhr, PF_INET, SOCK_STREAM, (getprotobyname('tcp))[2]);
    ...
    print $fhr "$fileop\n";
    print "ERROR: Socket closed in myopen()\n" if (! -s $fhr);
    return 1;
    }

    sub myclose(*){
    my $fh = shift;
    my $fhr = qualify_to_ref($fh);

    print $fhr "EOT\n"; # End of Transmission Delimiter
    close($fhr);
    return 1;
    }

    and my little test app does this:

    myopen SKT, ">writeop", $ip, $port;
    print SKT "LINE1\n";
    print SKT "LINE2\n";
    myclose(SKT);

    The strangeness comes when I watch my server in the debugger, and
    watch how the perl script operates and errors.

    In the myopen() command, the line:

    print "ERROR: Socket closed in myopen()\n" if (! -s $fhr);

    executes, and the error message is printed, indicating that the socket
    is now closed.

    This seems to be the case because in the test script (running perl -w)
    the two print commands both warn that they are printing on a unopened
    filehandle SKT.

    But when I get into myclose() the line:

    print $fhr "EOT\n";

    does not print such a warning, and watching the data come to my server
    the string "EOT" does pass across the wire!

    So, it seems that I am able to create an open filehandle in myopen(),
    which is good, but when I return from myopen() that filehandle appears
    closed to perl, not so good, but when I then enter myclose() that same
    filehandle is once again open and things continue on accordingly!

    How can this be? Shouldn't the filehandle be closed in myclose()?

    -Chris
    Chris Heller, Aug 25, 2004
    #5
  6. Chris Heller

    Chris Heller Guest

    Well,

    I managed to answer my own question and solve the problem.

    It was a case of not using qualify_to_ref() fully.

    As you see my examples all do something like:

    qualify_to_ref($fh);

    when they really needed to be this:

    qualify_to_ref($fh, scalar caller);

    That makes all the difference.

    Thanks for everyone who suggested solutions to my problem, my
    understanding of Perl is a little greater now.

    -Chris
    Chris Heller, Aug 26, 2004
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DG
    Replies:
    3
    Views:
    439
  2. Modukuri
    Replies:
    7
    Views:
    3,150
    Marcus Harnisch
    Jun 1, 2004
  3. Drew
    Replies:
    1
    Views:
    518
    wieli1
    Jul 26, 2004
  4. Jeremy Webb
    Replies:
    2
    Views:
    2,750
    Jeremy Webb
    Oct 23, 2004
  5. Anton Pervukhin
    Replies:
    5
    Views:
    5,419
    Victor Bazarov
    May 11, 2005
Loading...

Share This Page