Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

F_GETFL and Win32

by dragonchild (Archbishop)
on Mar 08, 2006 at 02:58 UTC ( #535091=perlquestion: print w/replies, xml ) Need Help??
dragonchild has asked for the wisdom of the Perl Monks concerning the following question:

(This is yet another reason why I hate programming for Win32, even if only through CPAN.)

In DBM::Deep 0.98 and above, we added the feature that you could pass in your own filehandle instead of a filename. (This allows you to use the *DATA filehandle as a DBM::Deep file.) The only issue is that DBM::Deep opens its filehandles as read-write handles. Potentially, you could pass us a read-only filehandle. (I'm not even going to comment on the stupidity of passing a write-only filehandle to DBM::Deep.)

If you do, then accidentally try to modify the data, then a warning gets popped up in print() saying "Cannot print to a closed filehandle". Fatal doesn't work because print() cannot be overridden. While I could trap the warning, I'd still prefer to detect the fact that the filehandle isn't writable and throw an error.

I found the following code somewhere on Perlmonks (Thanks, Zaxo!) and it does the trick:

sub _is_writable { my $fh = shift; (O_WRONLY | O_RDWR) & fcntl( $fh, F_GETFL, my $slush = 0); }
The code works great . . . on systems whose Fcntl have defined F_GETFL. Unfortunately, that doesn't seem to include Win32 (at least not for ActiveState 5.8.6).

Other than disabling that function for Win32, how should I go about fixing this problem?

Update: Zaxo's code is found here

My criteria for good software:
  1. Does it work?
  2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

Replies are listed 'Best First'.
Re: F_GETFL and Win32
by PodMaster (Abbot) on Mar 08, 2006 at 04:40 UTC
    fcntl is not supported on win32 (see perlport).

    You might try using Win32API::File or simply try printing

    sub _is_writable { my $fh = shift; return eval { defined print { $fh } ''; }; }
    though that may not be desireable.

    update: It just dawned on me that printing on a CLOSED filehandle is different error, than simply a filehandle thats not opened for writing, in which case you want to use the fileno function.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: F_GETFL and Win32
by BrowserUk (Pope) on Mar 08, 2006 at 04:56 UTC

    This will return the open mode for a given Perl filehandle as a number.

    • fmode($fh) & 1 and print 'is readonly';
    • fmode($fh) & 2 and print 'is writeonly';
    • fmode($fh) & 128 and print 'is readwrite';
    #! perl -slw use strict; use Inline C => 'DATA', NAME => 'fmode', CLEAN_AFTER_BUILD => 0; open FILE, $ARGV[0] or die "'$ARGV[0]:$!"; printf "%x\n", fmode( \*FILE ); __DATA__ C:\test>fmode "<junk.dat" 1 C:\test>fmode ">junk.dat" 2 C:\test>fmode ">>junk.dat" 2 C:\test>fmode "+<junk.dat" 80 C:\test>fmode "+>junk.dat" 80 C:\test>fmode "+>>junk.dat" 80 __C__ int fmode( FILE *stream ) { return stream->_flag; }

    In theory you could grab the XS code generated by Inline::C and form that into a module (Win32::Fmode?) for distribution--but I've never managed to get that to work. Everytime I've tried, xsubpp bellyaches about being unable to parse stuff:

    C:\Perl\bin\perl.exe C:\Perl\lib\ExtUtils/xsubpp -typemap C:\Perl\lib\ExtUtils\typemap Fmode.xs > Fmode.xsc && C:\Perl\bin\perl.exe -MExtUtils::Command -e mv Fmode.xsc Fmode.c Error: Cannot parse function definition from 'fmode( FILE *stream ) {' in Fmode.xs, line 12

    And since none {{censored}} ....

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      That process you describe works fine for me - I don't know why you would be getting the error you reported. (I wonder if it was a deficiency in the typemaps at the time.) The XS file should look like this:
      #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int fmode( FILE *stream ) { return stream->_flag; } MODULE = Win32::Fmode PACKAGE = Win32::Fmode PROTOTYPES: DISABLE int fmode (stream) FILE *stream
      If it were a portable cross-platform solution I'd put it on cpan (though not under the Win32 namespace, of course) .... pity ...


        I eventually got it to go(*) and I have placed it on cpan as Win32::Fmode.

        I'm not sure what I was doing wrong to be honest, but doing anything with XS seems to a bit of a trial and error process for me. I usually manage to track down my misunderstandings and once I know what they are, I can normally find the text in perlxs or perlxstut that would have allowed me to avoid the mistake had I recognised the significance of it.

        If it were a portable cross-platform solution, I'd put it on cpan ...

        Do the field names of the _iobuf struct vary by platform? I haven't verified my memory, but I seem to recall using a macro to obtain the file mode directly from the FILE* years ago under HP?

        (*)The docs appear to be quite thorough to me, but just rather dense and understated such that you (I) have to make the mistakes and then go looking for the breif mention of the cause before recognising it as such. I'm not sure what can be done about that?

        Have you ever read a graduate thesis on some deep Physics or Chemistry theory, and then later read a description of the same thing by a (good) professor. that really understands and has internalised the same material.

        The former usually touches on everything in precise detail--crosses every T and dots every I--but somehow at the end of it, whilst you may be familiar with all the terminology, and able to quickly find an accurate description of everything, you end up little the wiser because there is lacking an explantion of the underlying causes/concepts.

        Conversely, the latter will often skip much of the detail, by referring you to existing reference material, but it will explain, by simplification and/or analogy, the underlying concepts directly and clearly. You come away with a much better feeling of understanding, even if you need to go elsewhere for precise details.

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://535091]
Approved by GrandFather
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2017-12-11 03:17 GMT
Find Nodes?
    Voting Booth?
    What programming language do you hate the most?

    Results (286 votes). Check out past polls.