package File::FilterFuncs; use strict; use warnings; use Exporter (); use Carp qw(croak confess); BEGIN { our $VERSION = '0.53_01'; $VERSION = eval $VERSION; our @EXPORT_OK = qw(filters filter_funcs $KEEP_LINE $IGNORE_LINE); our %EXPORT_TAGS = (all => [@EXPORT_OK]); our @ISA = qw(Exporter); *KEEP_LINE = \1; *IGNORE_LINE = \0; } # These are options that accept arguments. my @arg_options = qw(binmode boutmode grepper $/); my %arg_options = map +($_ => 1), @arg_options; sub filters { local $_; local $/ = $/; my %opts = &parse_args; my $in = open_handle($opts{source}, '<'); my $out = open_handle($opts{dest}, '>'); binmode $in, $opts{binmode} if $opts{binmode}; binmode $out, $opts{boutmode} if $opts{boutmode}; $/ = $opts{'$/'} if exists($opts{'$/'}); NEXTLINE: while ($_ = <$in>) { foreach my $transform (@{$opts{subs}}) { next NEXTLINE unless $transform->(); } print $out $_; } # Close the output and input handles only if they # were opened by us. unless (ref $opts{dest}) { close $out or croak("Can't close '$opts{dest}'"); } unless (ref $opts{source}) { close $in or croak("Can't close '$opts{source}'"); } } sub parse_args { local $_; my %hash; # die "No source file name" unless ($_[0] && '' eq ref $_[0]); # die "No destination file name" unless ($_[-1] && '' eq ref $_[-1]); die "No source file name (or handle)" unless ($_[0]); die "No destination file name (or handle)" unless ($_[-1]); $hash{source} = shift; $hash{dest} = pop; if ($hash{dest} eq $hash{source}) { die("Cannot filter '$hash{source}' onto itself."); } while (@_) { $_ = shift; if ($arg_options{$_}) { $hash{$_} = shift; } elsif ('CODE' eq ref($_)) { push @{$hash{subs}}, $_; } } %hash; } sub open_handle { my ($fname, $op) = @_; # print "REF = $fname\n"; return $fname if (ref($fname) =~ /^(?:GLOB|FileHandle|IO::File)$/); my $wstr = ($op =~ />/) ? 'writing' : 'reading'; open my $fh, $op, $fname or confess("Can't open '$fname' for $wstr: $!"); $fh; } BEGIN { *filter_funcs = \&filters; } 1;