| Filename | /home/hejohns/perl5/lib/perl5/File/Slurp.pm |
| Statements | Executed 42 statements in 1.78ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 2.46ms | 3.95ms | File::Slurp::BEGIN@16 |
| 1 | 1 | 1 | 1.05ms | 1.22ms | File::Slurp::BEGIN@128 |
| 1 | 1 | 1 | 7µs | 9µs | File::Slurp::BEGIN@3 |
| 1 | 1 | 1 | 6µs | 6µs | File::Slurp::BEGIN@13 |
| 1 | 1 | 1 | 5µs | 12µs | File::Slurp::BEGIN@17 |
| 1 | 1 | 1 | 4µs | 8µs | File::Slurp::BEGIN@10 |
| 1 | 1 | 1 | 4µs | 21µs | File::Slurp::BEGIN@4 |
| 1 | 1 | 1 | 3µs | 19µs | File::Slurp::BEGIN@9 |
| 1 | 1 | 1 | 3µs | 193µs | File::Slurp::BEGIN@11 |
| 1 | 1 | 1 | 3µs | 29µs | File::Slurp::BEGIN@14 |
| 1 | 1 | 1 | 2µs | 2µs | File::Slurp::BEGIN@12 |
| 1 | 1 | 1 | 2µs | 2µs | File::Slurp::CORE:match (opcode) |
| 1 | 1 | 1 | 1µs | 1µs | File::Slurp::BEGIN@15 |
| 1 | 1 | 1 | 300ns | 300ns | File::Slurp::__ANON__ (xsub) |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::_check_ref |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::_error |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::_seek_data_handle |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::append_file |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::edit_file |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::edit_file_lines |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::prepend_file |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::read_dir |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::read_file |
| 0 | 0 | 0 | 0s | 0s | File::Slurp::write_file |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package File::Slurp; | ||||
| 2 | |||||
| 3 | 2 | 19µs | 2 | 10µs | # spent 9µs (7+2) within File::Slurp::BEGIN@3 which was called:
# once (7µs+2µs) by main::BEGIN@19 at line 3 # spent 9µs making 1 call to File::Slurp::BEGIN@3
# spent 2µs making 1 call to strict::import |
| 4 | 2 | 24µs | 2 | 39µs | # spent 21µs (4+18) within File::Slurp::BEGIN@4 which was called:
# once (4µs+18µs) by main::BEGIN@19 at line 4 # spent 21µs making 1 call to File::Slurp::BEGIN@4
# spent 18µs making 1 call to warnings::import |
| 5 | |||||
| 6 | 1 | 400ns | our $VERSION = '9999.32'; | ||
| 7 | 1 | 14µs | $VERSION = eval $VERSION; # spent 2µs executing statements in string eval | ||
| 8 | |||||
| 9 | 2 | 16µs | 2 | 35µs | # spent 19µs (3+16) within File::Slurp::BEGIN@9 which was called:
# once (3µs+16µs) by main::BEGIN@19 at line 9 # spent 19µs making 1 call to File::Slurp::BEGIN@9
# spent 16µs making 1 call to Exporter::import |
| 10 | 2 | 14µs | 2 | 11µs | # spent 8µs (4+3) within File::Slurp::BEGIN@10 which was called:
# once (4µs+3µs) by main::BEGIN@19 at line 10 # spent 8µs making 1 call to File::Slurp::BEGIN@10
# spent 3µs making 1 call to Exporter::import |
| 11 | 2 | 16µs | 2 | 384µs | # spent 193µs (3+190) within File::Slurp::BEGIN@11 which was called:
# once (3µs+190µs) by main::BEGIN@19 at line 11 # spent 193µs making 1 call to File::Slurp::BEGIN@11
# spent 190µs making 1 call to Exporter::import |
| 12 | 2 | 10µs | 1 | 2µs | # spent 2µs within File::Slurp::BEGIN@12 which was called:
# once (2µs+0s) by main::BEGIN@19 at line 12 # spent 2µs making 1 call to File::Slurp::BEGIN@12 |
| 13 | 2 | 17µs | 2 | 7µs | # spent 6µs (6+300ns) within File::Slurp::BEGIN@13 which was called:
# once (6µs+300ns) by main::BEGIN@19 at line 13 # spent 6µs making 1 call to File::Slurp::BEGIN@13
# spent 300ns making 1 call to File::Slurp::__ANON__ |
| 14 | 2 | 12µs | 2 | 54µs | # spent 29µs (3+26) within File::Slurp::BEGIN@14 which was called:
# once (3µs+26µs) by main::BEGIN@19 at line 14 # spent 29µs making 1 call to File::Slurp::BEGIN@14
# spent 26µs making 1 call to Exporter::import |
| 15 | 2 | 11µs | 1 | 1µs | # spent 1µs within File::Slurp::BEGIN@15 which was called:
# once (1µs+0s) by main::BEGIN@19 at line 15 # spent 1µs making 1 call to File::Slurp::BEGIN@15 |
| 16 | 2 | 92µs | 2 | 4.93ms | # spent 3.95ms (2.46+1.49) within File::Slurp::BEGIN@16 which was called:
# once (2.46ms+1.49ms) by main::BEGIN@19 at line 16 # spent 3.95ms making 1 call to File::Slurp::BEGIN@16
# spent 982µs making 1 call to POSIX::import |
| 17 | 2 | 286µs | 2 | 18µs | # spent 12µs (5+6) within File::Slurp::BEGIN@17 which was called:
# once (5µs+6µs) by main::BEGIN@19 at line 17 # spent 12µs making 1 call to File::Slurp::BEGIN@17
# spent 6µs making 1 call to Exporter::import |
| 18 | |||||
| 19 | 1 | 1µs | my @std_export = qw( | ||
| 20 | read_file | ||||
| 21 | write_file | ||||
| 22 | overwrite_file | ||||
| 23 | append_file | ||||
| 24 | read_dir | ||||
| 25 | ) ; | ||||
| 26 | |||||
| 27 | 1 | 400ns | my @edit_export = qw( | ||
| 28 | edit_file | ||||
| 29 | edit_file_lines | ||||
| 30 | ) ; | ||||
| 31 | |||||
| 32 | 1 | 500ns | my @abbrev_export = qw( | ||
| 33 | rf | ||||
| 34 | wf | ||||
| 35 | ef | ||||
| 36 | efl | ||||
| 37 | ) ; | ||||
| 38 | |||||
| 39 | 1 | 800ns | our @EXPORT_OK = ( | ||
| 40 | @edit_export, | ||||
| 41 | @abbrev_export, | ||||
| 42 | qw( | ||||
| 43 | slurp | ||||
| 44 | prepend_file | ||||
| 45 | ), | ||||
| 46 | ) ; | ||||
| 47 | |||||
| 48 | 1 | 4µs | 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 | 1 | 400ns | our @EXPORT = @std_export ; | ||
| 56 | |||||
| 57 | 1 | 200ns | my $max_fast_slurp_size = 1024 * 100 ; | ||
| 58 | |||||
| 59 | 1 | 6µs | 1 | 2µs | my $is_win32 = $^O =~ /win32/i ; # spent 2µs making 1 call to File::Slurp::CORE:match |
| 60 | |||||
| 61 | 1 | 1µs | *slurp = \&read_file ; | ||
| 62 | 1 | 200ns | *rf = \&read_file ; | ||
| 63 | |||||
| 64 | sub read_file { | ||||
| 65 | my $file_name = shift; | ||||
| 66 | 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 | if (ref($file_name)) { | ||||
| 73 | my $ref_result = _check_ref($file_name, $opts); | ||||
| 74 | if (ref($ref_result)) { | ||||
| 75 | @_ = ($opts, $ref_result); | ||||
| 76 | goto &_error; | ||||
| 77 | } | ||||
| 78 | $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 | my $fh; | ||||
| 84 | if (ref($file_name)) { | ||||
| 85 | $fh = $file_name; | ||||
| 86 | } | ||||
| 87 | else { | ||||
| 88 | # to keep with the old ways, read in :raw by default | ||||
| 89 | unless (open $fh, "<:raw", $file_name) { | ||||
| 90 | @_ = ($opts, "read_file '$file_name' - open: $!"); | ||||
| 91 | goto &_error; | ||||
| 92 | } | ||||
| 93 | # even though we set raw, let binmode take place here (busted) | ||||
| 94 | if (my $bm = $opts->{binmode}) { | ||||
| 95 | 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 | my $buf; | ||||
| 102 | my $buf_ref = $opts->{buf_ref} || \$buf; | ||||
| 103 | ${$buf_ref} = ''; | ||||
| 104 | my $blk_size = $opts->{blk_size} || 1024 * 1024; | ||||
| 105 | if (my $size = -f $fh && -s _) { | ||||
| 106 | $blk_size = $size if $size < $blk_size; | ||||
| 107 | my ($pos, $read) = 0; | ||||
| 108 | do { | ||||
| 109 | unless(defined($read = read $fh, ${$buf_ref}, $blk_size, $pos)) { | ||||
| 110 | @_ = ($opts, "read_file '$file_name' - read: $!"); | ||||
| 111 | goto &_error; | ||||
| 112 | } | ||||
| 113 | $pos += $read; | ||||
| 114 | } while ($read && $pos < $size); | ||||
| 115 | } | ||||
| 116 | else { | ||||
| 117 | ${$buf_ref} = do { local $/; <$fh> }; | ||||
| 118 | } | ||||
| 119 | seek($fh, $opts->{_data_tell}, SEEK_SET) if $opts->{_is_data} && $opts->{_data_tell}; | ||||
| 120 | |||||
| 121 | # line endings if we're on Windows | ||||
| 122 | ${$buf_ref} =~ s/\015\012/\012/g if ${$buf_ref} && $is_win32 && !$opts->{binmode}; | ||||
| 123 | |||||
| 124 | # we now have a buffer filled with the file content. Figure out how to | ||||
| 125 | # return it to the user | ||||
| 126 | my $want_array = wantarray; # let's only ask for this once | ||||
| 127 | if ($want_array || $opts->{array_ref}) { | ||||
| 128 | 2 | 1.22ms | 2 | 1.23ms | # spent 1.22ms (1.05+177µs) within File::Slurp::BEGIN@128 which was called:
# once (1.05ms+177µs) by main::BEGIN@19 at line 128 # spent 1.22ms making 1 call to File::Slurp::BEGIN@128
# spent 8µs making 1 call to re::import |
| 129 | my $sep = $/; | ||||
| 130 | $sep = '\n\n+' if defined $sep && $sep eq ''; | ||||
| 131 | # split the buffered content into lines | ||||
| 132 | my @lines = length(${$buf_ref}) ? | ||||
| 133 | ${$buf_ref} =~ /(.*?$sep|.+)/sg : (); | ||||
| 134 | chomp @lines if $opts->{chomp}; | ||||
| 135 | return \@lines if $opts->{array_ref}; | ||||
| 136 | return @lines; | ||||
| 137 | } | ||||
| 138 | return $buf_ref if $opts->{scalar_ref}; | ||||
| 139 | # if the function was called in scalar context, return the contents | ||||
| 140 | return ${$buf_ref} if defined $want_array; | ||||
| 141 | # if we were called in void context, return nothing | ||||
| 142 | 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 | my( $handle, $opts ) = @_ ; | ||||
| 152 | |||||
| 153 | # check if we are reading from a handle (GLOB or IO object) | ||||
| 154 | |||||
| 155 | if ( eval { $handle->isa( 'GLOB' ) || $handle->isa( 'IO' ) } ) { | ||||
| 156 | |||||
| 157 | # we have a handle. deal with seeking to it if it is DATA | ||||
| 158 | |||||
| 159 | my $err = _seek_data_handle( $handle, $opts ) ; | ||||
| 160 | |||||
| 161 | # return the error string if any | ||||
| 162 | |||||
| 163 | return \$err if $err ; | ||||
| 164 | |||||
| 165 | # we have good handle | ||||
| 166 | return ; | ||||
| 167 | } | ||||
| 168 | |||||
| 169 | eval { require overload } ; | ||||
| 170 | |||||
| 171 | # return an error if we can't load the overload pragma | ||||
| 172 | # or if the object isn't overloaded | ||||
| 173 | |||||
| 174 | 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 | return "$handle" ; | ||||
| 180 | } | ||||
| 181 | |||||
| 182 | sub _seek_data_handle { | ||||
| 183 | |||||
| 184 | my( $handle, $opts ) = @_ ; | ||||
| 185 | # store some meta-data about the __DATA__ file handle | ||||
| 186 | $opts->{_is_data} = 0; | ||||
| 187 | $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 | eval{ require B } ; | ||||
| 198 | |||||
| 199 | if ( $@ ) { | ||||
| 200 | |||||
| 201 | return <<ERR ; | ||||
| 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 | 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 | $opts->{_is_data} = 1; | ||||
| 215 | $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 | return ; | ||||
| 226 | } | ||||
| 227 | |||||
| 228 | 1 | 100ns | *wf = \&write_file ; | ||
| 229 | |||||
| 230 | sub write_file { | ||||
| 231 | my $file_name = shift; | ||||
| 232 | 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 | my $fh; | ||||
| 237 | my $no_truncate = 0; | ||||
| 238 | 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 | if (ref($file_name)) { | ||||
| 242 | my $ref_result = _check_ref($file_name, $opts); | ||||
| 243 | if (ref($ref_result)) { | ||||
| 244 | # some error happened while checking for a ref | ||||
| 245 | @_ = ($opts, $ref_result); | ||||
| 246 | goto &_error; | ||||
| 247 | } | ||||
| 248 | if ($ref_result) { | ||||
| 249 | # we have now stringified $file_name from the overloaded obj | ||||
| 250 | $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 | $fh = $file_name; | ||||
| 256 | $no_truncate = 1; | ||||
| 257 | # can't do atomic or permissions on a file handle | ||||
| 258 | delete $opts->{atomic}; | ||||
| 259 | delete $opts->{perms}; | ||||
| 260 | } | ||||
| 261 | } | ||||
| 262 | |||||
| 263 | # open the file for writing if we were given a filename | ||||
| 264 | unless ($fh) { | ||||
| 265 | $orig_filename = $file_name; | ||||
| 266 | my $perms = defined($opts->{perms}) ? $opts->{perms} : 0666; | ||||
| 267 | # set the mode for the sysopen | ||||
| 268 | my $mode = O_WRONLY | O_CREAT; | ||||
| 269 | $mode |= O_APPEND if $opts->{append}; | ||||
| 270 | $mode |= O_EXCL if $opts->{no_clobber}; | ||||
| 271 | 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 | my $dir = File::Spec->rel2abs(File::Basename::dirname($file_name)); | ||||
| 277 | if (!defined($opts->{perms}) && -e $file_name && -f _) { | ||||
| 278 | $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 | local $^W = 0; # AYFKM | ||||
| 284 | (undef, $file_name) = tempfile('.tempXXXXX', DIR => $dir, OPEN => 0); | ||||
| 285 | } | ||||
| 286 | } | ||||
| 287 | $fh = local *FH; | ||||
| 288 | unless (sysopen($fh, $file_name, $mode, $perms)) { | ||||
| 289 | @_ = ($opts, "write_file '$file_name' - sysopen: $!"); | ||||
| 290 | goto &_error; | ||||
| 291 | } | ||||
| 292 | } | ||||
| 293 | # we now have an open file handle as well as data to write to that handle | ||||
| 294 | if (my $binmode = $opts->{binmode}) { | ||||
| 295 | 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 | my $buf_ref; | ||||
| 302 | my $data_is_ref = 0; | ||||
| 303 | if (ref($opts->{buf_ref}) eq 'SCALAR') { | ||||
| 304 | # a scalar ref passed in %opts has the data | ||||
| 305 | # note that the data was passed by ref | ||||
| 306 | $buf_ref = $opts->{buf_ref}; | ||||
| 307 | $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 | $buf_ref = shift; | ||||
| 313 | $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 | ${$buf_ref} = join '', @{$_[0]}; | ||||
| 318 | } | ||||
| 319 | else { | ||||
| 320 | # good old @_ has all the data so join it. | ||||
| 321 | ${$buf_ref} = join '', @_; | ||||
| 322 | } | ||||
| 323 | |||||
| 324 | # seek and print | ||||
| 325 | seek($fh, 0, SEEK_END) if $opts->{append}; | ||||
| 326 | print {$fh} ${$buf_ref}; | ||||
| 327 | truncate($fh, tell($fh)) unless $no_truncate; | ||||
| 328 | close($fh); | ||||
| 329 | |||||
| 330 | if ($opts->{atomic} && !rename($file_name, $orig_filename)) { | ||||
| 331 | @_ = ($opts, "write_file '$file_name' - rename: $!"); | ||||
| 332 | goto &_error; | ||||
| 333 | } | ||||
| 334 | |||||
| 335 | 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 | 1 | 100ns | *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 | my $opts = $_[1] ; | ||||
| 350 | if ( ref $opts eq 'HASH' ) { | ||||
| 351 | |||||
| 352 | # we were passed an opts ref so just mark the append mode | ||||
| 353 | |||||
| 354 | $opts->{append} = 1 ; | ||||
| 355 | } | ||||
| 356 | else { | ||||
| 357 | |||||
| 358 | # no opts hash so insert one with the append mode | ||||
| 359 | |||||
| 360 | 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 | goto &write_file | ||||
| 367 | } | ||||
| 368 | |||||
| 369 | # prepend data to the beginning of a file | ||||
| 370 | |||||
| 371 | sub prepend_file { | ||||
| 372 | |||||
| 373 | my $file_name = shift ; | ||||
| 374 | |||||
| 375 | #print "FILE $file_name\n" ; | ||||
| 376 | |||||
| 377 | my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ; | ||||
| 378 | |||||
| 379 | # delete unsupported options | ||||
| 380 | |||||
| 381 | my @bad_opts = | ||||
| 382 | grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ; | ||||
| 383 | |||||
| 384 | delete @{$opts}{@bad_opts} ; | ||||
| 385 | |||||
| 386 | my $prepend_data = shift ; | ||||
| 387 | $prepend_data = '' unless defined $prepend_data ; | ||||
| 388 | $prepend_data = ${$prepend_data} if ref $prepend_data eq 'SCALAR' ; | ||||
| 389 | |||||
| 390 | #print "PRE [$prepend_data]\n" ; | ||||
| 391 | |||||
| 392 | my $err_mode = delete $opts->{err_mode} ; | ||||
| 393 | $opts->{ err_mode } = 'croak' ; | ||||
| 394 | $opts->{ scalar_ref } = 1 ; | ||||
| 395 | |||||
| 396 | my $existing_data = eval { read_file( $file_name, $opts ) } ; | ||||
| 397 | |||||
| 398 | if ( $@ ) { | ||||
| 399 | |||||
| 400 | @_ = ( { err_mode => $err_mode }, | ||||
| 401 | "prepend_file '$file_name' - read_file: $!" ) ; | ||||
| 402 | goto &_error ; | ||||
| 403 | } | ||||
| 404 | |||||
| 405 | #print "EXIST [$$existing_data]\n" ; | ||||
| 406 | |||||
| 407 | $opts->{atomic} = 1 ; | ||||
| 408 | my $write_result = | ||||
| 409 | eval { write_file( $file_name, $opts, | ||||
| 410 | $prepend_data, $$existing_data ) ; | ||||
| 411 | } ; | ||||
| 412 | |||||
| 413 | if ( $@ ) { | ||||
| 414 | |||||
| 415 | @_ = ( { err_mode => $err_mode }, | ||||
| 416 | "prepend_file '$file_name' - write_file: $!" ) ; | ||||
| 417 | goto &_error ; | ||||
| 418 | } | ||||
| 419 | |||||
| 420 | return $write_result ; | ||||
| 421 | } | ||||
| 422 | |||||
| 423 | # edit a file as a scalar in $_ | ||||
| 424 | |||||
| 425 | 1 | 100ns | *ef = \&edit_file ; | ||
| 426 | |||||
| 427 | sub edit_file(&$;$) { | ||||
| 428 | |||||
| 429 | my( $edit_code, $file_name, $opts ) = @_ ; | ||||
| 430 | $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 | grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ; | ||||
| 442 | |||||
| 443 | delete @{$opts}{@bad_opts} ; | ||||
| 444 | |||||
| 445 | # keep the user err_mode and force croaking on internal errors | ||||
| 446 | |||||
| 447 | my $err_mode = delete $opts->{err_mode} ; | ||||
| 448 | $opts->{ err_mode } = 'croak' ; | ||||
| 449 | |||||
| 450 | # get a scalar ref for speed and slurp the file into a scalar | ||||
| 451 | |||||
| 452 | $opts->{ scalar_ref } = 1 ; | ||||
| 453 | my $existing_data = eval { read_file( $file_name, $opts ) } ; | ||||
| 454 | |||||
| 455 | if ( $@ ) { | ||||
| 456 | |||||
| 457 | @_ = ( { err_mode => $err_mode }, | ||||
| 458 | "edit_file '$file_name' - read_file: $!" ) ; | ||||
| 459 | goto &_error ; | ||||
| 460 | } | ||||
| 461 | |||||
| 462 | #print "EXIST [$$existing_data]\n" ; | ||||
| 463 | |||||
| 464 | my( $edited_data ) = map { $edit_code->(); $_ } $$existing_data ; | ||||
| 465 | |||||
| 466 | $opts->{atomic} = 1 ; | ||||
| 467 | my $write_result = | ||||
| 468 | eval { write_file( $file_name, $opts, $edited_data ) } ; | ||||
| 469 | |||||
| 470 | if ( $@ ) { | ||||
| 471 | |||||
| 472 | @_ = ( { err_mode => $err_mode }, | ||||
| 473 | "edit_file '$file_name' - write_file: $!" ) ; | ||||
| 474 | goto &_error ; | ||||
| 475 | } | ||||
| 476 | |||||
| 477 | return $write_result ; | ||||
| 478 | } | ||||
| 479 | |||||
| 480 | 1 | 100ns | *efl = \&edit_file_lines ; | ||
| 481 | |||||
| 482 | sub edit_file_lines(&$;$) { | ||||
| 483 | |||||
| 484 | my( $edit_code, $file_name, $opts ) = @_ ; | ||||
| 485 | $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 | grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ; | ||||
| 497 | |||||
| 498 | delete @{$opts}{@bad_opts} ; | ||||
| 499 | |||||
| 500 | # keep the user err_mode and force croaking on internal errors | ||||
| 501 | |||||
| 502 | my $err_mode = delete $opts->{err_mode} ; | ||||
| 503 | $opts->{ err_mode } = 'croak' ; | ||||
| 504 | |||||
| 505 | # get an array ref for speed and slurp the file into lines | ||||
| 506 | |||||
| 507 | $opts->{ array_ref } = 1 ; | ||||
| 508 | my $existing_data = eval { read_file( $file_name, $opts ) } ; | ||||
| 509 | |||||
| 510 | if ( $@ ) { | ||||
| 511 | |||||
| 512 | @_ = ( { err_mode => $err_mode }, | ||||
| 513 | "edit_file_lines '$file_name' - read_file: $!" ) ; | ||||
| 514 | goto &_error ; | ||||
| 515 | } | ||||
| 516 | |||||
| 517 | #print "EXIST [$$existing_data]\n" ; | ||||
| 518 | |||||
| 519 | my @edited_data = map { $edit_code->(); $_ } @$existing_data ; | ||||
| 520 | |||||
| 521 | $opts->{atomic} = 1 ; | ||||
| 522 | my $write_result = | ||||
| 523 | eval { write_file( $file_name, $opts, @edited_data ) } ; | ||||
| 524 | |||||
| 525 | if ( $@ ) { | ||||
| 526 | |||||
| 527 | @_ = ( { err_mode => $err_mode }, | ||||
| 528 | "edit_file_lines '$file_name' - write_file: $!" ) ; | ||||
| 529 | goto &_error ; | ||||
| 530 | } | ||||
| 531 | |||||
| 532 | return $write_result ; | ||||
| 533 | } | ||||
| 534 | |||||
| 535 | # basic wrapper around opendir/readdir | ||||
| 536 | |||||
| 537 | sub read_dir { | ||||
| 538 | |||||
| 539 | my $dir = shift ; | ||||
| 540 | my $opts = ( ref $_[0] eq 'HASH' ) ? shift : { @_ } ; | ||||
| 541 | |||||
| 542 | # this handle will be destroyed upon return | ||||
| 543 | |||||
| 544 | local(*DIRH); | ||||
| 545 | |||||
| 546 | # open the dir and handle any errors | ||||
| 547 | |||||
| 548 | unless ( opendir( DIRH, $dir ) ) { | ||||
| 549 | |||||
| 550 | @_ = ( $opts, "read_dir '$dir' - opendir: $!" ) ; | ||||
| 551 | goto &_error ; | ||||
| 552 | } | ||||
| 553 | |||||
| 554 | my @dir_entries = readdir(DIRH) ; | ||||
| 555 | |||||
| 556 | @dir_entries = grep( $_ ne "." && $_ ne "..", @dir_entries ) | ||||
| 557 | unless $opts->{'keep_dot_dot'} ; | ||||
| 558 | |||||
| 559 | if ( $opts->{'prefix'} ) { | ||||
| 560 | |||||
| 561 | $_ = File::Spec->catfile($dir, $_) for @dir_entries; | ||||
| 562 | } | ||||
| 563 | |||||
| 564 | return @dir_entries if wantarray ; | ||||
| 565 | 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 | 1 | 1µs | my %err_func = ( | ||
| 578 | 'carp' => \&carp, | ||||
| 579 | 'croak' => \&croak, | ||||
| 580 | ) ; | ||||
| 581 | |||||
| 582 | sub _error { | ||||
| 583 | |||||
| 584 | my( $opts, $err_msg ) = @_ ; | ||||
| 585 | |||||
| 586 | # get the error function to use | ||||
| 587 | |||||
| 588 | 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 | return unless $func ; | ||||
| 594 | |||||
| 595 | # call the carp/croak function | ||||
| 596 | |||||
| 597 | $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 | return undef ; | ||||
| 603 | } | ||||
| 604 | |||||
| 605 | 1 | 11µs | 1; | ||
| 606 | __END__ | ||||
# spent 2µs within File::Slurp::CORE:match which was called:
# once (2µs+0s) by main::BEGIN@19 at line 59 | |||||
# spent 300ns within File::Slurp::__ANON__ which was called:
# once (300ns+0s) by File::Slurp::BEGIN@13 at line 13 |