]> Repositorios git - scryer-prolog.git/commitdiff
Implement shell/1 and shell/2
authorAdrián Arroyo Calle <[email protected]>
Mon, 11 Oct 2021 20:35:05 +0000 (22:35 +0200)
committerAdrián Arroyo Calle <[email protected]>
Mon, 11 Oct 2021 20:35:05 +0000 (22:35 +0200)
src/clause_types.rs
src/lib/os.pl
src/machine/system_calls.rs

index e6559417d2c572c5e1a9159644e1bedaaf4926e1..a22b542e1505a214deb03dc1a8aa6cd7336f2198 100644 (file)
@@ -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),
index f505ab7bc49125c58197871e89f5a27c02ab1331..90357716f35f13ccbfd494ac650516ead84abce4 100644 (file)
@@ -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.
index cd02c750b484b78ff1e25156df4d931be767dfce..8b4d7b27b45769ebaa88d052b8a78b2a9f1c3646 100644 (file)
@@ -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();