| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package File::Edit::Portable; | 
| 2 | 17 |  |  | 17 |  | 351768 | use 5.008; | 
|  | 17 |  |  |  |  | 44 |  | 
| 3 | 17 |  |  | 17 |  | 63 | use strict; | 
|  | 17 |  |  |  |  | 17 |  | 
|  | 17 |  |  |  |  | 287 |  | 
| 4 | 17 |  |  | 17 |  | 53 | use warnings; | 
|  | 17 |  |  |  |  | 15 |  | 
|  | 17 |  |  |  |  | 1023 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | $SIG{__WARN__} = sub { confess(shift); }; | 
| 7 |  |  |  |  |  |  | our $VERSION = '1.24'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 17 |  |  | 17 |  | 61 | use Carp; | 
|  | 17 |  |  |  |  | 28 |  | 
|  | 17 |  |  |  |  | 1125 |  | 
| 10 | 17 |  |  | 17 |  | 63 | use Exporter; | 
|  | 17 |  |  |  |  | 16 |  | 
|  | 17 |  |  |  |  | 512 |  | 
| 11 | 17 |  |  | 17 |  | 55 | use Fcntl qw(:flock); | 
|  | 17 |  |  |  |  | 19 |  | 
|  | 17 |  |  |  |  | 1693 |  | 
| 12 | 17 |  |  | 17 |  | 7712 | use File::Find::Rule; | 
|  | 17 |  |  |  |  | 99761 |  | 
|  | 17 |  |  |  |  | 175 |  | 
| 13 | 17 |  |  | 17 |  | 7329 | use File::Temp; | 
|  | 17 |  |  |  |  | 155092 |  | 
|  | 17 |  |  |  |  | 1238 |  | 
| 14 | 17 |  |  | 17 |  | 7792 | use POSIX qw(uname); | 
|  | 17 |  |  |  |  | 80703 |  | 
|  | 17 |  |  |  |  | 123 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | our @ISA = qw(Exporter); | 
| 17 |  |  |  |  |  |  | our @EXPORT_OK = qw( | 
| 18 |  |  |  |  |  |  | recsep | 
| 19 |  |  |  |  |  |  | platform_recsep | 
| 20 |  |  |  |  |  |  | ); | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | sub new { | 
| 23 | 60 |  |  | 60 | 1 | 32595 | return bless {}, shift; | 
| 24 |  |  |  |  |  |  | } | 
| 25 |  |  |  |  |  |  | sub read { | 
| 26 | 112 |  |  | 112 | 1 | 20744 | my $self = shift; | 
| 27 | 112 |  |  |  |  | 200 | my ($file, $testing); | 
| 28 |  |  |  |  |  |  |  | 
| 29 | 112 | 100 |  |  |  | 210 | if ($_[0] eq 'file'){ | 
| 30 | 8 |  |  |  |  | 42 | $self->_config(@_); | 
| 31 |  |  |  |  |  |  | } | 
| 32 |  |  |  |  |  |  | else { | 
| 33 | 104 |  |  |  |  | 99 | $file = shift; | 
| 34 | 104 | 100 |  |  |  | 205 | $testing = shift if @_; | 
| 35 | 104 |  |  |  |  | 224 | $self->_config(file => $file, testing => $testing); | 
| 36 |  |  |  |  |  |  | } | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 112 |  |  |  |  | 125 | $file = $self->{file}; | 
| 39 | 112 |  |  |  |  | 106 | $testing = $self->{testing}; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 112 | 100 |  |  |  | 164 | if (! $file){ | 
| 42 | 1 |  |  |  |  | 86 | confess "read() requires a file name sent in!"; | 
| 43 |  |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 111 |  |  |  |  | 179 | $self->recsep($file); | 
| 46 | 111 |  |  |  |  | 257 | $self->{files}{$file}{is_read} = 1; | 
| 47 | 111 |  |  |  |  | 166 | $self->{files}{$file}{recsep} = $self->{recsep}; | 
| 48 | 111 |  |  |  |  | 109 | $self->{reads}{count} = keys %{ $self->{files} }; | 
|  | 111 |  |  |  |  | 251 |  | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 111 |  |  |  |  | 93 | my $fh; | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 111 | 100 |  |  |  | 166 | if (! wantarray){ | 
| 53 | 54 |  |  |  |  | 105 | $fh = $self->_handle($file); | 
| 54 | 54 |  |  |  |  | 1320 | return $fh; | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  | else { | 
| 57 | 57 |  |  |  |  | 86 | $fh = $self->_binmode_handle($file); | 
| 58 | 57 |  |  |  |  | 544 | my @contents = <$fh>; | 
| 59 | 57 | 50 |  |  |  | 281 | close $fh or confess "read() can't close file $file!: $!"; | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 57 | 100 |  |  |  | 89 | if (! $testing){ | 
| 62 | 55 |  |  |  |  | 83 | for (@contents){ | 
| 63 | 474 |  |  |  |  | 483 | $_ = $self->_strip_ends($_); | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  | } | 
| 66 | 57 |  |  |  |  | 281 | return @contents; | 
| 67 |  |  |  |  |  |  | } | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  | sub write { | 
| 70 | 76 |  |  | 76 | 1 | 7410 | my $self = shift; | 
| 71 | 76 |  |  |  |  | 191 | my %p = @_; | 
| 72 | 76 |  |  |  |  | 175 | $self->_config(%p); | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 76 | 100 |  |  |  | 1073 | if (! $self->{file}){ | 
| 75 | 2 |  |  |  |  | 315 | confess "write() requires a file to be passed in!"; | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 74 |  | 100 |  |  | 163 | my $reads_count = $self->{reads}{count} || 0; | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 74 | 100 | 100 |  |  | 201 | if ($reads_count > 1 && ! $p{file}){ | 
| 81 |  |  |  |  |  |  | confess "\nif calling write() with more than one read() open, you must " . | 
| 82 |  |  |  |  |  |  | "send in a file name with the 'file' parameter so we know " . | 
| 83 |  |  |  |  |  |  | "which file to write. You currently have the following files " . | 
| 84 | 2 |  |  |  |  | 1 | "open: " . join(' ', keys %{ $self->{files} }) . "\n"; | 
|  | 2 |  |  |  |  | 260 |  | 
| 85 |  |  |  |  |  |  | } | 
| 86 | 72 | 100 |  |  |  | 144 | if (! $self->{contents}){ | 
| 87 | 1 |  |  |  |  | 84 | confess "write() requires 'contents' param sent in"; | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 71 |  |  |  |  | 207 | my $file = $self->{file}; # needed for cleanup of open file list | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 71 | 100 |  |  |  | 142 | if (! $self->{files}{$file}{is_read}){ | 
| 93 | 6 |  |  |  |  | 15 | $self->{files}{$file}{recsep} = $self->recsep($file); | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 71 | 100 |  |  |  | 146 | $self->{file} = $self->{copy} if $self->{copy}; | 
| 97 |  |  |  |  |  |  |  | 
| 98 | 71 |  |  |  |  | 128 | my $wfh = $self->_binmode_handle($self->{file}, 'w'); | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | # certain FreeBSD versions on amd64 don't work | 
| 101 |  |  |  |  |  |  | # with flock() | 
| 102 |  |  |  |  |  |  |  | 
| 103 | 71 |  |  |  |  | 470 | my @os = uname(); | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 71 | 50 | 33 |  |  | 210 | unless ($os[0] eq 'FreeBSD' && $os[-1] eq 'amd64'){ | 
| 106 | 71 |  |  |  |  | 245 | flock $wfh, LOCK_EX; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | my $recsep = defined $self->{custom_recsep} | 
| 110 |  |  |  |  |  |  | ? $self->{custom_recsep} | 
| 111 | 71 | 100 |  |  |  | 172 | : $self->{files}{$file}{recsep}; | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 71 |  |  |  |  | 68 | my $contents = $self->{contents}; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 71 | 100 | 100 |  |  | 256 | if (ref($contents) eq 'GLOB' || ref($contents) eq 'File::Temp') { | 
| 116 |  |  |  |  |  |  | { | 
| 117 | 49 |  |  |  |  | 45 | my $warn; | 
|  | 49 |  |  |  |  | 33 |  | 
| 118 | 49 |  |  | 1 |  | 278 | local $SIG{__WARN__} = sub { $warn = shift; }; | 
|  | 1 |  |  |  |  | 24 |  | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 49 |  |  |  |  | 542 | seek $contents, 0, 0; | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 49 | 100 |  |  |  | 222 | if ($warn) { | 
| 123 | 1 |  |  |  |  | 153 | confess "\nthe file handle you're passing into write() as ". | 
| 124 |  |  |  |  |  |  | "the contents param has already been closed\n"; | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | }; | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 48 |  |  |  |  | 292 | while (<$contents>){ | 
| 130 | 221 |  |  |  |  | 276 | $_ = $self->_strip_ends($_); | 
| 131 | 221 |  |  |  |  | 730 | print $wfh $_ . $recsep; | 
| 132 |  |  |  |  |  |  | } | 
| 133 | 48 |  |  |  |  | 374 | close $contents; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  | else { | 
| 136 | 22 |  |  |  |  | 35 | for (@$contents){ | 
| 137 | 250 |  |  |  |  | 251 | $_ = $self->_strip_ends($_); | 
| 138 | 250 |  |  |  |  | 333 | print $wfh $_ . $recsep; | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  |  | 
| 142 | 70 |  |  |  |  | 1474 | close $wfh; | 
| 143 | 70 |  |  |  |  | 192 | delete $self->{files}{$file}; # cleanup open list | 
| 144 | 70 | 100 |  |  |  | 60 | $self->{reads}{count} = 0 if keys %{ $self->{files} } == 0; | 
|  | 70 |  |  |  |  | 239 |  | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 70 |  |  |  |  | 276 | return 1; | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  | sub splice { | 
| 149 | 17 |  |  | 17 | 1 | 96 | my $self = shift; | 
| 150 | 17 |  |  |  |  | 30 | $self->_config(@_); | 
| 151 |  |  |  |  |  |  |  | 
| 152 | 17 |  |  |  |  | 19 | my $file = $self->{file}; | 
| 153 | 17 |  |  |  |  | 14 | my $copy = $self->{copy}; | 
| 154 | 17 |  |  |  |  | 13 | my $insert = $self->{insert}; | 
| 155 | 17 | 100 |  |  |  | 29 | my $limit = defined $self->{limit} ? $self->{limit} : 1; | 
| 156 |  |  |  |  |  |  |  | 
| 157 | 17 | 100 |  |  |  | 31 | if (! $insert){ | 
| 158 | 1 |  |  |  |  | 163 | confess "splice() requires insert => [aref] param"; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 16 |  |  |  |  | 17 | my ($line, $find) = ($self->{line}, $self->{find}); | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 16 | 100 | 66 |  |  | 40 | if (! defined $line && ! defined $find){ | 
| 164 | 1 |  |  |  |  | 148 | confess | 
| 165 |  |  |  |  |  |  | "splice() requires either the 'line' or 'find' parameter sent in."; | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 15 | 100 | 100 |  |  | 37 | if (defined $line && defined $find){ | 
| 169 | 1 |  |  |  |  | 17 | warn | 
| 170 |  |  |  |  |  |  | "splice() can't search for both line and find. Operating on 'line'."; | 
| 171 |  |  |  |  |  |  | } | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 15 |  |  |  |  | 26 | my @contents = $self->read($file); | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 14 | 100 |  |  |  | 25 | if (defined $line){ | 
| 176 | 4 | 100 |  |  |  | 15 | if ($line !~ /^[0-9]+$/){ | 
| 177 | 1 |  |  |  |  | 89 | confess "splice() requires its 'line' param to contain only an " . | 
| 178 |  |  |  |  |  |  | "integer. You supplied: $line\n"; | 
| 179 |  |  |  |  |  |  | } | 
| 180 | 3 |  |  |  |  | 8 | splice @contents, $line, 0, @$insert; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 13 | 100 | 100 |  |  | 44 | if (defined $find && ! defined $line){ | 
| 184 | 10 | 50 |  |  |  | 50 | $find = qr{$find} if ! ref $find ne 'Regexp'; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 10 |  |  |  |  | 9 | my $i = 0; | 
| 187 | 10 |  |  |  |  | 7 | my $inserts = 0; | 
| 188 |  |  |  |  |  |  |  | 
| 189 | 10 |  |  |  |  | 12 | for (@contents){ | 
| 190 | 75 |  |  |  |  | 44 | $i++; | 
| 191 | 75 | 100 |  |  |  | 143 | if (/$find/){ | 
| 192 | 21 |  |  |  |  | 11 | $inserts++; | 
| 193 | 21 |  |  |  |  | 35 | splice @contents, $i, 0, @$insert; | 
| 194 | 21 | 100 |  |  |  | 25 | if ($limit){ | 
| 195 | 17 | 100 |  |  |  | 31 | last if $inserts == $limit; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  | } | 
| 200 |  |  |  |  |  |  |  | 
| 201 | 13 |  |  |  |  | 22 | $self->write(contents => \@contents, copy => $copy); | 
| 202 |  |  |  |  |  |  |  | 
| 203 | 13 |  |  |  |  | 74 | return @contents; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  | sub dir { | 
| 206 | 18 |  |  | 18 | 1 | 7003 | my $self = shift; | 
| 207 | 18 |  |  |  |  | 45 | $self->_config(@_); | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 18 |  |  |  |  | 24 | my $recsep = $self->{custom_recsep}; | 
| 210 |  |  |  |  |  |  |  | 
| 211 | 18 |  |  |  |  | 18 | my @types; | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 18 | 100 |  |  |  | 32 | if ($self->{types}){ | 
| 214 | 8 |  |  |  |  | 6 | @types = @{ $self->{types} }; | 
|  | 8 |  |  |  |  | 15 |  | 
| 215 |  |  |  |  |  |  | } | 
| 216 |  |  |  |  |  |  | else { | 
| 217 | 10 |  |  |  |  | 18 | @types = qw(*); | 
| 218 |  |  |  |  |  |  | } | 
| 219 |  |  |  |  |  |  |  | 
| 220 | 18 |  |  |  |  | 98 | my $find = File::Find::Rule->new; | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 18 | 100 |  |  |  | 162 | $find->maxdepth($self->{maxdepth}) if $self->{maxdepth}; | 
| 223 | 18 |  |  |  |  | 435 | $find->file; | 
| 224 | 18 |  |  |  |  | 419 | $find->name(@types); | 
| 225 |  |  |  |  |  |  |  | 
| 226 | 18 |  |  |  |  | 1341 | my @files = $find->in($self->{dir}); | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 18 | 100 |  |  |  | 11315 | return @files if $self->{list}; | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 10 |  |  |  |  | 18 | for my $file (@files){ | 
| 231 |  |  |  |  |  |  |  | 
| 232 | 23 |  |  |  |  | 43 | my $fh = $self->read($file); | 
| 233 | 23 |  |  |  |  | 40 | my $wfh = $self->tempfile; | 
| 234 |  |  |  |  |  |  |  | 
| 235 | 23 |  |  |  |  | 208 | while(<$fh>){ | 
| 236 | 69 |  |  |  |  | 187 | print $wfh $_; | 
| 237 |  |  |  |  |  |  | } | 
| 238 | 23 |  |  |  |  | 250 | close $fh; | 
| 239 |  |  |  |  |  |  |  | 
| 240 | 23 | 100 |  |  |  | 67 | $self->write( | 
| 241 |  |  |  |  |  |  | file => $file, | 
| 242 |  |  |  |  |  |  | contents => $wfh, | 
| 243 |  |  |  |  |  |  | recsep => defined $recsep | 
| 244 |  |  |  |  |  |  | ? $recsep | 
| 245 |  |  |  |  |  |  | : $self->platform_recsep, | 
| 246 |  |  |  |  |  |  | ); | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 10 |  |  |  |  | 73 | return @files; | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  | sub recsep { | 
| 252 | 226 | 100 |  | 226 | 1 | 9700 | my $self = ref $_[0] eq __PACKAGE__ | 
| 253 |  |  |  |  |  |  | ? shift | 
| 254 |  |  |  |  |  |  | : __PACKAGE__->new; | 
| 255 |  |  |  |  |  |  |  | 
| 256 | 226 |  |  |  |  | 198 | my $file = shift; | 
| 257 | 226 |  |  |  |  | 168 | my $want = shift; | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 226 |  |  |  |  | 184 | my $fh; | 
| 260 | 226 |  |  |  |  | 213 | eval { | 
| 261 | 226 |  |  |  |  | 296 | $fh = $self->_binmode_handle($file); | 
| 262 |  |  |  |  |  |  | }; | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 226 | 100 | 100 |  |  | 2177 | if ($@ || -z $fh){ | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | # we've got an empty file... | 
| 267 |  |  |  |  |  |  | # we'll set recsep to the local platform's | 
| 268 |  |  |  |  |  |  |  | 
| 269 | 9 |  |  |  |  | 26 | $self->{recsep} = $self->platform_recsep; | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | return $want | 
| 272 |  |  |  |  |  |  | ? $self->_convert_recsep($self->{recsep}, $want) | 
| 273 | 9 | 100 |  |  |  | 35 | : $self->{recsep}; | 
| 274 |  |  |  |  |  |  | } | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 217 |  |  |  |  | 480 | seek $fh, 0, 0; | 
| 277 |  |  |  |  |  |  |  | 
| 278 | 217 |  |  |  |  | 343 | my $recsep_regex = $self->_recsep_regex; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 217 | 50 |  |  |  | 2396 | if (<$fh> =~ /$recsep_regex/){ | 
| 281 | 217 |  |  |  |  | 490 | $self->{recsep} = $1; | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 217 | 50 |  |  |  | 1297 | close $fh or confess "recsep() can't close file $file!: $!"; | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | return $want | 
| 287 |  |  |  |  |  |  | ? $self->_convert_recsep($self->{recsep}, $want) | 
| 288 | 217 | 100 |  |  |  | 604 | : $self->{recsep}; | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  | sub platform_recsep { | 
| 291 | 183 | 50 |  | 183 | 1 | 820 | my $self = ref $_[0] eq __PACKAGE__ | 
| 292 |  |  |  |  |  |  | ? shift | 
| 293 |  |  |  |  |  |  | : __PACKAGE__->new; | 
| 294 |  |  |  |  |  |  |  | 
| 295 | 183 |  |  |  |  | 141 | my $want = shift; | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 183 |  |  |  |  | 289 | my $file = $self->_temp_filename; | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | # for platform_recsep(), we need the file open in ASCII mode, | 
| 300 |  |  |  |  |  |  | # so we can't use _binmode_handle() or File::Temp | 
| 301 |  |  |  |  |  |  |  | 
| 302 | 183 | 50 |  |  |  | 23486 | open my $wfh, '>', $file | 
| 303 |  |  |  |  |  |  | or confess | 
| 304 |  |  |  |  |  |  | "platform_recsep() can't open temp file $file for writing!: $!"; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 183 |  |  |  |  | 771 | print $wfh "abc\n"; | 
| 307 |  |  |  |  |  |  |  | 
| 308 | 183 | 50 |  |  |  | 4784 | close $wfh | 
| 309 |  |  |  |  |  |  | or confess "platform_recsep() can't close write temp file $file: $!"; | 
| 310 |  |  |  |  |  |  |  | 
| 311 | 183 |  |  |  |  | 395 | my $fh = $self->_binmode_handle($file); | 
| 312 |  |  |  |  |  |  |  | 
| 313 | 183 |  |  |  |  | 318 | my $recsep_regex = $self->_recsep_regex; | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 183 | 50 |  |  |  | 1894 | if (<$fh> =~ /$recsep_regex/){ | 
| 316 | 183 |  |  |  |  | 485 | $self->{platform_recsep} = $1; | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 | 183 | 50 |  |  |  | 832 | close $fh | 
| 320 |  |  |  |  |  |  | or confess "platform_recsep() can't close temp file $file after run: $!"; | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | return $want | 
| 323 |  |  |  |  |  |  | ? $self->_convert_recsep($self->{platform_recsep}, $want) | 
| 324 | 183 | 100 |  |  |  | 784 | : $self->{platform_recsep}; | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  | sub tempfile { | 
| 327 |  |  |  |  |  |  | # returns a temporary file handle in write mode | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 41 |  |  | 41 | 1 | 157 | my $wfh = File::Temp->new(UNLINK => 1); | 
| 330 | 41 |  |  |  |  | 10010 | return $wfh; | 
| 331 |  |  |  |  |  |  | } | 
| 332 |  |  |  |  |  |  | sub _config { | 
| 333 |  |  |  |  |  |  | # configures self with incoming params | 
| 334 |  |  |  |  |  |  |  | 
| 335 | 223 |  |  | 223 |  | 189 | my $self = shift; | 
| 336 | 223 |  |  |  |  | 423 | my %p = @_; | 
| 337 |  |  |  |  |  |  |  | 
| 338 | 223 |  |  |  |  | 327 | $self->{custom_recsep} = $p{recsep}; | 
| 339 | 223 |  |  |  |  | 198 | delete $p{recsep}; | 
| 340 |  |  |  |  |  |  |  | 
| 341 | 223 |  |  |  |  | 437 | my @params = qw( | 
| 342 |  |  |  |  |  |  | testing copy types list maxdepth | 
| 343 |  |  |  |  |  |  | insert line find limit | 
| 344 |  |  |  |  |  |  | ); | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 223 |  |  |  |  | 301 | for (@params){ | 
| 347 | 2007 |  |  |  |  | 1610 | delete $self->{$_}; | 
| 348 |  |  |  |  |  |  | } | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 223 |  |  |  |  | 373 | for (keys %p){ | 
| 351 | 489 |  |  |  |  | 1787 | $self->{$_} = $p{$_}; | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  | sub _handle { | 
| 355 |  |  |  |  |  |  | # returns a handle with platform's record separator | 
| 356 |  |  |  |  |  |  |  | 
| 357 | 54 |  |  | 54 |  | 47 | my $self = shift; | 
| 358 | 54 |  |  |  |  | 48 | my $file = shift; | 
| 359 |  |  |  |  |  |  |  | 
| 360 | 54 |  |  |  |  | 41 | my $fh; | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 54 | 100 |  |  |  | 74 | if ($self->recsep($file, 'hex') ne $self->platform_recsep('hex')){ | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 16 |  |  |  |  | 40 | $fh = $self->_binmode_handle($file); | 
| 365 | 16 |  |  |  |  | 38 | my $temp_wfh = $self->tempfile; | 
| 366 | 16 |  |  |  |  | 53 | binmode $temp_wfh, ':raw'; | 
| 367 |  |  |  |  |  |  |  | 
| 368 | 16 |  |  |  |  | 36 | my $temp_filename = $temp_wfh->filename; | 
| 369 |  |  |  |  |  |  |  | 
| 370 | 16 |  |  |  |  | 177 | while (<$fh>){ | 
| 371 | 92 |  |  |  |  | 133 | $_ = $self->_platform_replace($_); | 
| 372 | 92 |  |  |  |  | 406 | print $temp_wfh $_; | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 16 | 50 |  |  |  | 68 | close $fh or confess "can't close file $file: $!"; | 
| 376 | 16 | 50 |  |  |  | 404 | close $temp_wfh or confess "can't close file $temp_filename: $!"; | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 16 |  |  |  |  | 34 | my $ret_fh = $self->_binmode_handle($temp_filename); | 
| 379 |  |  |  |  |  |  |  | 
| 380 | 16 |  |  |  |  | 52 | return $ret_fh; | 
| 381 |  |  |  |  |  |  | } | 
| 382 |  |  |  |  |  |  | else { | 
| 383 | 38 |  |  |  |  | 55 | $fh = $self->_binmode_handle($file); | 
| 384 | 38 |  |  |  |  | 60 | return $fh; | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  | sub _binmode_handle { | 
| 388 |  |  |  |  |  |  | # returns a handle opened with binmode :raw | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 608 |  |  | 608 |  | 632 | my $self = shift; | 
| 391 | 608 |  |  |  |  | 520 | my $file = shift; | 
| 392 | 608 |  | 100 |  |  | 1625 | my $mode = shift || 'r'; | 
| 393 |  |  |  |  |  |  |  | 
| 394 | 608 |  |  |  |  | 386 | my $fh; | 
| 395 |  |  |  |  |  |  |  | 
| 396 | 608 | 100 |  |  |  | 1118 | if ($mode =~ /^w/){ | 
| 397 | 71 | 50 |  |  |  | 3650 | open $fh, '>', $file | 
| 398 |  |  |  |  |  |  | or confess "_binmode_handle() can't open file $file for writing!: $!"; | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  | else { | 
| 401 | 537 | 100 |  |  |  | 12449 | open $fh, '<', $file | 
| 402 |  |  |  |  |  |  | or confess "_binmode_handle() can't open file $file for reading!: $!"; | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 601 |  |  |  |  | 1706 | binmode $fh, ':raw'; | 
| 406 |  |  |  |  |  |  |  | 
| 407 | 601 |  |  |  |  | 992 | return $fh; | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  | sub _convert_recsep { | 
| 410 |  |  |  |  |  |  | # converts recsep to either hex or OS name (ie. type) | 
| 411 |  |  |  |  |  |  |  | 
| 412 | 175 |  |  | 175 |  | 2996 | my ($self, $sep, $want) = @_; | 
| 413 |  |  |  |  |  |  |  | 
| 414 | 175 |  |  |  |  | 425 | $sep = unpack "H*", $sep; | 
| 415 | 175 |  |  |  |  | 451 | $sep =~ s/0/\\0/g; | 
| 416 |  |  |  |  |  |  |  | 
| 417 | 175 | 100 |  |  |  | 845 | return $sep if $want eq 'hex'; | 
| 418 |  |  |  |  |  |  |  | 
| 419 | 23 |  |  |  |  | 68 | my %seps = ( | 
| 420 |  |  |  |  |  |  | '\0a'    => 'nix', | 
| 421 |  |  |  |  |  |  | '\0d\0a' => 'win', | 
| 422 |  |  |  |  |  |  | '\0d'    => 'mac', | 
| 423 |  |  |  |  |  |  | ); | 
| 424 |  |  |  |  |  |  |  | 
| 425 | 23 |  | 100 |  |  | 132 | return $seps{$sep} || 'unknown'; | 
| 426 |  |  |  |  |  |  | } | 
| 427 |  |  |  |  |  |  | sub _recsep_regex { | 
| 428 |  |  |  |  |  |  | # returns a regex object representing all recseps | 
| 429 | 1437 |  |  | 1437 |  | 2737 | return qr/([\n\x{0B}\f\r\x{85}]{1,2})/; | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  | sub _platform_replace { | 
| 432 |  |  |  |  |  |  | # replace recseps in a string with the platform recsep | 
| 433 |  |  |  |  |  |  |  | 
| 434 | 92 |  |  | 92 |  | 115 | my ($self, $str) = @_; | 
| 435 | 92 |  |  |  |  | 106 | my $re = $self->_recsep_regex; | 
| 436 | 92 |  |  |  |  | 362 | $str =~ s/$re/$self->platform_recsep/ge; | 
|  | 98 |  |  |  |  | 179 |  | 
| 437 | 92 |  |  |  |  | 199 | return $str; | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  | sub _strip_ends { | 
| 440 |  |  |  |  |  |  | # strip all line endings from string | 
| 441 |  |  |  |  |  |  |  | 
| 442 | 945 |  |  | 945 |  | 763 | my ($self, $str) = @_; | 
| 443 | 945 |  |  |  |  | 825 | my $re = $self->_recsep_regex; | 
| 444 | 945 |  |  |  |  | 2081 | $str =~ s/$re//g; | 
| 445 | 945 |  |  |  |  | 1313 | return $str; | 
| 446 |  |  |  |  |  |  | } | 
| 447 |  |  |  |  |  |  | sub _temp_filename { | 
| 448 |  |  |  |  |  |  | # return the name of a temporary file | 
| 449 |  |  |  |  |  |  |  | 
| 450 | 186 |  |  | 186 |  | 1853 | my $temp_fh = File::Temp->new(UNLINK => 1); | 
| 451 | 186 |  |  |  |  | 426217 | my $filename = $temp_fh->filename; | 
| 452 |  |  |  |  |  |  |  | 
| 453 | 186 | 50 |  |  |  | 1813 | close $temp_fh | 
| 454 |  |  |  |  |  |  | or confess "_temp_filename() can't close the $filename temp file: $!"; | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 186 |  |  |  |  | 488 | return $filename; | 
| 457 |  |  |  |  |  |  | } | 
| 458 | 1 |  |  | 1 |  | 9 | sub _vim_placeholder { return 1; }; # for folding | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | 1; | 
| 461 |  |  |  |  |  |  | __END__ |