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 | BEGIN@16 | File::Slurp::
1 | 1 | 1 | 1.05ms | 1.22ms | BEGIN@128 | File::Slurp::
1 | 1 | 1 | 7µs | 9µs | BEGIN@3 | File::Slurp::
1 | 1 | 1 | 6µs | 6µs | BEGIN@13 | File::Slurp::
1 | 1 | 1 | 5µs | 12µs | BEGIN@17 | File::Slurp::
1 | 1 | 1 | 4µs | 8µs | BEGIN@10 | File::Slurp::
1 | 1 | 1 | 4µs | 21µs | BEGIN@4 | File::Slurp::
1 | 1 | 1 | 3µs | 19µs | BEGIN@9 | File::Slurp::
1 | 1 | 1 | 3µs | 193µs | BEGIN@11 | File::Slurp::
1 | 1 | 1 | 3µs | 29µs | BEGIN@14 | File::Slurp::
1 | 1 | 1 | 2µs | 2µs | BEGIN@12 | File::Slurp::
1 | 1 | 1 | 2µs | 2µs | CORE:match (opcode) | File::Slurp::
1 | 1 | 1 | 1µs | 1µs | BEGIN@15 | File::Slurp::
1 | 1 | 1 | 300ns | 300ns | __ANON__ (xsub) | File::Slurp::
0 | 0 | 0 | 0s | 0s | _check_ref | File::Slurp::
0 | 0 | 0 | 0s | 0s | _error | File::Slurp::
0 | 0 | 0 | 0s | 0s | _seek_data_handle | File::Slurp::
0 | 0 | 0 | 0s | 0s | append_file | File::Slurp::
0 | 0 | 0 | 0s | 0s | edit_file | File::Slurp::
0 | 0 | 0 | 0s | 0s | edit_file_lines | File::Slurp::
0 | 0 | 0 | 0s | 0s | prepend_file | File::Slurp::
0 | 0 | 0 | 0s | 0s | read_dir | File::Slurp::
0 | 0 | 0 | 0s | 0s | read_file | File::Slurp::
0 | 0 | 0 | 0s | 0s | write_file | File::Slurp::
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 |