File Coverage

blib/lib/File/Slurp.pm
Criterion Covered Total %
statement 241 261 92.3
branch 111 124 89.5
condition 39 51 76.4
subroutine 22 22 100.0
pod 7 7 100.0
total 420 465 90.3


line stmt bran cond sub pod time code
1             package File::Slurp;
2              
3 32     32   511556 use strict;
  32         259  
  32         825  
4 32     32   145 use warnings ;
  32         44  
  32         1366  
5              
6             our $VERSION = '9999.32';
7             $VERSION = eval $VERSION;
8              
9 32     32   152 use Carp ;
  32         45  
  32         1910  
10 32     32   159 use Exporter qw(import);
  32         45  
  32         1025  
11 32     32   150 use Fcntl qw( :DEFAULT ) ;
  32         48  
  32         9501  
12 32     32   203 use File::Basename ();
  32         56  
  32         521  
13 32     32   153 use File::Spec;
  32         58  
  32         855  
14 32     32   7165 use File::Temp qw(tempfile);
  32         225109  
  32         1541  
15 32     32   241 use IO::Handle ();
  32         59  
  32         568  
16 32     32   13895 use POSIX qw( :fcntl_h ) ;
  32         176889  
  32         150  
17 32     32   48592 use Errno ;
  32         63  
  32         16061  
18              
19             my @std_export = qw(
20             read_file
21             write_file
22             overwrite_file
23             append_file
24             read_dir
25             ) ;
26              
27             my @edit_export = qw(
28             edit_file
29             edit_file_lines
30             ) ;
31              
32             my @abbrev_export = qw(
33             rf
34             wf
35             ef
36             efl
37             ) ;
38              
39             our @EXPORT_OK = (
40             @edit_export,
41             @abbrev_export,
42             qw(
43             slurp
44             prepend_file
45             ),
46             ) ;
47              
48             our %EXPORT_TAGS = (
49             'all' => [ @std_export, @edit_export, @abbrev_export, @EXPORT_OK ],
50             'edit' => [ @edit_export ],
51             'std' => [ @std_export ],
52             'abr' => [ @abbrev_export ],
53             ) ;
54              
55             our @EXPORT = @std_export ;
56              
57             my $max_fast_slurp_size = 1024 * 100 ;
58              
59             my $is_win32 = $^O =~ /win32/i ;
60              
61             *slurp = \&read_file ;
62             *rf = \&read_file ;
63              
64             sub read_file {
65 234     234 1 198050 my $file_name = shift;
66 234 100       1169 my $opts = (ref $_[0] eq 'HASH') ? shift : {@_};
67             # options we care about:
68             # array_ref binmode blk_size buf_ref chomp err_mode scalar_ref
69              
70             # let's see if we have a stringified object before doing anything else
71             # We then only have to deal with when we are given a file handle/globref
72 234 100       751 if (ref($file_name)) {
73 16         173 my $ref_result = _check_ref($file_name, $opts);
74 16 50       176 if (ref($ref_result)) {
75 0         0 @_ = ($opts, $ref_result);
76 0         0 goto &_error;
77             }
78 16 100       122 $file_name = $ref_result if $ref_result;
79             # we have now stringified $file_name if possible. if it's still a ref
80             # then we probably have a file handle
81             }
82              
83 234         329 my $fh;
84 234 100       784 if (ref($file_name)) {
85 14         15 $fh = $file_name;
86             }
87             else {
88             # to keep with the old ways, read in :raw by default
89 220 100       7819 unless (open $fh, "<:raw", $file_name) {
90 36         289 @_ = ($opts, "read_file '$file_name' - open: $!");
91 36         192 goto &_error;
92             }
93             # even though we set raw, let binmode take place here (busted)
94 184 100       937 if (my $bm = $opts->{binmode}) {
95 13         70 binmode $fh, $bm;
96             }
97             }
98              
99             # we are now sure to have an open file handle. Let's slurp it in the same
100             # way that File::Slurper does.
101 198         282 my $buf;
102 198   100     1121 my $buf_ref = $opts->{buf_ref} || \$buf;
103 198         354 ${$buf_ref} = '';
  198         449  
104 198   50     654 my $blk_size = $opts->{blk_size} || 1024 * 1024;
105 198 100 100     2439 if (my $size = -f $fh && -s _) {
106 158 100       521 $blk_size = $size if $size < $blk_size;
107 158         355 my ($pos, $read) = 0;
108 158   100     232 do {
109 194 50       356 unless(defined($read = read $fh, ${$buf_ref}, $blk_size, $pos)) {
  194         47116  
110 0         0 @_ = ($opts, "read_file '$file_name' - read: $!");
111 0         0 goto &_error;
112             }
113 194         1161 $pos += $read;
114             } while ($read && $pos < $size);
115             }
116             else {
117 40         85 ${$buf_ref} = do { local $/; <$fh> };
  40         156  
  40         313  
  40         4178  
118             }
119 198 50 66     579 seek($fh, $opts->{_data_tell}, SEEK_SET) if $opts->{_is_data} && $opts->{_data_tell};
120              
121             # line endings if we're on Windows
122 198 50 66     252 ${$buf_ref} =~ s/\015\012/\012/g if ${$buf_ref} && $is_win32 && !$opts->{binmode};
  0   33     0  
  198         953  
123              
124             # we now have a buffer filled with the file content. Figure out how to
125             # return it to the user
126 198         456 my $want_array = wantarray; # let's only ask for this once
127 198 100 100     771 if ($want_array || $opts->{array_ref}) {
128 32     32   250 use re 'taint';
  32         51  
  32         60954  
129 50         119 my $sep = $/;
130 50 100 66     197 $sep = '\n\n+' if defined $sep && $sep eq '';
131             # split the buffered content into lines
132 50         120 my @lines = length(${$buf_ref}) ?
133 50 100       86 ${$buf_ref} =~ /(.*?$sep|.+)/sg : ();
  40         18285  
134 50 100       236 chomp @lines if $opts->{chomp};
135 50 100       875 return \@lines if $opts->{array_ref};
136 22         869 return @lines;
137             }
138 148 100       648 return $buf_ref if $opts->{scalar_ref};
139             # if the function was called in scalar context, return the contents
140 120 100       250 return ${$buf_ref} if defined $want_array;
  108         14193  
141             # if we were called in void context, return nothing
142 12         221 return;
143             }
144              
145             # errors in this sub are returned as scalar refs
146             # a normal IO/GLOB handle is an empty return
147             # an overloaded object returns its stringified as a scalarfilename
148              
149             sub _check_ref {
150              
151 21     21   61 my( $handle, $opts ) = @_ ;
152              
153             # check if we are reading from a handle (GLOB or IO object)
154              
155 21 100       117 if ( eval { $handle->isa( 'GLOB' ) || $handle->isa( 'IO' ) } ) {
  21 100       636  
156              
157             # we have a handle. deal with seeking to it if it is DATA
158              
159 18         152 my $err = _seek_data_handle( $handle, $opts ) ;
160              
161             # return the error string if any
162              
163 18 50       169 return \$err if $err ;
164              
165             # we have good handle
166 18         146 return ;
167             }
168              
169 3         6 eval { require overload } ;
  3         16  
170              
171             # return an error if we can't load the overload pragma
172             # or if the object isn't overloaded
173              
174 3 50 33     16 return \"Bad handle '$handle' is not a GLOB or IO object or overloaded"
175             if $@ || !overload::Overloaded( $handle ) ;
176              
177             # must be overloaded so return its stringified value
178              
179 3         108 return "$handle" ;
180             }
181              
182             sub _seek_data_handle {
183              
184 18     18   65 my( $handle, $opts ) = @_ ;
185             # store some meta-data about the __DATA__ file handle
186 18         155 $opts->{_is_data} = 0;
187 18         74 $opts->{_data_tell} = 0;
188              
189             # DEEP DARK MAGIC. this checks the UNTAINT IO flag of a
190             # glob/handle. only the DATA handle is untainted (since it is from
191             # trusted data in the source file). this allows us to test if this is
192             # the DATA handle and then to do a sysseek to make sure it gets
193             # slurped correctly. on some systems, the buffered i/o pointer is not
194             # left at the same place as the fd pointer. this sysseek makes them
195             # the same so slurping with sysread will work.
196              
197 18         92 eval{ require B } ;
  18         454  
198              
199 18 50       102 if ( $@ ) {
200              
201 0         0 return <
202             Can't find B.pm with this Perl: $!.
203             That module is needed to properly slurp the DATA handle.
204             ERR
205             }
206              
207 18 100       887 if ( B::svref_2object( $handle )->IO->IoFLAGS & 16 ) {
208              
209             # we now know we have the data handle. Let's store its original
210             # location in the file so that we can put it back after the read.
211             # this is only done for Bugwards-compatibility in some dists such as
212             # CPAN::Index::API that made use of the oddity where sysread was in use
213             # before
214 4         6 $opts->{_is_data} = 1;
215 4         10 $opts->{_data_tell} = tell($handle);
216             # set the seek position to the current tell.
217              
218             # unless( sysseek( $handle, tell( $handle ), SEEK_SET ) ) {
219             # return "read_file '$handle' - sysseek: $!" ;
220             # }
221             }
222              
223             # seek was successful, return no error string
224              
225 18         502 return ;
226             }
227              
228             *wf = \&write_file ;
229              
230             sub write_file {
231 185     185 1 1310405 my $file_name = shift;
232 185 100       758 my $opts = (ref $_[0] eq 'HASH') ? shift : {};
233             # options we care about:
234             # append atomic binmode buf_ref err_mode no_clobber perms
235              
236 185         319 my $fh;
237 185         295 my $no_truncate = 0;
238 185         285 my $orig_filename;
239             # let's see if we have a stringified object or some sort of handle
240             # or globref before doing anything else
241 185 100       584 if (ref($file_name)) {
242 5         90 my $ref_result = _check_ref($file_name, $opts);
243 5 50       64 if (ref($ref_result)) {
244             # some error happened while checking for a ref
245 0         0 @_ = ($opts, $ref_result);
246 0         0 goto &_error;
247             }
248 5 100       75 if ($ref_result) {
249             # we have now stringified $file_name from the overloaded obj
250 1         2 $file_name = $ref_result;
251             }
252             else {
253             # we now have a proper handle ref
254             # make sure we don't call truncate on it
255 4         9 $fh = $file_name;
256 4         7 $no_truncate = 1;
257             # can't do atomic or permissions on a file handle
258 4         31 delete $opts->{atomic};
259 4         15 delete $opts->{perms};
260             }
261             }
262              
263             # open the file for writing if we were given a filename
264 185 100       434 unless ($fh) {
265 181         274 $orig_filename = $file_name;
266 181 100       388 my $perms = defined($opts->{perms}) ? $opts->{perms} : 0666;
267             # set the mode for the sysopen
268 181         246 my $mode = O_WRONLY | O_CREAT;
269 181 100       348 $mode |= O_APPEND if $opts->{append};
270 181 100       350 $mode |= O_EXCL if $opts->{no_clobber};
271 181 100       343 if ($opts->{atomic}) {
272             # in an atomic write, we must open a new file in the same directory
273             # as the original to account for ACLs. We must also set the new file
274             # to the same permissions as the original unless overridden by the
275             # caller's request to set a specified permission set.
276 30         1139 my $dir = File::Spec->rel2abs(File::Basename::dirname($file_name));
277 30 100 66     487 if (!defined($opts->{perms}) && -e $file_name && -f _) {
      66        
278 17         196 $perms = 07777 & (stat $file_name)[2];
279             }
280             # we must ensure we're using a good temporary filename (doesn't already
281             # exist). This is slower, but safer.
282             {
283 30         68 local $^W = 0; # AYFKM
  30         110  
284 30         98 (undef, $file_name) = tempfile('.tempXXXXX', DIR => $dir, OPEN => 0);
285             }
286             }
287 181         6271 $fh = local *FH;
288 181 100       7239 unless (sysopen($fh, $file_name, $mode, $perms)) {
289 14         381 @_ = ($opts, "write_file '$file_name' - sysopen: $!");
290 14         74 goto &_error;
291             }
292             }
293             # we now have an open file handle as well as data to write to that handle
294 171 100       2029 if (my $binmode = $opts->{binmode}) {
295 9         56 binmode($fh, $binmode);
296             }
297              
298             # get the data to print to the file
299             # get the buffer ref - it depends on how the data is passed in
300             # after this if/else $buf_ref will have a scalar ref to the data
301 171         276 my $buf_ref;
302 171         256 my $data_is_ref = 0;
303 171 100       782 if (ref($opts->{buf_ref}) eq 'SCALAR') {
    100          
    100          
304             # a scalar ref passed in %opts has the data
305             # note that the data was passed by ref
306 10         16 $buf_ref = $opts->{buf_ref};
307 10         21 $data_is_ref = 1;
308             }
309             elsif (ref($_[0]) eq 'SCALAR') {
310             # the first value in @_ is the scalar ref to the data
311             # note that the data was passed by ref
312 10         20 $buf_ref = shift;
313 10         17 $data_is_ref = 1;
314             }
315             elsif (ref($_[0]) eq 'ARRAY') {
316             # the first value in @_ is the array ref to the data so join it.
317 10         25 ${$buf_ref} = join '', @{$_[0]};
  10         1403  
  10         1191  
318             }
319             else {
320             # good old @_ has all the data so join it.
321 141         3434 ${$buf_ref} = join '', @_;
  141         421  
322             }
323              
324             # seek and print
325 171 100       632 seek($fh, 0, SEEK_END) if $opts->{append};
326 171         322 print {$fh} ${$buf_ref};
  171         456  
  171         24595  
327 171 100       8273 truncate($fh, tell($fh)) unless $no_truncate;
328 171         2369 close($fh);
329              
330 171 100 100     2012 if ($opts->{atomic} && !rename($file_name, $orig_filename)) {
331 16         130 @_ = ($opts, "write_file '$file_name' - rename: $!");
332 16         78 goto &_error;
333             }
334              
335 155         1021 return 1;
336             }
337              
338             # this is for backwards compatibility with the previous File::Slurp module.
339             # write_file always overwrites an existing file
340             *overwrite_file = \&write_file ;
341              
342             # the current write_file has an append mode so we use that. this
343             # supports the same API with an optional second argument which is a
344             # hash ref of options.
345              
346             sub append_file {
347              
348             # get the optional opts hash ref
349 21     21 1 23874 my $opts = $_[1] ;
350 21 100       80 if ( ref $opts eq 'HASH' ) {
351              
352             # we were passed an opts ref so just mark the append mode
353              
354 8         16 $opts->{append} = 1 ;
355             }
356             else {
357              
358             # no opts hash so insert one with the append mode
359              
360 13         59 splice( @_, 1, 0, { append => 1 } ) ;
361             }
362              
363             # magic goto the main write_file sub. this overlays the sub without touching
364             # the stack or @_
365              
366 21         143 goto &write_file
367             }
368              
369             # prepend data to the beginning of a file
370              
371             sub prepend_file {
372              
373 15     15 1 6036 my $file_name = shift ;
374              
375             #print "FILE $file_name\n" ;
376              
377 15 100       46 my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
378              
379             # delete unsupported options
380              
381             my @bad_opts =
382 15   100     19 grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ;
  15         71  
383              
384 15         25 delete @{$opts}{@bad_opts} ;
  15         26  
385              
386 15         21 my $prepend_data = shift ;
387 15 100       30 $prepend_data = '' unless defined $prepend_data ;
388 15 100       36 $prepend_data = ${$prepend_data} if ref $prepend_data eq 'SCALAR' ;
  1         2  
389              
390             #print "PRE [$prepend_data]\n" ;
391              
392 15         36 my $err_mode = delete $opts->{err_mode} ;
393 15         25 $opts->{ err_mode } = 'croak' ;
394 15         20 $opts->{ scalar_ref } = 1 ;
395              
396 15         19 my $existing_data = eval { read_file( $file_name, $opts ) } ;
  15         34  
397              
398 15 100       139 if ( $@ ) {
399              
400 4         29 @_ = ( { err_mode => $err_mode },
401             "prepend_file '$file_name' - read_file: $!" ) ;
402 4         14 goto &_error ;
403             }
404              
405             #print "EXIST [$$existing_data]\n" ;
406              
407 11         21 $opts->{atomic} = 1 ;
408             my $write_result =
409 11         16 eval { write_file( $file_name, $opts,
  11         23  
410             $prepend_data, $$existing_data ) ;
411             } ;
412              
413 11 100       105 if ( $@ ) {
414              
415 3         14 @_ = ( { err_mode => $err_mode },
416             "prepend_file '$file_name' - write_file: $!" ) ;
417 3         8 goto &_error ;
418             }
419              
420 8         31 return $write_result ;
421             }
422              
423             # edit a file as a scalar in $_
424              
425             *ef = \&edit_file ;
426              
427             sub edit_file(&$;$) {
428              
429 12     12 1 7199 my( $edit_code, $file_name, $opts ) = @_ ;
430 12 100       50 $opts = {} unless ref $opts eq 'HASH' ;
431              
432             # my $edit_code = shift ;
433             # my $file_name = shift ;
434             # my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
435              
436             #print "FILE $file_name\n" ;
437              
438             # delete unsupported options
439              
440             my @bad_opts =
441 12   100     15 grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ;
  12         59  
442              
443 12         20 delete @{$opts}{@bad_opts} ;
  12         21  
444              
445             # keep the user err_mode and force croaking on internal errors
446              
447 12         23 my $err_mode = delete $opts->{err_mode} ;
448 12         19 $opts->{ err_mode } = 'croak' ;
449              
450             # get a scalar ref for speed and slurp the file into a scalar
451              
452 12         17 $opts->{ scalar_ref } = 1 ;
453 12         15 my $existing_data = eval { read_file( $file_name, $opts ) } ;
  12         24  
454              
455 12 100       324 if ( $@ ) {
456              
457 7         39 @_ = ( { err_mode => $err_mode },
458             "edit_file '$file_name' - read_file: $!" ) ;
459 7         23 goto &_error ;
460             }
461              
462             #print "EXIST [$$existing_data]\n" ;
463              
464 5         10 my( $edited_data ) = map { $edit_code->(); $_ } $$existing_data ;
  5         14  
  5         92  
465              
466 5         11 $opts->{atomic} = 1 ;
467             my $write_result =
468 5         6 eval { write_file( $file_name, $opts, $edited_data ) } ;
  5         11  
469              
470 5 50       13 if ( $@ ) {
471              
472 0         0 @_ = ( { err_mode => $err_mode },
473             "edit_file '$file_name' - write_file: $!" ) ;
474 0         0 goto &_error ;
475             }
476              
477 5         20 return $write_result ;
478             }
479              
480             *efl = \&edit_file_lines ;
481              
482             sub edit_file_lines(&$;$) {
483              
484 7     7 1 6808 my( $edit_code, $file_name, $opts ) = @_ ;
485 7 100       22 $opts = {} unless ref $opts eq 'HASH' ;
486              
487             # my $edit_code = shift ;
488             # my $file_name = shift ;
489             # my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
490              
491             #print "FILE $file_name\n" ;
492              
493             # delete unsupported options
494              
495             my @bad_opts =
496 7   33     9 grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ;
  7         29  
497              
498 7         12 delete @{$opts}{@bad_opts} ;
  7         11  
499              
500             # keep the user err_mode and force croaking on internal errors
501              
502 7         13 my $err_mode = delete $opts->{err_mode} ;
503 7         11 $opts->{ err_mode } = 'croak' ;
504              
505             # get an array ref for speed and slurp the file into lines
506              
507 7         11 $opts->{ array_ref } = 1 ;
508 7         10 my $existing_data = eval { read_file( $file_name, $opts ) } ;
  7         14  
509              
510 7 50       341 if ( $@ ) {
511              
512 7         49 @_ = ( { err_mode => $err_mode },
513             "edit_file_lines '$file_name' - read_file: $!" ) ;
514 7         24 goto &_error ;
515             }
516              
517             #print "EXIST [$$existing_data]\n" ;
518              
519 0         0 my @edited_data = map { $edit_code->(); $_ } @$existing_data ;
  0         0  
  0         0  
520              
521 0         0 $opts->{atomic} = 1 ;
522             my $write_result =
523 0         0 eval { write_file( $file_name, $opts, @edited_data ) } ;
  0         0  
524              
525 0 0       0 if ( $@ ) {
526              
527 0         0 @_ = ( { err_mode => $err_mode },
528             "edit_file_lines '$file_name' - write_file: $!" ) ;
529 0         0 goto &_error ;
530             }
531              
532 0         0 return $write_result ;
533             }
534              
535             # basic wrapper around opendir/readdir
536              
537             sub read_dir {
538              
539 15     15 1 9872 my $dir = shift ;
540 15 100       59 my $opts = ( ref $_[0] eq 'HASH' ) ? shift : { @_ } ;
541              
542             # this handle will be destroyed upon return
543              
544 15         38 local(*DIRH);
545              
546             # open the dir and handle any errors
547              
548 15 100       323 unless ( opendir( DIRH, $dir ) ) {
549              
550 7         69 @_ = ( $opts, "read_dir '$dir' - opendir: $!" ) ;
551 7         40 goto &_error ;
552             }
553              
554 8         175 my @dir_entries = readdir(DIRH) ;
555              
556             @dir_entries = grep( $_ ne "." && $_ ne "..", @dir_entries )
557 8 100 100     158 unless $opts->{'keep_dot_dot'} ;
558              
559 8 100       16 if ( $opts->{'prefix'} ) {
560              
561 2         137 $_ = File::Spec->catfile($dir, $_) for @dir_entries;
562             }
563              
564 8 100       129 return @dir_entries if wantarray ;
565 1         15 return \@dir_entries ;
566             }
567              
568             # error handling section
569             #
570             # all the error handling uses magic goto so the caller will get the
571             # error message as if from their code and not this module. if we just
572             # did a call on the error code, the carp/croak would report it from
573             # this module since the error sub is one level down on the call stack
574             # from read_file/write_file/read_dir.
575              
576              
577             my %err_func = (
578             'carp' => \&carp,
579             'croak' => \&croak,
580             ) ;
581              
582             sub _error {
583              
584 94     94   194 my( $opts, $err_msg ) = @_ ;
585              
586             # get the error function to use
587              
588 94   100     261 my $func = $err_func{ $opts->{'err_mode'} || 'croak' } ;
589              
590             # if we didn't find it in our error function hash, they must have set
591             # it to quiet and we don't do anything.
592              
593 94 100       218 return unless $func ;
594              
595             # call the carp/croak function
596              
597 71 50       5957 $func->($err_msg) if $func ;
598              
599             # return a hard undef (in list context this will be a single value of
600             # undef which is not a legal in-band value)
601              
602 22         889 return undef ;
603             }
604              
605             1;
606             __END__