Using fcntl and |= - "Argument .... isn"t numeric in bitwise or ..."
Using fcntl and |= - "Argument .... isn"t numeric in bitwise or ..."
am 29.09.2007 03:15:25 von Jim Cochrane
I'm stumped - trying to get rid of a warning message with code based on
this example snippet from the "Perl Cookbook" book:
use Fcntl;
$lags = "";
fcntl(HANDLE, F_GETFL, $flags) or die "Couldn't get flags: $!\n";
$flags |= O_NONBLOCK;
fcntl(HANDLE, F_SETFL, $flags) or die "Couldn't set flags: $!\n";
(I've typed the above by hand and shortened the error messages - sorry
for any typos.)
I did some searching, including messages about similar problems in this
NG, but failed to find anything relevant.
My code, a short example (included below), produces the warning:
Argument "\0\0\0\0/test1\0\0^P\0\0\0XM-3j^ITLKW \0\0\0^P\0\0\0hM-3..." isn't numeric in bitwise or (|) at ./odd-flags.pl line 13.
This refers to the line:
$flags |= O_NONBLOCK;
I suspect this has something to do with this paragraph from the fcntl
man page:
You donât have to check for "defined" on the return from
"fcntl". Like "ioctl", it maps a 0 return from the system call
into "0 but true" in Perl. This string is true in boolean con-
text and 0 in numeric context. It is also exempt from the nor-
mal -w warnings on improper numeric conversions.
But the last sentence appears to imply the above warning should not
occur.
FYI:
perl -v
This is perl, v5.8.6 built for i386-linux-thread-multi
Is the perl version I'm using mistakenly producing this warning or have
I missed something? If the former - any recommendations on how to
cleanly suppress the warning. (Turn warnings off just for the
"offending" line?)
Here's my example code:
------------------------------------------------------------ ------
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl;
my $file;
open $file, '>/tmp/test1';
my $flags = '';
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
$flags |= O_NONBLOCK;
print "flags: $flags\n";
fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
# Below lines added only to get more info about the problem:
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
$flags |= 8;
print "flags: $flags\n";
fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
------------------------------------------------------------ ------
Oddly, it complains about the first |=, but not the 2nd. It produces
this output (sorry about the odd characters):
Argument "\0\0\0\0/test1\0\0^P\0\0\0XM-cp^ITLKW \0\0\0^P\0\0\0hM-c..." isn't numeric in bitwise or (|) at ./odd-flags.pl line 13.
flags: flags: 2048
flags: 2048flags: 2048flags: 2056
flags: 2056
Thanks for any help or pointers on this!
--
Re: Using fcntl and |= - "Argument .... isn"t numeric in bitwise or ..."
am 29.09.2007 07:33:56 von Ben Morrow
Quoth Jim Cochrane :
>
> I'm stumped - trying to get rid of a warning message with code based on
> this example snippet from the "Perl Cookbook" book:
>
> use Fcntl;
>
> $lags = "";
> fcntl(HANDLE, F_GETFL, $flags) or die "Couldn't get flags: $!\n";
You need to read you systems fcntl(2) as well as the perldocs; at least
on mine, it says
F_GETFL Get descriptor status flags, as described below (arg is
ignored).
So, contrary to the example in perldoc -f fcntl, you need
my $flags = fcntl(HANDLE, F_GETFL);
Ben
Re: Using fcntl and |= - "Argument .... isn"t numeric in bitwise or ..."
am 30.09.2007 09:01:28 von Jim Cochrane
On 2007-09-29, Ben Morrow wrote:
>
> Quoth Jim Cochrane :
>>
>> I'm stumped - trying to get rid of a warning message with code based on
>> this example snippet from the "Perl Cookbook" book:
>>
>> use Fcntl;
>>
>> $lags = "";
>> fcntl(HANDLE, F_GETFL, $flags) or die "Couldn't get flags: $!\n";
>
> You need to read you systems fcntl(2) as well as the perldocs; at least
> on mine, it says
>
> F_GETFL Get descriptor status flags, as described below (arg is
> ignored).
>
> So, contrary to the example in perldoc -f fcntl, you need
>
> my $flags = fcntl(HANDLE, F_GETFL);
>
This appears to be wrong. It looks like fcntl takes 3 arguments with
F_GETFL, even though the 3rd arg is not passed as a reference. (Trying
it with just 2 args -
$flags = fcntl($handle, F_GETFL) or die "Could not get flags: $!";
produces the error:
Not enough arguments for fcntl at ./exp8.pl line 37, near "F_GETFL) "
)
However, it looks like the answer to my question is that the warning
occurs because the example is based on old code that does not 'use
warnings' and thus does not produce a warning message unless 'use
warnings' is added. I found that instead of doing this, which produced
the warning:
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
$flags |= O_NONBLOCK;
fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
doing it this way does not produce a warning:
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
fcntl($file, F_SETFL, $flags | O_NONBLOCK) or die "Could not set flags: $!";
So to answer my own question, the warning is expected and the best way
to get rid of it is to simply use the latter form instead of changing
the value of $flags with |=.
--
Re: Using fcntl and |= - "Argument .... isn"t numeric in bitwiseor ..."
am 30.09.2007 22:40:54 von Big and Blue
Jim Cochrane wrote:
> I'm stumped - trying to get rid of a warning message with code based on
> this example snippet from the "Perl Cookbook" book:
Your problem has nothing at all to do with fcntl
"use strict" and "use warnings" would have shown you the problem.
> $lags = "";
> fcntl(HANDLE, F_GETFL, $flags) or die "Couldn't get flags: $!\n";
> $flags |= O_NONBLOCK;
It's $flags which is undefined. You've set $lags, not $flags (and
setting it to 0 rather than "" would make far more sense).
> You don't have to check for "defined" on the return from
> "fcntl".
You aren't even checking the return result from fcntl. You are just
ignoring it completely (you're calling it in a void context, i.e. not
assigning the return value to anything).
--
Just because I've written it doesn't mean that
either you or I have to believe it.
Re: Using fcntl and |= - "Argument .... isn"t numeric in bitwise or ..."
am 01.10.2007 02:24:37 von Jim Cochrane
On 2007-09-30, Big and Blue wrote:
> Jim Cochrane wrote:
>> I'm stumped - trying to get rid of a warning message with code based on
>> this example snippet from the "Perl Cookbook" book:
>
> Your problem has nothing at all to do with fcntl
>
> "use strict" and "use warnings" would have shown you the problem.
You've missed the mark and have things pretty much reversed. And you
don't appear to have read my original message very well. I'll summarize
what I found, below.
>
>> $lags = "";
>> fcntl(HANDLE, F_GETFL, $flags) or die "Couldn't get flags: $!\n";
>> $flags |= O_NONBLOCK;
You've excerpted my typed-in quote from the Perl Cookbook, rather
than the code at the bottom of my message that I was actually running
(and which does 'use strict' and 'use warnings').
[From my original message: "(I've typed the above by hand and shortened
the error messages - sorry for any typos.)" and "My code, a short example
(included below), produces the warning:
Argument "\0\0\0\0/test1\0\0^P\0\0\0XM-3j^ITLKW \0\0\0^P\0\0\0hM-3..."
isn't numeric in bitwise or (|) at ./odd-flags.pl line 13."
]
>
> It's $flags which is undefined. You've set $lags, not $flags (and
> setting it to 0 rather than "" would make far more sense).
>
>> You don't have to check for "defined" on the return from
>> "fcntl".
>
> You aren't even checking the return result from fcntl. You are just
> ignoring it completely (you're calling it in a void context, i.e. not
> assigning the return value to anything).
If you're going to respond to a message, please read it properly first,
take some time to understand the issue, and do a better job of quoting
from it.
What I found was that the warning message occurs because the 'use
warnings' facility does not like the use of the | operator with the
non-numeric value assigned to the $flags variable by the first fcntl
call. The best solution appears to be to insert a local 'no warnings
"numeric"' line before the "offending" code. (I posted a followup a
couple days ago that incorrectly stated that deleting:
$flags |= O_NONBLOCK;
and instead doing the or in the 2nd fcntl call:
fcntl($file, F_SETFL, $flags | O_NONBLOCK) or die "Could not set flags: $!\n";
got rid of the warning; but it doesn't - I had forgotten to remove the
'no warnings...' line when I tried that.)
For reference, here's my test code posted in my original message:
------------------------------------------------------------ ------
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl;
my $file;
open $file, '>/tmp/test1';
my $flags = '';
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
$flags |= O_NONBLOCK;
print "flags: $flags\n";
fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
# Below lines added only to get more info about the problem:
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
$flags |= 8;
print "flags: $flags\n";
fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
print "flags: $flags\n";
------------------------------------------------------------ ------
--
Re: Using fcntl and |= - "Argument .... isn"t numeric in bitwiseor ..."
am 02.10.2007 10:02:32 von Joe Smith
Jim Cochrane wrote:
> my $flags = '';
> Argument "" isn't numeric in bitwise or ...
That's because you did not put $flags on the left hand side of
an equal sign. Both undef and '0' are legal for |=, '' is not.
> fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
That's not how its documented in "perldoc -f fcntl".
Here's an example of setting a filehandle named "REMOTE" to be
non-blocking at the system level.
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
$flags = fcntl(REMOTE, F_GETFL, 0)
or die "Can't get flags for the socket: $!\n";
$flags = fcntl(REMOTE, F_SETFL, $flags | O_NONBLOCK)
or die "Can't set flags for the socket: $!\n";
That last line in the docs is misleading. It should be:
$value = fcntl(REMOTE, F_SETFL, $flags | O_NONBLOCK)
or die "Can't set flags for the socket: $!\n";
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl;
my $file;
open $file, '>/tmp/test1';
printf "0: O_NONBLOCK = %d = 0x%X, file = %s\n",O_NONBLOCK,O_NONBLOCK,$file;
my $flags;
$flags = fcntl($file, F_GETFL, 0) or die "Could not get flags: $!";
printf "1: flags = 0x%08X\n",$flags;
$flags |= O_NONBLOCK;
printf "2: flags = 0x%08X\n",$flags;
$_ = fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
printf "3: value as string = %s\n",$_;
$flags = fcntl($file, F_GETFL, 0) or die "Could not get flags: $!";
printf "4: flags = 0x%08X\n",$flags;
$flags |= 8;
printf "5: flags = 0x%08X\n",$flags;
$_ = fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
printf "6: value as string = %s\n",$_;
$flags = fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
printf "7: flags = 0x%08X\n",$flags;
print "Setting bit for 8 is ",($flags&8 ? 'supported' : 'not implemented'),
" on $^O\n";
########
0: O_NONBLOCK = 2048 = 0x800, file = GLOB(0x8770c20)
1: flags = 0x00008001
2: flags = 0x00008801
3: value as string = 0 but true
4: flags = 0x00008801
5: flags = 0x00008809
6: value as string = 0 but true
7: flags = 0x00008801
Setting bit for 8 is not implemented on linux
Works as documented.
-Joe
Re: Using fcntl and |= - "Argument .... isn"t numeric in bitwise or ..."
am 03.10.2007 04:35:08 von Jim Cochrane
On 2007-10-02, Joe Smith wrote:
> Jim Cochrane wrote:
>
>> my $flags = '';
>> Argument "" isn't numeric in bitwise or ...
>
> That's because you did not put $flags on the left hand side of
> an equal sign. Both undef and '0' are legal for |=, '' is not.
Duh - I wrote my code based on the example in Perl Cookbook (p. 284).
But I should have noticed that - "$flags = '';" is an empty string, not
a number. I wrongly assumed $flags got its non-numeric value from the
first fcntl call. I need to remember not to take books - even those
with good reputations - as gospel.
Thanks for pointing this out; everyone else who responded missed it.
>
>> fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
>
> That's not how its documented in "perldoc -f fcntl".
>
> Here's an example of setting a filehandle named "REMOTE" to be
> non-blocking at the system level.
>
> use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
>
> $flags = fcntl(REMOTE, F_GETFL, 0)
> or die "Can't get flags for the socket: $!\n";
>
> $flags = fcntl(REMOTE, F_SETFL, $flags | O_NONBLOCK)
> or die "Can't set flags for the socket: $!\n";
>
Thanks; another thing wrong with the Cookbook example, although
'fcntl(REMOTE, F_GETFL, $flags)' version appears to work (I think -
don't have time to test it right now); but the form documented in perldoc
is cleaner.
>
> That last line in the docs is misleading. It should be:
>
> $value = fcntl(REMOTE, F_SETFL, $flags | O_NONBLOCK)
> or die "Can't set flags for the socket: $!\n";
You mean the result is a status value, not a new 'flags' value. OK.
>
>
> #!/usr/bin/perl
> use strict;
> use warnings;
> use Fcntl;
>
> my $file;
> open $file, '>/tmp/test1';
> printf "0: O_NONBLOCK = %d = 0x%X, file = %s\n",O_NONBLOCK,O_NONBLOCK,$file;
>
> my $flags;
> $flags = fcntl($file, F_GETFL, 0) or die "Could not get flags: $!";
> printf "1: flags = 0x%08X\n",$flags;
> $flags |= O_NONBLOCK;
> printf "2: flags = 0x%08X\n",$flags;
> $_ = fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
> printf "3: value as string = %s\n",$_;
>
> $flags = fcntl($file, F_GETFL, 0) or die "Could not get flags: $!";
> printf "4: flags = 0x%08X\n",$flags;
> $flags |= 8;
> printf "5: flags = 0x%08X\n",$flags;
> $_ = fcntl($file, F_SETFL, $flags) or die "Could not set flags: $!";
> printf "6: value as string = %s\n",$_;
>
> $flags = fcntl($file, F_GETFL, $flags) or die "Could not get flags: $!";
> printf "7: flags = 0x%08X\n",$flags;
> print "Setting bit for 8 is ",($flags&8 ? 'supported' : 'not implemented'),
> " on $^O\n";
>
> ########
> 0: O_NONBLOCK = 2048 = 0x800, file = GLOB(0x8770c20)
> 1: flags = 0x00008001
> 2: flags = 0x00008801
> 3: value as string = 0 but true
> 4: flags = 0x00008801
> 5: flags = 0x00008809
> 6: value as string = 0 but true
> 7: flags = 0x00008801
> Setting bit for 8 is not implemented on linux
Cool.
>
>
> Works as documented.
>
> -Joe
Thanks
--