File Coverage

blib/lib/Errno/AnyString.pm
Criterion Covered Total %
statement 27 27 100.0
branch 8 8 100.0
condition n/a
subroutine 8 8 100.0
pod 3 3 100.0
total 46 46 100.0


line stmt bran cond sub pod time code
1             package Errno::AnyString;
2 54     54   6265541 use strict;
  54         142  
  54         1798  
3 54     54   285 use warnings;
  54         101  
  54         2898  
4              
5             =head1 NAME
6              
7             Errno::AnyString - put arbitrary strings in $!
8              
9             =head1 VERSION
10              
11             Version 1.03
12              
13             =cut
14              
15             our $VERSION = '1.03';
16              
17             =head1 SYNOPSIS
18              
19             C allows you to place an arbitrary error message in the special C<$!> variable, without disrupting C<$!>'s ability to pick up the result of the next system call that sets C.
20              
21             It is useful if you are writing code that reports errors by setting C<$!>, and none of the standard system error messages fit.
22              
23             use Errno qw/EIO/;
24             use Errno::AnyString qw/custom_errstr/;
25              
26             $! = custom_errstr "My hovercraft is full of eels";
27             print "$!\n"; # prints My hovercraft is full of eels
28              
29             my $saved_errno = $!;
30              
31             open my $fh, "<", "/no/such/file";
32             print "$!\n"; # prints No such file or directory
33              
34             $! = EIO;
35             print "$!\n"; # prints Input/output error
36              
37             $! = $saved_errno;
38             print "$!\n"; # prints My hovercraft is full of eels
39              
40             You can also set the error strings for particular error numbers, for the lifetime of the Perl interpreter:
41              
42             use Errno::AnyString qw/register_errstr/;
43              
44             register_errstr "Wetware failure", 339864;
45              
46             $! = 339864;
47             print "$!\n"; # prints Wetware failure
48              
49              
50              
51             =head1 BACKGROUND
52              
53             Perl's special C<$!> variable provides access to C, the "error number", which is an integer variable used by C library functions to record what went wrong when they fail. See L and L.
54              
55             There is a fixed error message for each C value in use, and a C library function to translate C values into error messages. The magical C<$!> variable always holds the current value of C if you use it in a numeric context, and the corresponding error message if you use it in a string context.
56              
57             open my $fh, "<", "/no/such/file"; # the failing open sets errno to 2
58             my $errno = $! + 0; # $errno now contains 2
59             my $err = "$!"; # $err now contains "No such file or directory"
60              
61             You can also assign a number to C<$!>, to set the value of C. An C value of 22 means "invalid argument", so:
62              
63             $! = 22;
64             $errno = $! + 0; # $errno now contains 22
65             $err = "$!"; # $err now contains "Invalid argument"
66              
67             What you can't do however is assign a string of your own choice to C<$!>. If you try, Perl just converts your string to an integer as best it can and puts that in C.
68              
69             $! = "You broke it";
70             # gives an "Argument isn't numeric" warning and sets errno to 0
71              
72             =head1 DESCRIPTION
73              
74             C allows you to set the error message strings that correspond to particular C values. It makes a change to the C<$!> magic so that the correct string is returned when C takes a value for which a string has been registered. The change to C<$!> is global and lasts until the Perl interpreter exits.
75              
76             =cut
77              
78 54     54   269 use Exporter;
  54         116  
  54         1852  
79 54     54   288 use Carp;
  54         93  
  54         3633  
80 54     54   295 use Scalar::Util qw/dualvar tainted/;
  54         143  
  54         26601  
81              
82             require XSLoader;
83             XSLoader::load('Errno::AnyString', $VERSION);
84              
85             our @ISA = qw/Exporter/;
86             our @EXPORT_OK = qw/custom_errstr register_errstr CUSTOM_ERRSTR_ERRNO/;
87              
88             our (%Errno2Errstr, %_string2errno);
89              
90             Errno::AnyString::_install_my_magic($!);
91              
92             =head1 EXPORTS
93              
94             Nothing is exported by default. The following are available for export.
95              
96             =head2 CUSTOM_ERRSTR_ERRNO
97              
98             A constant with the value 458513437. This is the C 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 C value that something else uses.
99              
100             =cut
101              
102 480     480 1 137618 sub CUSTOM_ERRSTR_ERRNO () { return 458513437; }
103              
104             our $_next_registered_errno = CUSTOM_ERRSTR_ERRNO() + 1;
105              
106             =head2 custom_errstr ( ERROR_STRING )
107              
108             Returns a value which will set the specified custom error string when assigned to C<$!>.
109              
110             The returned value is actually a dual valued scalar with C as its numeric value and the specified error string as its string value. It's not just magical variables like C<$!> that can hold a number and a string at the same time, ordinary Perl scalars can do it as well. See L.
111              
112             With C loaded, the C<$!> magic responds specially to a scalar with a numeric value of CUSTOM_ERRSTR_ERRNO being assigned to C<$!>: the string value of the scalar gets recorded as the registered string for C value CUSTOM_ERRSTR_ERRNO, replacing any previous registered string for that value.
113              
114             This way of setting the custom error string was chosen because it works well with code that saves and restores the value of C<$!>.
115              
116             $! = custom_errstr "Test string";
117              
118             my $saved_errno = $!;
119             do_other_things();
120             $! = $saved_errno;
121              
122             print "$!\n"; # prints Test string
123              
124             When C<$!> is copied to C<$saved_errno>, C<$saved_errno> becomes dual valued with a number value of CUSTOM_ERRSTR_ERRNO and a string value of "Test string". When C<$saved_errno> gets copied back to C<$!> at the end, the number value of CUSTOM_ERRSTR_ERRNO triggers the modified C<$!> magic to register the string value of "Test string" as the custom error string for CUSTOM_ERRSTR_ERRNO.
125              
126             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 C<$saved_errno> saves the error message string as well as the C value, the C<$!> magic can put the correct string back in place when the C<$saved_errno> value is restored.
127              
128             =cut
129              
130             sub custom_errstr ($) {
131 202 100   202 1 5414829 tainted $_[0] and croak "Tainted error string used with Errno::AnyString";
132              
133 198         559 return dualvar CUSTOM_ERRSTR_ERRNO, "$_[0]";
134             }
135              
136             =head2 register_errstr ( ERROR_STRING [,ERRNO_VALUE] )
137              
138             register_errstr() can be used in a similar way to custom_errstr():
139              
140             $! = register_errstr "An error string";
141              
142             The difference is that register_errstr() permanently (i.e. for the lifetime of the Perl interpreter) assigns an C value to that error string. The error string is stored away, and will be used as the string value of C<$!> any time that C value is set in future. By default, register_errstr() picks a large C value that it has not yet assigned to any other string.
143              
144             If you call register_errstr() repeatedly with the same error string, it will notice and use the same C value each time. That means it's safe to do something like:
145              
146             $! = register_errstr "Too many foos defined";
147              
148             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 C value.
149              
150             You can specify the C value to use as a second parameter to register_errstr(), for example:
151              
152             $! = register_errstr "my error string", 999999;
153              
154             This sets the error string for C value 999999 (replacing any previously set error string for 999999) and assigns it to C<$!>. You can also call register_errstr() simply to register a bunch of new error codes, without assigning the return value to C<$!> each time:
155              
156             register_errstr "Invalid foodb file", -20000;
157             register_errstr "Invalid foodb parameter", -20001;
158             register_errstr "foodb out of key slots", -20002;
159              
160             # ...
161              
162             $! = -20001;
163             print "$!\n"; # prints Invalid foodb parameter
164              
165             It is also possible to use register_errstr() to replace the standard system error messages. For example, to replace the "Permission denied" message;
166              
167             use Errno qw/EACCES/;
168             register_errstr "I'm sorry, Dave. I'm afraid I can't do that", EACCES;
169              
170             open my $fh, ">/no_permission_to_write_here";
171             print "$!\n"; prints "I'm sorry, Dave. I'm afraid I can't do that"
172              
173             This is not something I'd recommend, as it's likely to cause confusion. In general, when specifying the C value to register_errstr() one should take care to avoid values that are likely to be used for any other purpose.
174              
175             Internally, the error strings registered by register_errstr() are kept in the C<%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:
176            
177             {
178             local %Errno::AnyString::Errno2Errstr = %Errno::AnyString::Errno2Errstr;
179              
180             register_errstr "I'm sorry, Dave. I'm afraid I can't do that", EACCES;
181              
182             # here you have a silly error message in place of "Permission denied"
183             }
184             # here sanity is restored
185              
186             =cut
187              
188             sub register_errstr ($;$) {
189 40148     40148 1 340070 my ($str, $num) = @_;
190              
191 40148 100       99316 tainted $str and croak "Tainted error string used with Errno::AnyString";
192              
193 40138 100       69635 unless (defined $num) {
194 92         189 $num = $_string2errno{$str};
195 92 100       231 unless (defined $num) {
196 64         106 $num = $_next_registered_errno++;
197 64         178 $_string2errno{$str} = $num;
198             }
199             }
200 40138         116903 $Errno2Errstr{$num} = "$str";
201              
202 40138         107649 return dualvar $num, $str;
203             }
204              
205             =head1 INTER-OPERATION
206              
207             This section is aimed at the authors of other modules that alter C<$!>'s behaviour, as a guide to ensuring clean inter-operation between Errno::AnyString and your module.
208              
209             Errno::AnyString works by adding two instances of uvar magic to C<$!>, one at the head of the list and one at the tail. It does not modify or remove any existing magic from C<$!>. It should inter-operate cleanly with anything else that adds more magic to C<$!>, so long magic is added in a way that preserves existing uvar magic.
210              
211             Emptying the C<%Errno::AnyString::Errno2Errstr> hash effectively turns off this module's interference with C<$!>, so you can get a "real" C<$!> value with:
212              
213             my $e = do { local %Errno::AnyString::Errno2Errstr ; $! };
214              
215             =head1 AUTHOR
216              
217             Dave Taylor, C<< >>
218              
219             =head1 BUGS AND LIMITATIONS
220              
221             =head2 C LEVEL STRERROR CALLS
222              
223             If C level code attempts to get a textual error message based on C while a custom error string is set, it will get something like the following, depending on the platform:
224              
225             Unknown error 458513437
226              
227             =head2 PURE NUMERIC RESTORE
228              
229             If the string part of a saved custom_errstr() C<$!> value is lost, then restoring that value to C<$!> restores the string most recently set with custom_errstr(), which is not necessarily the string that was set when the C<$!> value was saved.
230              
231             $! = custom_errstr "String 1";
232             my $saved_errno = 0 + $!;
233              
234             $! = custom_errstr "String 2";
235              
236             $! = $saved_errno;
237             print "$!\n"; # prints String 2
238              
239             Note that the Perl code that saved the error number had to go out of its way to discard the string part of C<$!>, so I think this combination is fairly unlikely in practice.
240              
241             Error strings set with register_errstr() are not effected by this issue, since each gets its own unique C value. For this reason, register_errstr() should be used in preference to custom_errstr() if you have a small number of fixed error strings:
242              
243             $! = register_errstr "Attempt to frob without a foo"; # good
244              
245             However, register_errstr() uses up an C 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.
246              
247             $! = register_errstr "failed at $line in $file: $why"; # less good
248              
249             =head2 TAINT MODE
250              
251             I'm currently unable to find a good way to propagate the taintedness of custom error strings through C<$!>, due to an interaction between taint magic, C<$!>'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:
252              
253             Tainted error string used with Errno::AnyString
254              
255             =head2 OTHER BUGS
256              
257             Please report any other bugs or feature requests to C, or through
258             the web interface at L. I will be notified, and then you'll
259             automatically be notified of progress on your bug as I make changes.
260              
261             =head1 SUPPORT
262              
263             You can find documentation for this module with the perldoc command.
264              
265             perldoc Errno::AnyString
266              
267             You can also look for information at:
268              
269             =over 4
270              
271             =item * RT: CPAN's request tracker
272              
273             L
274              
275             =item * AnnoCPAN: Annotated CPAN documentation
276              
277             L
278              
279             =item * CPAN Ratings
280              
281             L
282              
283             =item * Search CPAN
284              
285             L
286              
287             =back
288              
289             =head1 SEE ALSO
290              
291             L, L, L, L
292              
293             =head1 COPYRIGHT & LICENSE
294              
295             Copyright 2009 Dave Taylor, all rights reserved.
296              
297              
298             This program is free software; you can redistribute it and/or modify it
299             under the same terms as Perl itself.
300              
301             =cut
302              
303             1; # End of Errno::AnyString