Implement shell/1 and shell/2
This commit is contained in:
@@ -301,6 +301,7 @@ pub(crate) enum SystemClauseType {
|
||||
GetEnv,
|
||||
SetEnv,
|
||||
UnsetEnv,
|
||||
Shell,
|
||||
PID,
|
||||
CharsBase64,
|
||||
DevourWhitespace,
|
||||
@@ -592,6 +593,7 @@ impl SystemClauseType {
|
||||
&SystemClauseType::GetEnv => clause_name!("$getenv"),
|
||||
&SystemClauseType::SetEnv => clause_name!("$setenv"),
|
||||
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
|
||||
&SystemClauseType::Shell => clause_name!("$shell"),
|
||||
&SystemClauseType::PID => clause_name!("$pid"),
|
||||
&SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
|
||||
&SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"),
|
||||
@@ -813,6 +815,7 @@ impl SystemClauseType {
|
||||
("$getenv", 2) => Some(SystemClauseType::GetEnv),
|
||||
("$setenv", 2) => Some(SystemClauseType::SetEnv),
|
||||
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
|
||||
("$shell", 2) => Some(SystemClauseType::Shell),
|
||||
("$pid", 1) => Some(SystemClauseType::PID),
|
||||
("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
|
||||
("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream),
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
:- module(os, [getenv/2,
|
||||
setenv/2,
|
||||
unsetenv/1,
|
||||
shell/1,
|
||||
shell/2,
|
||||
pid/1]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
@@ -34,9 +36,13 @@ unsetenv(Key) :-
|
||||
must_be_env_var(Key),
|
||||
'$unsetenv'(Key).
|
||||
|
||||
shell(Command) :- shell(Command, 0).
|
||||
shell(Command, Status) :-
|
||||
'$shell'(Command, Status).
|
||||
|
||||
pid(PID) :-
|
||||
can_be(integer, PID),
|
||||
'$pid'(PID).
|
||||
'$pid'(PID).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
For now, we only support a restricted subset of variable names.
|
||||
|
||||
@@ -5382,6 +5382,56 @@ impl MachineState {
|
||||
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
|
||||
env::remove_var(key);
|
||||
}
|
||||
&SystemClauseType::Shell => {
|
||||
// shell executes a command in a system shell
|
||||
// the code looks for a SHELL env var to do it in a UNIX-style
|
||||
// if not found, the code looks for COMSPEC env var to do it in a DOS-style
|
||||
// the output is printed directly to stdout
|
||||
// the output status code is returned after finishing
|
||||
fn command_result(machine: &mut MachineState, command: std::io::Result<process::ExitStatus>) {
|
||||
match command {
|
||||
Ok(status) => {
|
||||
match status.code() {
|
||||
Some(code) => {
|
||||
let addr = machine.heap.put_constant(Constant::Integer(Rc::new(Integer::from(code))));
|
||||
(machine.unify_fn)(machine, machine[temp_v!(2)], addr);
|
||||
}
|
||||
_ => {
|
||||
machine.fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
machine.fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let command = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
|
||||
match env::var("SHELL") {
|
||||
Ok(value) => {
|
||||
let command = process::Command::new(&value)
|
||||
.arg("-c")
|
||||
.arg(command)
|
||||
.status();
|
||||
command_result(self, command);
|
||||
}
|
||||
_ => {
|
||||
match env::var("COMSPEC") {
|
||||
Ok(value) => {
|
||||
let command = process::Command::new(&value)
|
||||
.arg("/C")
|
||||
.arg(command)
|
||||
.status();
|
||||
command_result(self, command);
|
||||
}
|
||||
_ => {
|
||||
self.fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
&SystemClauseType::PID => {
|
||||
let a1 = self[temp_v!(1)];
|
||||
let pid = process::id();
|
||||
|
||||
Reference in New Issue
Block a user