Batch-Interpreter
view release on metacpan or search on metacpan
lib/Batch/Interpreter.pm view on Meta::CPAN
sub get_file_attr {
my ($self, $syspath) = @_;
# TODO: too simple
return '--a------';
}
sub get_file_timedate {
my ($self, $syspath, $mode) = @_;
my @localtime = localtime((stat $syspath)[9] // 0);
my @timedate = (
$localtime[5]+1900, $localtime[4]+1, $localtime[3],
$localtime[2], $localtime[1],
);
return ($mode//'') eq 'for'
? $self->{locale}->format_file_timedate_for(@timedate)
: $self->{locale}->format_file_timedate(@timedate)
;
}
sub format_size {
my ($self, $size) = @_;
1 while $size =~ s/(?<=\d)(\d\d\d)(?!\d)/.$1/;
return $size;
}
sub set_subprocess_env {
my ($self, $add_env) = @_;
my %old = %ENV;
my $case = $self->{varcases};
my @copy = grep exists($case->{$_}), keys %{$self->{vars}};
# select the variables that can be safely copied
if ($is_win_host) {
# setting a variable converts its case
#@copy = grep $_ eq ($case->{$_} // 'a'), @copy;
} else {
}
# TODO: convert the variables that have to be translated
@ENV{@$case{@copy}} = @{$self->{vars}}{@copy};
$add_env and
@ENV{keys %$add_env} = values %$add_env;
return %old;
}
sub extract_for_tokens {
my ($opts, $line) = @_;
if ($opts->{skip}) {
$opts->{skip}--;
return;
}
# skip empty lines
$line =~ /\S/ or return;
$opts->{eol_re} and $line =~ s/$opts->{eol_re}/$1/;
return map $_ // '', ($opts->{delim_re}
? split($opts->{delim_re}, $line, $opts->{numvals})
: ($line)
)[@{$opts->{tokens}}];
}
my $re_quoted = qr/ \" (?:\\.|\"\"|[^\\\"])*+ (?:\"|$) /x;
my $re_quotesc = qr/ \^. | $re_quoted /xo;
my $re_string =
qr/ (?: $re_quotesc | \d(?!\>) | [^\<\>\|\&\(\)\"\^\s] )++ /xo;
my $re_lhs =
qr/ (?: $re_quotesc | \d(?!\>) | [^\<\>\|\&\(\)\"\^\s\=] )++ /xo;
my $re_call_arg =
qr/ (?: $re_quotesc | \d(?!\>) | [^\<\>\|\&\(\)\"\^\s\=\,] )++ /xo;
my $re_call_arg_separator = qr/ [\=\,\s] /x;
my $re_redirect = qr/ \< | \d?\>\>?(?:\&\d?)? /x;
my $re_pipe = qr/ \|\|? | \&\&? /x;
my $re_grouping = qr/ [\(\)] /x;
my $any_token = qr/$re_redirect | $re_pipe | $re_grouping | $re_string/x;
sub next_token {
# trailing separator is included to not have to store separators
# separately. the separatator will be removed in unquote_token.
$_[0] =~ /\G ( $any_token \s*+ ) /gcxo
or return;
return $1;
}
sub next_token_no_pipe {
$_[0] =~ /\G ( (?:$re_redirect | $re_grouping | $re_string) \s*+ ) /gcxo
or return;
return $1;
}
sub next_token_string {
$_[0] =~ /\G ( $re_string \s*+ ) /gcxo
or return;
return $1;
}
sub next_token_lhs {
$_[0] =~ /\G ( $re_lhs \s*+ ) /gcxo
or return;
return $1;
}
sub next_token_call_arg {
# semantics different from next_token, because no unquote_token is
# following
$_[0] =~ /\G ( $re_call_arg ) $re_call_arg_separator*+ /gcxo
or return;
return $1;
}
sub unquote_token {
my ($token) = @_;
defined $token or return;
while ($token =~ /\G [^\"\^\s]* ( $re_quotesc | \s+ ) /gcxo) {
my ($p, $q) = (pos($token) - length($1), $1);
lib/Batch/Interpreter.pm view on Meta::CPAN
while (my $token = next_token $list) {
$handle_token->($token);
}
} elsif ($mode eq 'recursive') {
my $scandir = unquote_token $cmd->{scandir};
$cmd->{echo} and $self->print_prompt('for ',
'/r ', $scandir, " %$var in (", $list, ')'
);
my @token;
push @token, $_ while defined($_ = next_token $list);
my $wanted = sub {
-d or return;
my $dir = $self->sys2unc($_);
$handle_token->(File::Spec::Win32->catfile(
$dir, $_
)) for @token;
};
find {
no_chdir => 1, wanted => $wanted,
preprocess => sub {
return sort @_;
},
}, $self->unc2sys($scandir);
} elsif ($mode eq 'numbers') {
my ($start, $step, $end) = split /,/, $list;
s/^\s+//s for $start, $step, $end;
s/\s+$//s for $start, $step, $end;
/^-?\d+$/ or
return $self->syn_error(
"for: '%s' is not a number", $_
)
for $start, $step, $end;
$cmd->{echo} and $self->print_prompt('for ',
"/l %$var in ($start, $step, $end)"
);
for (my $i = $start;
$step > 0 ? $i <= $end
: $step < 0 ? $i >= $end : 0;
$i += $step
) {
local $self->{for_vars}{$var} = $i;
my $result = $self->run_cmd($command);
$result eq 'next' or return $result;
}
} elsif ($mode eq 'lines') {
my $opts = unquote_token $cmd->{line_options};
$cmd->{echo} and $self->print_prompt('for ',
"/f \"$opts\" %$var in (", $list, ')'
);
my %opt;
(@opt{qw(eol skip delims tokens)}, my $usebackq) = (
undef, 0, "\t ", '1', 0
);
$opts =~ /\beol=(.)/i and $opt{eol} = $1;
$opts =~ /\bskip=(\d+)/i and $opt{skip} = $1;
$opts =~ /\bdelims=(.?[^\s]*)/i and $opt{delims} = $1;
$opts =~ /\btokens=(\d[\d,-]*+\*?)/i
and $opt{tokens} = $1;
$opts =~ /\busebackq\b/i and $usebackq = 1;
$opt{eol} and $opt{eol_re} =
qr/^([\Q$opt{eol}\E]+)\Q$opt{eol}\E.*+$/;
$opt{delims} ne ''
and $opt{delim_re} = qr/[\Q$opt{delims}\E]/;
my @token = map {
/^(\d+)\-(\d+)$/ ? ($1 .. $2) : ($_);
} split /,/, $opt{tokens};
if ($token[-1] =~ s/\*$//) {
# 1,* or 1*
$token[-1] eq '' and pop @token;
push @token, $token[-1]+1;
$opt{numvals} = @token;
} else {
$opt{numvals} = @token+1;
}
/^\d++$/ or
return $self->syn_error(
"invalid token '%s'", $_
)
for @token;
$opt{tokens} = [ map $_-1, @token ];
my @var;
my $varcount = "$var";
push @var, $varcount++ for 1..$opt{numvals};
my $type = 'files';
if ( # $usebackq &&
$list =~ /^\s*\"/s && $list =~ /\"\s*+$/s
) {
$type = 'explicit';
$list =~ s/^\s*+\"//s;
$list =~ s/\"\s*+$//s;
} elsif ($usebackq &&
$list =~ /^\s*\`/s && $list =~ /\`\s*+$/s
) {
$type = 'output';
$list =~ s/^\s*+\`//s;
$list =~ s/\`\s*+$//s;
}
local $self->{for_vars} = my $for_vars = {
%{$self->{for_vars}}
};
if ($type eq 'explicit') {
if (my @val = extract_for_tokens \%opt, $list) {
@$for_vars{@var} = @val;
my $result = $self->run_cmd($command);
$result eq 'next' or return $result;
}
} elsif ($type eq 'files') {
$list =~ /^\s+/gc;
while (my $token =
unquote_token next_token $list
) {
open my $fh, '<:crlf',
$self->unc2sys($token)
or return $self->os_error(
$token, 'for'
( run in 3.785 seconds using v1.01-cache-2.11-cpan-8f98c5d2c55 )