File Coverage

lib/Modern/Open.pm
Criterion Covered Total %
statement 173 209 82.7
branch 34 58 58.6
condition 8 33 24.2
subroutine 32 34 94.1
pod 5 7 71.4
total 252 341 73.9


line stmt bran cond sub pod time code
1             package Modern::Open;
2             ######################################################################
3             #
4             # Modern::Open - Autovivification, Autodie, and 3-args open support
5             #
6             # https://metacpan.org/dist/Modern-Open
7             #
8             # Copyright (c) 2014, 2015, 2018, 2019, 2020, 2021, 2023, 2026 INABA Hitoshi
9             ######################################################################
10              
11 10     10   198155 use 5.00503;
  10         34  
12 10     10   54 use vars qw($VERSION $_fh_seq);
  10         37  
  10         581  
13 10     10   47 use strict;
  10         14  
  10         855  
14 10 50 33 10   358 BEGIN { if ($] < 5.006 && !defined(&warnings::import)) { $INC{'warnings.pm'} = 'stub';
  0         0  
15 0     10   0 eval 'package warnings; sub import {}' } } use warnings; local $^W=1;
  10         78  
  10         33  
  10         1027  
16              
17             $VERSION = '0.15';
18             $VERSION = $VERSION;
19             $_fh_seq = 0;
20              
21 10 100   10   272 BEGIN { pop @INC if $INC[-1] eq '.' } # CVE-2016-1238: Important unsafe module load path flaw
22 10     10   42 use Fcntl;
  10         12  
  10         4268  
23              
24             #---------------------------------------------------------------------
25             sub Modern::Open::confess (@) {
26 22     22 0 33 my $i = 0;
27 22         37 my @confess = ();
28 22         141 while (my($package, $filename, $line, $subroutine) = caller($i)) {
29 66         145 push @confess, "[$i] $filename($line) $subroutine\n";
30 66         280 $i++;
31             }
32 22         130 print STDERR "\n", @_, "\n";
33 22         111 print STDERR CORE::reverse @confess;
34 22         141 die;
35             }
36              
37             #---------------------------------------------------------------------
38             sub Modern::Open::open (*$;$) {
39 34     34 1 1596871 my $handle;
40              
41 34 100       102 if (defined $_[0]) {
42 17         32 Modern::Open::confess "Bare handle no longer supported";
43             }
44             else {
45 17         45 $_fh_seq++;
46 17         52 my $fhn = "Modern::Open::FH::H${_fh_seq}";
47 10     10   62 no strict 'refs';
  10         26  
  10         1039  
48 17         31 $handle = $fhn;
49 17         21 $_[0] = \*{$fhn};
  17         167  
50             }
51              
52 17 50       67 if (@_ >= 4) {
    100          
    50          
53 0         0 Modern::Open::confess "Too many arguments for open";
54             }
55             elsif (@_ == 3) {
56 8         29 my($mode, $filename) = @_[1, 2];
57              
58 8 100       69 if ($mode eq '-|') {
    100          
59 10     10   49 no strict 'refs';
  10         24  
  10         1073  
60 1         2573 my $return = CORE::open($handle, qq{$filename |});
61 1 50 33     37 if ($return or defined wantarray) {
62 1         41 return $return;
63             }
64             else {
65 0         0 Modern::Open::confess "Can't open($_[0],$_[1],$_[2]): $!";
66             }
67             }
68             elsif ($mode eq '|-') {
69 10     10   48 no strict 'refs';
  10         14  
  10         1632  
70 1         3061 my $return = CORE::open($handle, qq{| $filename});
71 1 50 33     52 if ($return or defined wantarray) {
72 1         27 return $return;
73             }
74             else {
75 0         0 Modern::Open::confess "Can't open($_[0],$_[1],$_[2]): $!";
76             }
77             }
78             else {
79 6         30 my %flags = (
80             '<' => O_RDONLY,
81             '>' => O_WRONLY | O_TRUNC | O_CREAT,
82             '>>' => O_WRONLY |O_APPEND | O_CREAT,
83             '+<' => O_RDWR,
84             '+>' => O_RDWR | O_TRUNC | O_CREAT,
85             '+>>' => O_RDWR | O_APPEND | O_CREAT,
86             );
87 6 50       15 if (not exists $flags{$mode}) {
88 0         0 Modern::Open::confess "Unknown open() mode '$mode'";
89             }
90 10     10   54 no strict 'refs';
  10         24  
  10         820  
91 6         7 my $return = CORE::sysopen(*{$handle}, $filename, $flags{$mode});
  6         472  
92 6 50 33     25 if ($return or defined wantarray) {
93 6         27 return $return;
94             }
95             else {
96 0         0 Modern::Open::confess "Can't open($_[0],$_[1],$_[2]): $!";
97             }
98             }
99             }
100             elsif (@_ == 2) {
101 10     10   45 no strict 'refs';
  10         14  
  10         2261  
102 9         7264 my $return = CORE::open($handle, $_[1]);
103 9 50 33     92 if ($return or defined wantarray) {
104 9         87 return $return;
105             }
106             else {
107 0         0 Modern::Open::confess "Can't open($_[0],$_[1]): $!";
108             }
109             }
110             else {
111 0         0 Modern::Open::confess "Not enough arguments for open";
112             }
113             }
114              
115             #---------------------------------------------------------------------
116             sub Modern::Open::opendir (*$) {
117 2     2 1 142518 my $handle;
118              
119 2 100       7 if (defined $_[0]) {
120 1         5 Modern::Open::confess "Bare handle no longer supported";
121             }
122             else {
123 1         3 $_fh_seq++;
124 1         4 my $fhn = "Modern::Open::FH::H${_fh_seq}";
125 10     10   52 no strict 'refs';
  10         26  
  10         680  
126 1         2 $handle = $fhn;
127 1         2 $_[0] = \*{$fhn};
  1         12  
128             }
129              
130 1         2 my $return;
131 10     10   44 { no strict 'refs';
  10         15  
  10         2132  
  1         3  
132 1 50 0     2 if ($return = CORE::opendir(*{$handle}, $_[1])) {
  1 0       82  
133             }
134             elsif (($^O =~ /MSWin32/) and (-d qq{$_[1].})) {
135 0         0 $return = CORE::opendir(*{$handle}, qq{$_[1].});
  0         0  
136             }
137             }
138              
139 1 50 33     8 if ($return or defined wantarray) {
140 1         5 return $return;
141             }
142             else {
143 0         0 Modern::Open::confess "Can't opendir($_[0],$_[1]): $!";
144             }
145             }
146              
147             #---------------------------------------------------------------------
148             sub Modern::Open::sysopen (*$$;$) {
149 2     2 1 148154 my $handle;
150              
151 2 100       5 if (defined $_[0]) {
152 1         6 Modern::Open::confess "Bare handle no longer supported";
153             }
154             else {
155 1         3 $_fh_seq++;
156 1         4 my $fhn = "Modern::Open::FH::H${_fh_seq}";
157 10     10   52 no strict 'refs';
  10         17  
  10         759  
158 1         2 $handle = $fhn;
159 1         2 $_[0] = \*{$fhn};
  1         10  
160             }
161              
162 1 50       8 if (@_ >= 5) {
    50          
    50          
163 0         0 Modern::Open::confess "Too many arguments for sysopen";
164             }
165             elsif (@_ == 4) {
166 10     10   44 no strict 'refs';
  10         51  
  10         1072  
167 0         0 my $return = CORE::sysopen(*{$handle}, $_[1], $_[2], $_[3]);
  0         0  
168 0 0 0     0 if ($return or defined wantarray) {
169 0         0 return $return;
170             }
171             else {
172 0         0 Modern::Open::confess "Can't sysopen($_[0],$_[1],$_[2],$_[3]): $!";
173             }
174             }
175             elsif (@_ == 3) {
176 10     10   70 no strict 'refs';
  10         12  
  10         1787  
177 1         2 my $return = CORE::sysopen(*{$handle}, $_[1], $_[2]);
  1         72  
178 1 50 33     7 if ($return or defined wantarray) {
179 1         4 return $return;
180             }
181             else {
182 0         0 Modern::Open::confess "Can't sysopen($_[0],$_[1],$_[2]): $!";
183             }
184             }
185             else {
186 0         0 Modern::Open::confess "Not enough arguments for sysopen";
187             }
188             }
189              
190             #---------------------------------------------------------------------
191             sub Modern::Open::pipe (**) {
192 2     2 1 141136 my($handle0, $handle1);
193              
194 2 100       7 if (defined $_[0]) {
195 1         8 Modern::Open::confess "Bare handle no longer supported";
196             }
197             else {
198 1         1 $_fh_seq++;
199 1         3 my $fhn0 = "Modern::Open::FH::P${_fh_seq}r";
200 10     10   55 no strict 'refs';
  10         24  
  10         807  
201 1         2 $handle0 = $fhn0;
202 1         1 $_[0] = \*{$fhn0};
  1         10  
203             }
204              
205 1 50       2 if (defined $_[1]) {
206 0         0 Modern::Open::confess "Bare handle no longer supported";
207             }
208             else {
209 1         2 my $fhn1 = "Modern::Open::FH::P${_fh_seq}w";
210 10     10   45 no strict 'refs';
  10         27  
  10         462  
211 1         2 $handle1 = $fhn1;
212 1         2 $_[1] = \*{$fhn1};
  1         3  
213             }
214              
215 10     10   45 no strict 'refs';
  10         14  
  10         1618  
216 1         14 my $return = CORE::pipe(*{$handle0}, *{$handle1});
  1         2  
  1         36  
217 1 50 33     4 if ($return or defined wantarray) {
218 1         4 return $return;
219             }
220             else {
221 0         0 Modern::Open::confess "Can't pipe($_[0],$_[1]): $!";
222             }
223             }
224              
225             #---------------------------------------------------------------------
226             sub Modern::Open::socket (*$$$) {
227 3     3 0 318330 my $handle;
228              
229 3 100       14 if (defined $_[0]) {
230 2         10 Modern::Open::confess "Bare handle no longer supported";
231             }
232             else {
233 1         3 $_fh_seq++;
234 1         4 my $fhn = "Modern::Open::FH::H${_fh_seq}";
235 10     10   55 no strict 'refs';
  10         14  
  10         574  
236 1         3 $handle = $fhn;
237 1         2 $_[0] = \*{$fhn};
  1         13  
238             }
239              
240             # socket doesn't autodie
241 10     10   45 no strict 'refs';
  10         17  
  10         1174  
242 1         3 return CORE::socket(*{$handle}, $_[1], $_[2], $_[3]);
  1         108  
243             }
244              
245             #---------------------------------------------------------------------
246             sub Modern::Open::accept (**) {
247 0     0 1 0 my($handle0, $handle1);
248              
249 0 0       0 if (defined $_[0]) {
250 0         0 Modern::Open::confess "Bare handle no longer supported";
251             }
252             else {
253 0         0 $_fh_seq++;
254 0         0 my $fhn = "Modern::Open::FH::H${_fh_seq}";
255 10     10   62 no strict 'refs';
  10         29  
  10         489  
256 0         0 $handle0 = $fhn;
257 0         0 $_[0] = \*{$fhn};
  0         0  
258             }
259              
260 10     10   49 no strict 'refs';
  10         16  
  10         1062  
261 0         0 my $return = CORE::accept(*{$handle0}, *{$_[1]});
  0         0  
  0         0  
262 0 0 0     0 if ($return or defined wantarray) {
263 0         0 return $return;
264             }
265             else {
266 0         0 Modern::Open::confess "Can't accept($_[0],$_[1]): $!";
267             }
268             }
269              
270             #---------------------------------------------------------------------
271             sub import {
272              
273             # avoid: Can't use string ("main::open") as a symbol ref while "strict refs" in use
274 10     10   44 no strict 'refs';
  10         19  
  10         2594  
275             {
276             # avoid: Prototype mismatch: sub main::open (*;$) vs (*$;$)
277 10     0   73 local $SIG{__WARN__} = sub {};
  10     10   69  
278 10         23 *{caller() . '::open'} = \&Modern::Open::open;
  10         83  
279             }
280 10         19 *{caller() . '::opendir'} = \&Modern::Open::opendir;
  10         37  
281 10         14 *{caller() . '::sysopen'} = \&Modern::Open::sysopen;
  10         24  
282 10         30 *{caller() . '::pipe'} = \&Modern::Open::pipe;
  10         78  
283 10         26 *{caller() . '::socket'} = \&Modern::Open::socket;
  10         84  
284 10         37 *{caller() . '::accept'} = \&Modern::Open::accept;
  10         8320  
285             }
286              
287             1;
288              
289             __END__