]> Repositorios git - scryer-prolog.git/commitdiff
ADDED: path_canonical/2, obtaining the canonical absolute path.
authorMarkus Triska <[email protected]>
Wed, 15 Jul 2020 18:24:26 +0000 (20:24 +0200)
committerMarkus Triska <[email protected]>
Wed, 15 Jul 2020 18:43:34 +0000 (20:43 +0200)
This addresses a remaining aspect of #511.

src/clause_types.rs
src/lib/files.pl
src/machine/system_calls.rs

index 89e4d00d0ca988412e7b8af30c85524129022e57..c45466232c6fd83f7c0d809cd9fd50674cdfa3f0 100644 (file)
@@ -178,6 +178,7 @@ pub enum SystemClauseType {
     MakeDirectory,
     DeleteFile,
     WorkingDirectory,
+    PathCanonical,
     DeleteAttribute,
     DeleteHeadAttribute,
     DynamicModuleResolution(usize),
@@ -345,6 +346,7 @@ impl SystemClauseType {
             &SystemClauseType::MakeDirectory => clause_name!("$make_directory"),
             &SystemClauseType::DeleteFile => clause_name!("$delete_file"),
             &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
+            &SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
             &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
             &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
             &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
@@ -681,6 +683,7 @@ impl SystemClauseType {
             ("$make_directory", 1) => Some(SystemClauseType::MakeDirectory),
             ("$delete_file", 1) => Some(SystemClauseType::DeleteFile),
             ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
+            ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
             ("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
             ("$use_module_from_file", 1) =>
                     Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),
index 9e54bf3392db67c9c8ae919cb83a47a95d589f08..69847b2939f633a8526bad8fd8d676dd0d9cc264 100644 (file)
@@ -52,7 +52,8 @@
                   directory_exists/1,
                   delete_file/1,
                   make_directory/1,
-                  working_directory/2]).
+                  working_directory/2,
+                  path_canonical/2]).
 
 :- use_module(library(error)).
 :- use_module(library(lists)).
@@ -87,7 +88,34 @@ delete_file(File) :-
         list_of_chars(File),
         '$delete_file'(File).
 
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+   Dir0 is the current working directory, and the working directory
+   is changed to Dir.
+
+   Use working_directory(Ds, Ds) to determine the current working directory,
+   and leave it as is.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
 working_directory(Dir0, Dir) :-
         can_be(list, Dir0),
         can_be(list, Dir),
         '$working_directory'(Dir0, Dir).
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+   True iff Cs is the canonical, absolute path of Ps.
+
+   All intermediate components are normalized, and all symbolic links
+   are resolved.
+
+   The predicate fails in the following situations, though not
+   necessarily *only* in these cases:
+
+      1. Ps is a path that does not exist.
+      2. A non-final component in Ps is not a directory.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+path_canonical(Ps, Cs) :-
+        must_be(list, Ps),
+        maplist(must_be(character), Ps),
+        can_be(list, Cs),
+        '$path_canonical'(Ps, Cs).
index 77ef1366282846aa1daab8244610e01f287dcd6e..2f357873b808effc65be0d5f424530f54aead625 100644 (file)
@@ -918,6 +918,31 @@ impl MachineState {
                     return Ok(());
                 }
             }
+            &SystemClauseType::PathCanonical => {
+                let path = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+
+                match fs::canonicalize(path) {
+                    Ok(canonical) => {
+                        let cs =
+                            match canonical.to_str() {
+                                Some(s) => { s }
+                                _ => {
+                                    let stub = MachineError::functor_stub(clause_name!("path_canonical"), 2);
+                                    let err = MachineError::representation_error(RepFlag::Character);
+                                    let err = self.error_form(err, stub);
+
+                                    return Err(err);
+                                }
+                            };
+                        let chars = self.heap.put_complete_string(cs);
+                        self.unify(self[temp_v!(2)], chars);
+                    }
+                    _ => {
+                        self.fail = true;
+                        return Ok(());
+                    }
+                }
+            }
             &SystemClauseType::AtEndOfExpansion => {
                 if self.cp == LocalCodePtr::TopLevel(0, 0) {
                     self.at_end_of_expansion = true;