diff --git a/build/instructions_template.rs b/build/instructions_template.rs index f58dbfed..e4904352 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -262,6 +262,8 @@ enum SystemClauseType { DeleteFile, #[strum_discriminants(strum(props(Arity = "2", Name = "$rename_file")))] RenameFile, + #[strum_discriminants(strum(props(Arity = "2", Name = "$file_copy")))] + FileCopy, #[strum_discriminants(strum(props(Arity = "2", Name = "$working_directory")))] WorkingDirectory, #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_directory")))] @@ -1607,6 +1609,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallMakeDirectoryPath(_) | &Instruction::CallDeleteFile(_) | &Instruction::CallRenameFile(_) | + &Instruction::CallFileCopy(_) | &Instruction::CallWorkingDirectory(_) | &Instruction::CallDeleteDirectory(_) | &Instruction::CallPathCanonical(_) | @@ -1819,6 +1822,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteMakeDirectoryPath(_) | &Instruction::ExecuteDeleteFile(_) | &Instruction::ExecuteRenameFile(_) | + &Instruction::ExecuteFileCopy(_) | &Instruction::ExecuteWorkingDirectory(_) | &Instruction::ExecuteDeleteDirectory(_) | &Instruction::ExecutePathCanonical(_) | diff --git a/src/lib/files.pl b/src/lib/files.pl index 1e856ff1..e920b5bd 100644 --- a/src/lib/files.pl +++ b/src/lib/files.pl @@ -70,8 +70,9 @@ In this library, directories and files are represented as file_exists/1, directory_exists/1, delete_file/1, - rename_file/2, - delete_directory/1, + rename_file/2, + file_copy/2, + delete_directory/1, make_directory/1, make_directory_path/1, working_directory/2, @@ -150,6 +151,14 @@ rename_file(File, Renamed) :- must_be(chars, Renamed), '$rename_file'(File, Renamed). +%% file_copy(+File, +Copied). +% +% Succeeds if File is copied to Copied +file_copy(File, Copied) :- + file_must_exist(File, file_copy/2), + must_be(chars, Copied), + '$file_copy'(File, Copied). + %% delete_directory(+Directory). % % Succeeds if Directory is deleted from the current system. diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 72da8bad..d3a6a9e1 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -3533,6 +3533,14 @@ impl Machine { self.rename_file(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallFileCopy(_) => { + self.file_copy(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFileCopy(_) => { + self.file_copy(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallWorkingDirectory(_) => { try_or_throw!(self.machine_st, self.working_directory()); step_or_fail!(self, self.machine_st.p += 1); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 289a6c97..0e4b1e16 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1653,6 +1653,19 @@ impl Machine { self.machine_st.fail = true; } + #[inline(always)] + pub(crate) fn file_copy(&mut self) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + if let Some(copied) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { + if fs::copy(file.as_str(), copied.as_str()).is_ok() { + return; + } + } + } + + self.machine_st.fail = true; + } + #[inline(always)] pub(crate) fn delete_directory(&mut self) { if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {