diff --git a/applets/pbot-vm/guest/lib/Languages/_c_base.pm b/applets/pbot-vm/guest/lib/Languages/_c_base.pm index d0ffb71c..c6ddf4c8 100755 --- a/applets/pbot-vm/guest/lib/Languages/_c_base.pm +++ b/applets/pbot-vm/guest/lib/Languages/_c_base.pm @@ -9,6 +9,8 @@ use strict; package _c_base; use parent '_default'; +use SplitLine; + sub preprocess { my $self = shift; @@ -18,7 +20,7 @@ sub preprocess { print $fh "$input\n"; close $fh; - my @cmd = $self->split_line($self->{cmdline}, strip_quotes => 1, preserve_escapes => 0); + my @cmd = split_line($self->{cmdline}, strip_quotes => 1, preserve_escapes => 0); if ($self->{code} =~ m/print_last_statement\(.*\);$/m) { # remove print_last_statement wrapper in order to get warnings/errors from last statement line @@ -85,7 +87,7 @@ sub postprocess { my $ulimits = "ulimit -f 2000; ulimit -t 8; ulimit -u 200"; - my @args = $self->split_line($self->{arguments}, strip_quotes => 1, preserve_escapes => 1); + my @args = split_line($self->{arguments}, strip_quotes => 1, preserve_escapes => 1); my $quoted_args = ''; diff --git a/applets/pbot-vm/guest/lib/Languages/_default.pm b/applets/pbot-vm/guest/lib/Languages/_default.pm index 46d9eae8..1c834f32 100755 --- a/applets/pbot-vm/guest/lib/Languages/_default.pm +++ b/applets/pbot-vm/guest/lib/Languages/_default.pm @@ -11,6 +11,8 @@ use strict; use IPC::Run qw/run timeout/; use Encode; +use SplitLine; + use Data::Dumper; $Data::Dumper::Terse = 1; $Data::Dumper::Sortkeys = 1; @@ -101,119 +103,10 @@ sub execute { return ($exitval, $stdout, $stderr); } -# splits line into arguments separated by unquoted whitespace. -# handles unbalanced quotes by treating them as part of the -# argument they were found within. -sub split_line { - my ($self, $line, %opts) = @_; - - my %default_opts = ( - strip_quotes => 0, - keep_spaces => 0, - preserve_escapes => 1, - ); - - %opts = (%default_opts, %opts); - - my @chars = split //, $line; - - my @args; - my $escaped = 0; - my $quote; - my $token = ''; - my $ch = ' '; - my $last_ch; - my $next_ch; - my $i = 0; - my $pos; - my $ignore_quote = 0; - my $spaces = 0; - - while (1) { - $last_ch = $ch; - - if ($i >= @chars) { - if (defined $quote) { - # reached end, but unbalanced quote... reset to beginning of quote and ignore it - $i = $pos; - $ignore_quote = 1; - $quote = undef; - $last_ch = ' '; - $token = ''; - } else { - # add final token and exit - push @args, $token if length $token; - last; - } - } - - $ch = $chars[$i++]; - $next_ch = $chars[$i]; - - $spaces = 0 if $ch ne ' '; - - if ($escaped) { - if ($opts{preserve_escapes}) { - $token .= "\\$ch"; - } else { - $token .= $ch; - } - $escaped = 0; - next; - } - - if ($ch eq '\\') { - $escaped = 1; - next; - } - - if (defined $quote) { - if ($ch eq $quote) { - # closing quote - $token .= $ch unless $opts{strip_quotes}; - $quote = undef; - } else { - # still within quoted argument - $token .= $ch; - } - next; - } - - if (not defined $quote and ($ch eq "'" or $ch eq '"')) { - if ($ignore_quote) { - # treat unbalanced quote as part of this argument - $token .= $ch; - $ignore_quote = 0; - } else { - # begin potential quoted argument - $pos = $i - 1; - $quote = $ch; - $token .= $ch unless $opts{strip_quotes}; - } - next; - } - - if ($ch eq ' ') { - if (++$spaces > 1 and $opts{keep_spaces}) { - $token .= $ch; - next; - } else { - push @args, $token if length $token; - $token = ''; - next; - } - } - - $token .= $ch; - } - - return @args; -} - sub quote_args { my ($self, $text) = @_; - my @args = $self->split_line($text, strip_quotes => 1, preserve_escapes => 1); + my @args = split_line($text, strip_quotes => 1, preserve_escapes => 1); my $quoted = ''; diff --git a/applets/pbot-vm/guest/lib/SplitLine.pm b/applets/pbot-vm/guest/lib/SplitLine.pm new file mode 100644 index 00000000..72ab6d1d --- /dev/null +++ b/applets/pbot-vm/guest/lib/SplitLine.pm @@ -0,0 +1,120 @@ +#!/usr/bin/env perl + +package SplitLine; + +use 5.020; + +use warnings; +use strict; + +use feature 'signatures'; +no warnings 'experimental::signatures'; + +use parent qw(Exporter); +our @EXPORT = qw(split_line); + +# splits line into arguments separated by unquoted whitespace. +# handles unbalanced quotes by treating them as part of the +# argument they were found within. +sub split_line ($line, %opts) { + my %default_opts = ( + strip_quotes => 0, + keep_spaces => 0, + preserve_escapes => 1, + ); + + %opts = (%default_opts, %opts); + + my @chars = split //, $line; + + my @args; + my $escaped = 0; + my $quote; + my $token = ''; + my $last_token = ''; + my $ch = ' '; + my $i = 0; + my $pos = 0; + my $ignore_quote = 0; + my $spaces = 0; + + while (1) { + if ($i >= @chars) { + if (defined $quote) { + # reached end, but unbalanced quote... reset to beginning of quote and ignore it + $i = $pos; + $ignore_quote = 1; + $quote = undef; + $token = $last_token; + } else { + # add final token and exit + push @args, $token if length $token; + last; + } + } + + $ch = $chars[$i++]; + + my $dquote = $quote // 'undef'; + $spaces = 0 if $ch ne ' '; + + if ($escaped) { + if ($opts{preserve_escapes}) { + $token .= "\\$ch"; + } else { + $token .= $ch; + } + $escaped = 0; + next; + } + + if ($ch eq '\\') { + $escaped = 1; + next; + } + + if (defined $quote) { + if ($ch eq $quote) { + # closing quote + $token .= $ch unless $opts{strip_quotes}; + $quote = undef; + } else { + # still within quoted argument + $token .= $ch; + } + next; + } + + if (not defined $quote and ($ch eq "'" or $ch eq '"')) { + if ($ignore_quote) { + # treat unbalanced quote as part of this argument + $token .= $ch; + $ignore_quote = 0; + } else { + # begin potential quoted argument + $pos = $i - 1; + $quote = $ch; + $last_token = $token; + $token .= $ch unless $opts{strip_quotes}; + } + next; + } + + if ($ch eq ' ') { + if (++$spaces > 1 and $opts{keep_spaces}) { + $token .= $ch; + next; + } else { + push @args, $token if length $token; + $token = ''; + next; + } + } + + $token .= $ch; + } + + return @args; +} + +1; diff --git a/applets/pbot-vm/host/lib/SplitLine.pm b/applets/pbot-vm/host/lib/SplitLine.pm index f866da76..72ab6d1d 100644 --- a/applets/pbot-vm/host/lib/SplitLine.pm +++ b/applets/pbot-vm/host/lib/SplitLine.pm @@ -33,23 +33,18 @@ sub split_line ($line, %opts) { my $token = ''; my $last_token = ''; my $ch = ' '; - my $last_ch; - my $next_ch; my $i = 0; my $pos = 0; my $ignore_quote = 0; my $spaces = 0; while (1) { - $last_ch = $ch; - if ($i >= @chars) { if (defined $quote) { # reached end, but unbalanced quote... reset to beginning of quote and ignore it $i = $pos; $ignore_quote = 1; $quote = undef; - $last_ch = ' '; $token = $last_token; } else { # add final token and exit @@ -59,7 +54,6 @@ sub split_line ($line, %opts) { } $ch = $chars[$i++]; - $next_ch = $chars[$i]; my $dquote = $quote // 'undef'; $spaces = 0 if $ch ne ' '; diff --git a/lib/PBot/Core/Interpreter.pm b/lib/PBot/Core/Interpreter.pm index 3298bca5..ea2b5b76 100644 --- a/lib/PBot/Core/Interpreter.pm +++ b/lib/PBot/Core/Interpreter.pm @@ -1203,15 +1203,12 @@ sub split_line($self, $line, %opts) { my $token = ''; my $last_token = ''; my $ch = ' '; - my $last_ch; - my $next_ch; my $i = 0; my $pos; my $ignore_quote = 0; my $spaces = 0; while (1) { - $last_ch = $ch; if ($i >= @chars) { if (defined $quote) { @@ -1219,7 +1216,6 @@ sub split_line($self, $line, %opts) { $i = $pos; $ignore_quote = 1; $quote = undef; - $last_ch = ' '; $token = $last_token; } else { # add final token and exit @@ -1230,7 +1226,6 @@ sub split_line($self, $line, %opts) { } $ch = $chars[$i++]; - $next_ch = $chars[$i]; $spaces = 0 if $ch ne ' '; diff --git a/lib/PBot/VERSION.pm b/lib/PBot/VERSION.pm index d9ff5356..7b81a638 100644 --- a/lib/PBot/VERSION.pm +++ b/lib/PBot/VERSION.pm @@ -25,7 +25,7 @@ use PBot::Imports; # These are set by the /misc/update_version script use constant { BUILD_NAME => "PBot", - BUILD_REVISION => 4815, + BUILD_REVISION => 4816, BUILD_DATE => "2024-10-29", };