2022-01-23 16:49:23 +01:00
|
|
|
#!/usr/bin/env perl
|
|
|
|
|
|
|
|
# File: vm-exec
|
|
|
|
#
|
|
|
|
# Purpose: Process and send commands to the PBot virtual machine on the
|
|
|
|
# default TCP port (5555). Use the PBOT_VM_PORT environment variable to
|
|
|
|
# override the port. E.g., to use port 6666 instead:
|
|
|
|
#
|
|
|
|
# $ PBOT_VM_PORT=6666 vm-exec -lang=sh echo test
|
|
|
|
|
|
|
|
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
|
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
use warnings;
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
use File::Basename;
|
|
|
|
use JSON::XS;
|
|
|
|
|
|
|
|
use FindBin qw($RealBin);
|
|
|
|
use lib "$RealBin/../lib";
|
|
|
|
|
2022-01-29 21:22:48 +01:00
|
|
|
use constant {
|
2022-02-07 05:01:56 +01:00
|
|
|
SERIAL_PORT => $ENV{PBOTVM_SERIAL} // 4445,
|
2022-01-29 21:22:48 +01:00
|
|
|
};
|
|
|
|
|
2022-01-23 16:49:23 +01:00
|
|
|
my $json = join ' ', @ARGV;
|
|
|
|
|
|
|
|
my $args = eval { decode_json $json };
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
# wasn't JSON; make structure manually
|
|
|
|
if ($json =~ s/^-lang=([^ ]+)//) {
|
|
|
|
$args = { lang => $1, code => $json };
|
|
|
|
} else {
|
|
|
|
$args = { code => $json };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not exists $args->{code}) {
|
2022-01-29 21:22:48 +01:00
|
|
|
die "Usage: $0 <code>\n";
|
2022-01-23 16:49:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# set any missing fields to default values
|
2022-01-29 21:22:48 +01:00
|
|
|
$args->{nick} //= 'vm';
|
|
|
|
$args->{channel} //= 'vm';
|
|
|
|
$args->{lang} //= 'c11';
|
2022-02-07 05:01:56 +01:00
|
|
|
$args->{'vm-port'} //= SERIAL_PORT;
|
2022-01-23 16:49:23 +01:00
|
|
|
|
|
|
|
my $language = lc $args->{lang};
|
|
|
|
|
|
|
|
eval {
|
|
|
|
require "Languages/$language.pm";
|
|
|
|
} or do {
|
|
|
|
my $found = 0;
|
|
|
|
my ($languages, $comma) = ('', '');
|
|
|
|
|
|
|
|
foreach my $module (sort glob "$RealBin/../lib/Languages/*.pm") {
|
|
|
|
$module = basename $module;
|
|
|
|
$module =~ s/.pm$//;
|
|
|
|
next if $module =~ m/^_/;
|
|
|
|
|
|
|
|
require "Languages/$module.pm" or die $!;
|
|
|
|
my $mod = "Languages::$module"->new;
|
|
|
|
|
|
|
|
if (exists $mod->{name} and $mod->{name} eq $language) {
|
|
|
|
$language = $module;
|
|
|
|
$found = 1;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
|
|
|
|
$module = $mod->{name} if exists $mod->{name};
|
|
|
|
$languages .= "$comma$module";
|
|
|
|
$comma = ', ';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not $found) {
|
|
|
|
print "Language '$language' is not supported.\nSupported languages are: $languages\n";
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (not length $args->{code}) {
|
|
|
|
if (exists $args->{usage}) {
|
|
|
|
print "$args->{usage}\n";
|
|
|
|
} else {
|
|
|
|
print "Usage: cc [-lang=<language>] [-info] [-paste] [-args \"command-line arguments\"] [compiler/language options] <code> [-stdin <stdin input>]\n";
|
|
|
|
}
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $lang = "Languages::$language"->new(%{$args});
|
|
|
|
|
|
|
|
$lang->{local} = $ENV{CC_LOCAL};
|
|
|
|
|
|
|
|
$lang->process_interactive_edit;
|
|
|
|
$lang->process_standard_options;
|
|
|
|
$lang->process_custom_options;
|
|
|
|
$lang->process_cmdline_options;
|
|
|
|
$lang->preprocess_code;
|
|
|
|
$lang->execute;
|
|
|
|
$lang->postprocess_output;
|
|
|
|
$lang->show_output;
|