NAME
Errno::AnyString - put arbitrary strings in $!
VERSION
Version 1.00
SYNOPSIS
Errno::AnyString
allows you to place an arbitrary error message in the special $!
variable, without disrupting $!
's ability to pick up the result of the next system call that sets errno
.
It is useful if you are writing code that reports errors by setting $!
, and none of the standard system error messages fit.
use Errno qw/EIO/;
use Errno::AnyString qw/custom_errstr/;
$! = custom_errstr "My hovercraft is full of eels";
print "$!\n"; # prints My hovercraft is full of eels
my $saved_errno = $!;
open my $fh, "<", "/no/such/file";
print "$!\n"; # prints No such file or directory
$! = EIO;
print "$!\n"; # prints Input/output error
$! = $saved_errno;
print "$!\n"; # prints My hovercraft is full of eels
You can also set the error strings for particular error numbers, for the lifetime of the Perl interpreter:
use Errno::AnyString qw/register_errstr/;
register_errstr "Wetware failure", 339864;
$! = 339864;
print "$!\n"; # prints Wetware failure
BACKGROUND
Perl's special $!
variable provides access to errno
, the "error number", which is an integer variable used by C library functions to record what went wrong when they fail. See "ERRNO" in perlvar and Errno.
There is a fixed error message for each errno
value in use, and a C library function to translate errno
values into error messages. The magical $!
variable always holds the current value of errno
if you use it in a numeric context, and the corresponding error message if you use it in a string context.
open my $fh, "<", "/no/such/file"; # the failing open sets errno to 2
my $errno = $! + 0; # $errno now contains 2
my $err = "$!"; # $err now contains "No such file or directory"
You can also assign a number to $!
, to set the value of errno
. An errno
value of 22 means "invalid argument", so:
$! = 22;
$errno = $! + 0; # $errno now contains 22
$err = "$!"; # $err now contains "Invalid argument"
What you can't do however is assign a string of your own choice to $!
. If you try, Perl just converts your string to an integer as best it can and puts that in errno
.
$! = "You broke it";
# gives an "Argument isn't numeric" warning and sets errno to 0
DESCRIPTION
Errno::AnyString
allows you to set the error message strings that correspond to particular errno
values. It makes a change to the $!
magic so that the correct string is returned when errno
takes a value for which a string has been registered. The change to $!
is global and lasts until the Perl interpreter exits.
EXPORTS
Nothing is exported by default. The following are available for export.
CUSTOM_ERRSTR_ERRNO
A constant with the value 458513437. This is the errno
value used by this module to indicate that a custom error string set with custom_errstr() is active. This value was chosen at random, to avoid picking an errno
value that something else uses.
custom_errstr ( ERROR_STRING )
Returns a value which will set the specified custom error string when assigned to $!
.
The returned value is actually a dual valued scalar with CUSTOM_ERRSTR_ERRNO
as its numeric value and the specified error string as its string value. It's not just magical variables like $!
that can hold a number and a string at the same time, ordinary Perl scalars can do it as well. See "dualvar" in Scalar::Util.
With Errno::AnyString
loaded, the $!
magic responds specially to a scalar with a numeric value of CUSTOM_ERRSTR_ERRNO being assigned to $!
: the string value of the scalar gets recorded as the registered string for errno
value CUSTOM_ERRSTR_ERRNO, replacing any previous registered string for that value.
This way of setting the custom error string was chosen because it works well with code that saves and restores the value of $!
.
$! = custom_errstr "Test string";
my $saved_errno = $!;
do_other_things();
$! = $saved_errno;
print "$!\n"; # prints Test string
When $!
is copied to $saved_errno
, $saved_errno
becomes dual valued with a number value of CUSTOM_ERRSTR_ERRNO and a string value of "Test string". When $saved_errno
gets copied back to $!
at the end, the number value of CUSTOM_ERRSTR_ERRNO triggers the modified $!
magic to register the string value of "Test string" as the custom error string for CUSTOM_ERRSTR_ERRNO.
This is important because code called from within do_other_things() might itself use custom_errstr() to set custom error strings, overwriting the registered error string of "Test string". Since $saved_errno
saves the error message string as well as the errno
value, the $!
magic can put the correct string back in place when the $saved_errno
value is restored.
register_errstr ( ERROR_STRING [,ERRNO_VALUE] )
register_errstr() can be used in a similar way to custom_errstr():
$! = register_errstr "An error string";
The difference is that register_errstr() permanently (i.e. for the lifetime of the Perl interpreter) assigns an errno
value to that error string. The error string is stored away, and will be used as the string value of $!
any time that errno
value is set in future. By default, register_errstr() picks a large errno
value that it has not yet assigned to any other string.
If you call register_errstr() repeatedly with the same error string, it will notice and use the same errno
value each time. That means it's safe to do something like:
$! = register_errstr "Too many foos defined";
in code that could be called a large number of times, and register_errstr() will store only one copy of the string and use up only one errno
value.
You can specify the errno
value to use as a second parameter to register_errstr(), for example:
$! = register_errstr "my error string", 999999;
This sets the error string for errno
value 999999 (replacing any previously set error string for 999999) and assigns it to $!
. You can also call register_errstr() simply to register a bunch of new error codes, without assigning the return value to $!
each time:
register_errstr "Invalid foodb file", -20000;
register_errstr "Invalid foodb parameter", -20001;
register_errstr "foodb out of key slots", -20002;
# ...
$! = -20001;
print "$!\n"; # prints Invalid foodb parameter
It is also possible to use register_errstr() to replace the standard system error messages. For example, to replace the "Permission denied" message;
use Errno qw/EACCES/;
register_errstr "I'm sorry, Dave. I'm afraid I can't do that", EACCES;
open my $fh, ">/no_permission_to_write_here";
print "$!\n"; prints "I'm sorry, Dave. I'm afraid I can't do that"
This is not something I'd recommend, as it's likely to cause confusion. In general, when specifying the errno
value to register_errstr() one should take care to avoid values that are likely to be used for any other purpose.
Internally, the error strings registered by register_errstr() are kept in the %Errno::AnyString::Errno2Errstr
hash. You shouldn't go poking around in this hash yourself, but by localising it you can limit the scope of a register_errstr() registration:
{
local %Errno::AnyString::Errno2Errstr = %Errno::AnyString::Errno2Errstr;
register_errstr "I'm sorry, Dave. I'm afraid I can't do that", EACCES;
# here you have a silly error message in place of "Permission denied"
}
# here sanity is restored
INTER-OPERATION
This section is aimed at the authors of other modules that alter $!
's behaviour, as a guide to ensuring clean inter-operation between Errno::AnyString and your module.
Errno::AnyString works by adding two instances of uvar magic to $!
, one at the head of the list and one at the tail. It does not modify or remove any existing magic from $!
. It should inter-operate cleanly with anything else that adds more magic to $!
, so long magic is added in a way that preserves existing uvar magic.
Emptying the %Errno::AnyString::Errno2Errstr
hash effectively turns off this module's interference with $!
, so you can get a "real" $!
value with:
my $e = do { local %Errno::AnyString::Errno2Errstr ; $! };
AUTHOR
Dave Taylor, <dave.taylor.cpan at gmail.com>
BUGS AND LIMITATIONS
C LEVEL STRERROR CALLS
If C level code attempts to get a textual error message based on errno
while a custom error string is set, it will get something like the following, depending on the platform:
Unknown error 458513437
PURE NUMERIC RESTORE
If the string part of a saved custom_errstr() $!
value is lost, then restoring that value to $!
restores the string most recently set with custom_errstr(), which is not necessarily the string that was set when the $!
value was saved.
$! = custom_errstr "String 1";
my $saved_errno = 0 + $!;
$! = custom_errstr "String 2";
$! = $saved_errno;
print "$!\n"; # prints String 2
Note that the Perl code that saved the error number had to go out of its way to discard the string part of $!
, so I think this combination is fairly unlikely in practice.
Error strings set with register_errstr() are not effected by this issue, since each gets its own unique errno
value. For this reason, register_errstr() should be used in preference to custom_errstr() if you have a small number of fixed error strings:
$! = register_errstr "Attempt to frob without a foo"; # good
However, register_errstr() uses up an errno
value and permanently stores the string each time it is called with a string it has not seen before. If your code could generate a large number of different error strings over the lifetime of the Perl interpreter, then using register_errstr() could cost a lot of memory. In such cases, custom_errstr() would be a better choice.
$! = register_errstr "failed at $line in $file: $why"; # less good
TAINT MODE
I'm currently unable to find a good way to propagate the taintedness of custom error strings through $!
, due to an interaction between taint magic, $!
's dualvar behaviour and the SvPOK flag in some Perl versions. If Perl is in taint mode then passing a tainted error string to custom_errstr() or register_errstr() will cause an immediate croak with the message:
Tainted error string used with Errno::AnyString
OTHER BUGS
Please report any other bugs or feature requests to bug-errno-anystring at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Errno::AnyString. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Errno::AnyString
You can also look for information at:
RT: CPAN's request tracker
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
SEE ALSO
Errno, "ERRNO" in perlvar, Scalar::Util, perlguts
COPYRIGHT & LICENSE
Copyright 2009 Dave Taylor, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.