+/** Predicates for reasoning about files and directories.
+
+In this library, directories and files are represented as
+*lists of characters*. This is an ideal representation:
+
+* Lists of characters can be conveniently reasoned about with DCGs
+ and built-in Prolog predicates from library(lists). This alone
+ is already a very compelling argument to use them.
+* Other Scryer libraries such as library(http/http_open) also already
+ use lists of characters to represent paths.
+* File names are mostly ephemeral, so it is good for efficiency
+ that they can quickly allocated transiently on the heap, leaving the
+ atom table mostly unaffected. Indexing is almost never needed
+ for file names. If needed, it should be added to the engine.
+* The previous point is also good for security, since the system
+ leaves little trace of which files were even accessed.
+* Scryer Prolog represents lists of characters extremely compactly.
+*/
+
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Part of Scryer Prolog.
:- use_module(library(charsio)).
:- use_module(library(dcgs)).
+%% directory_files(+Directory, -Files).
+%
+% Returns the list of files *and* directories available at a specific
+% directory in the current system.
+
directory_files(Directory, Files) :-
must_be(chars, Directory),
can_be(list, Files),
'$directory_files'(Directory, Files).
+%% file_size(+File, -Size).
+%
+% Returns the size (in bytes) of a file. The file must exist.
+
file_size(File, Size) :-
file_must_exist(File, file_size/2),
can_be(integer, Size),
'$file_size'(File, Size).
+%% file_exists(+File).
+%
+% Succeeds if File is a file that exists in the current system.
file_exists(File) :-
must_be(chars, File),
'$file_exists'(File).
+%% directory_exists(+Directory).
+%
+% Succeeds if Directory is a directory that exists in the current system.
directory_exists(Directory) :-
must_be(chars, Directory),
'$directory_exists'(Directory).
+%% make_directory(+Directory).
+%
+% Succeeds if it creates a new directory named Directory in the current system.
+% If you want to create a nested directory, use make\_directory\_path/1.
make_directory(Directory) :-
must_be(chars, Directory),
'$make_directory'(Directory).
+%% make_directory_path(+Directory).
+%
+% Similar to make\_directory/1 but recursively creates directories if they're missing.
+% Equivalent to mkdir -p in Unix.
make_directory_path(Directory) :-
must_be(chars, Directory),
'$make_directory_path'(Directory).
+%% delete_file(+File).
+%
+% Succeeds if deletes File from the current system.
delete_file(File) :-
file_must_exist(File, delete_file/1),
'$delete_file'(File).
+%% rename_file(+File, +Renamed).
+%
+% Succeeds if File is renamed to Renamed
rename_file(File, Renamed) :-
file_must_exist(File, rename_file/2),
must_be(chars, Renamed),
'$rename_file'(File, Renamed).
+%% delete_directory(+Directory).
+%
+% Succeeds if Directory is deleted from the current system.
+% Directory must be empty.
delete_directory(Directory) :-
directory_must_exist(Directory, delete_directory/1),
must_be(chars, Directory),
; throw(error(existence_error(directory, Directory), Context))
).
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Dir0 is the current working directory, and the working directory
- is changed to Dir.
+%% workind_directory(Dir0, Dir).
+%
+% 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.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+% 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).
+%
+% 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(chars, Ps),
For two time stamps A and B, if A precedes B, then A @< B holds.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+%% file_modification_time(+File, -T).
+%
+% For a file File that must exist, it returns a time stamp T with the modification time
+%
+% T is a time stamp compatible with library(time).
file_modification_time(File, T) :-
file_time_(File, modification, T).
+%% file_access_time(+File, -T).
+%
+% For a file File that must exist, it returns a time stamp T with the access time
+%
+% T is a time stamp compatible with library(time).
file_access_time(File, T) :-
file_time_(File, access, T).
+%% file_creation_time(+File, -T).
+%
+% For a file File that must exist, it returns a time stamp T with the creation time
+%
+% T is a time stamp compatible with library(time).
file_creation_time(File, T) :-
file_time_(File, creation, T).
read_from_chars(T0, T).
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- path_segments(Ps, Segments): True iff Segments are the segments of Ps.
-
- Segments is the list of components of the path Ps that are
- separated by the platform-specific directory separator. Each
- segment is a list of characters.
-
- At least one of the arguments must be instantiated.
-
- Examples:
-
- ?- path_segments("/hello/there", Segments).
- Segments = [[],"hello","there"].
-
- ?- path_segments(Path, ["hello","there"]).
- Path = "hello/there".
-
-
- To obtain the platform-specific directory separator, you can use:
-
- ?- path_segments(Separator, ["",""]).
- Separator = "/".
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+%% path_segments(Ps, Segments).
+%
+% True iff Segments are the segments of Ps.
+%
+% Segments is the list of components of the path Ps that are
+% separated by the platform-specific directory separator. Each
+% segment is a list of characters.
+%
+% At least one of the arguments must be instantiated.
+%
+% Examples:
+%
+% ?- path_segments("/hello/there", Segments).
+% Segments = [[],"hello","there"].
+% ?- path_segments(Path, ["hello","there"]).
+% Path = "hello/there".
+%
+% To obtain the platform-specific directory separator, you can use:
+%
+% ?- path_segments(Separator, ["",""]).
+% Separator = "/".
path_segments(Path, Segments) :-
'$directory_separator'(Sep),