package App::Greple::Filter;
use v5.14;
use warnings;
use Exporter 'import';
our @EXPORT = ();
our %EXPORT_TAGS = ();
our @EXPORT_OK = qw();
use Getopt::EX::Func qw(parse_func);
use App::Greple::Common;
sub new {
my $class = shift;
my $obj = bless [], $class;
$obj->append(@_) if @_;
$obj;
}
sub parse {
my $obj = shift;
push @$obj, map { /([^:]+):(.*)/ ? [ $1, $2 ] : $_ } @_;
$obj;
}
sub append {
my $obj = shift;
push @$obj, @_;
$obj;
}
sub get_filters {
my $obj = shift;
my $filename = shift;
my @f;
local $_ = $filename;
for (my $remember = ""; $remember ne $_; ) {
$remember = $_;
for my $p (@$obj) {
if (ref $p eq 'ARRAY') {
my($exp, $command) = @$p;
if (ref $exp eq 'CODE' ? &$exp : eval $exp) {
$command =~ s/{}/$filename/g;
push @f, $command;
last if $_ ne $remember;
}
} else {
push @f, $p;
}
}
}
@f;
}
push @EXPORT, qw(push_output_filter);
sub push_output_filter {
my %arg = ref $_[0] eq 'HASH' ? %{+shift} : ();
my $fh = shift;
my $pkg = caller;
for my $filter (reverse @_) {
$opt_d{F} and warn "Push output Filter: \"$filter\"\n";
my $pid = open($fh, '|-') // die "$filter: $!\n";
if ($pid == 0) {
if ($filter =~ /^&/ and
my $f = parse_func({ PACKAGE => $pkg }, $filter)) {
local @ARGV;
open STDIN, '<&', 0 if eof STDIN;
$f->call;
} else {
do { exec $filter } ;
warn $@ if $@;
}
exit;
}
}
}
push @EXPORT, qw(push_input_filter);
sub push_input_filter {
my %arg = ref $_[0] eq 'HASH' ? %{+shift} : ();
my $pkg = caller;
for my $filter (@_) {
$opt_d{F} and warn "Push input Filter: \"$filter\"\n";
if ($filter =~ /^&/ and
my $f = parse_func({ PACKAGE => $pkg }, $filter)) {
if ($arg{&FILELABEL}) {
$f->append(&FILELABEL => $arg{&FILELABEL});
}
##
## intput filter function is responsible for process fork
##
$f->call;
} else {
my $pid = open(STDIN, '-|') // die "$filter: $!\n";
if ($pid == 0) {
do { exec $filter } ;
warn $@ if $@;
exit;
}
}
}
}
1;