From: Adrián Arroyo Calle Date: Mon, 11 Oct 2021 20:35:05 +0000 (+0200) Subject: Implement shell/1 and shell/2 X-Git-Tag: v0.9.0~39^2~2 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=391cda919f001a64cfe066c9652aa495bc3f172f;p=scryer-prolog.git Implement shell/1 and shell/2 --- diff --git a/src/clause_types.rs b/src/clause_types.rs index e6559417..a22b542e 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -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), diff --git a/src/lib/os.pl b/src/lib/os.pl index f505ab7b..90357716 100644 --- a/src/lib/os.pl +++ b/src/lib/os.pl @@ -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. diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index cd02c750..8b4d7b27 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -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) { + 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();