More.Fpath
File paths.
A file path is a syntactic specification of a file or a directory location in a file system hierarchy. It is made of three parts:
"C:"
)."/a"
versus "a"
)."a/b/"
versus "a/b"
). But a directory can also be specified by a file path and a syntactic directory path may not be a directory (e.g. a symlink).The paths segments "."
and ".."
are relative path segments that respectively denote the current and parent directory. The basename of a path is its last non-empty segment if it is not a relative path segment or the empty string otherwise (e.g. on "/"
or ".."
).
natural_dir_sep_char
is the natural directory separator for the platform. This is '\\'
if Sys.win32
and '/'
otherwise.
Warning. Do not test for equality against this character to assert directory separators. Use is_dir_sep_char
, some platforms support more than one directory separator.
natural_dir_sep
is natural_dir_sep_char
as a string.
Warning. Do not test for equality against this string to assert directory separators. Use is_dir_sep
, some platforms support more than one directory separator.
is_dir_sep_char c
is true
iff c
is a directory separator on the platform. This means c
is '/'
or it is '\\'
and Sys.win32
is true
.
is_dir_sep s
is true
if s
is a singelton string and is_dir_sep_char
s.[0]
is true
.
val v : string -> t
v s
is the string s
as a file path. Raises Invalid_argument
if s
is not a valid path. Use of_string
to deal with untrusted input.
Warning. In code only use "/"
in string literals as the directory separator even on Windows platforms (don't be upset, the module gives them back to you with backslashes).
val fmt : ('a, Stdlib.Format.formatter, unit, t) Stdlib.format4 -> 'a
fmt …
is Fmt.kstr v …
.
append p q
appends q
to p
as follows:
q
is absolute or has a non-empty volume then q
is returned.q
's segments to p
using add_segment
.val null : t
null
represents a file on the OS that discards all writes and returns end of file on reads. This is NUL
if Sys.win32
is true
and /dev/null
otherwise. See also is_null
.
val dash : t
dash
is "-"
. This value is used in command line interfaces to denote standard input or output. See also is_dash
.
is_segment s
is true
iff s
does not contain a null byte or a directory separator as asserted by is_dir_sep_char
.
add_segment p seg
is:
p
with the last segment replaced by seg
, if the last segment is empty.p
with segment seg
added, otherwiseThis errors if is_segment
seg
is false
. FIXME error format.
p / seg
is add_segment
p seg |> Result.get_ok'
. Left associative. Warning. Use add_segment
to deal with untrusted seg
values.
val is_syntactic_dir : t -> bool
is_syntactic_dir p
is true
iff p
syntactically represents a directory. This means that p
is "."
, ".."
or ends with "/"
, "/."
or "/.."
.
Note. This a syntactic check, the file system may attribute different properties to these paths.
ensure_trailing_dir_sep p
is add_segment p ""
. This ensures that p
has a final empty segment and thus a trailing directory separator when converted to a string.
strip_trailing_dir_sep p
ensures p
has no final empty segment unless p
is a root path. When p
is not a root path this ensure that p
has no trailing directory separator when converted to a string.
Note. The following functions use syntactic semantic properties of paths. Given a path, these properties can be different from the ones your file system attributes to it.
val basename : ?strip_exts:bool -> t -> string
basename p
is the last non-empty segment of p
or the empty string otherwise. The latter occurs only on root paths and on paths whose last non-empty segment is a relative segment. If strip_exts
is true
(default to false
) the basename's multiple extension, if any, is removed from the segment.
basepath
is like basename
but returns a file path with the result or "."
if the result is empty which can be detected by is_current_dir
.
parent p
is a directory path that contains p
. If p
is a root path this is p
itself. If p
is in the current directory this is "./"
.
is_prefix prefix p
is true
iff prefix
is a strict prefix of p
that respects path segments. More formally iff the following two conditions hold:
not Fpath.(equal (to_dir_path prefix) (to_dir_path p))
Fpath.(String.is_prefix (to_string (to_dir_path prefix) (to_string p)))
is true
Warning. By definition is_prefix p p
is false
. Note also that the prefix relation does not entail directory containement; for example is_prefix (v "..") (v "../..")
holds.
strip_prefix prefix p
is:
None
if is_prefix
prefix p
is false
.Some q
otherwise where q
is p
without the string prefix Fpath.to_dir_path prefix
. This means that q
is always relative, that it preserves p
's syntactic directoryness and that Fpath.(equal (prefix // q) p)
holds.Warning. By definition strip_prefix p p
is None
.
drop_prefixed ps
is ps
without elements that have a strict prefixes in ps
. The list order is preserved. Duplicates are not removed use distinct
for this.
reroot ~src_root ~dst_root p
assumes src_root
prefixes p
removes the prefix and prepends dst_root
to the result.
Raises Invalid_argument
if dst_root
is not a prefix of src
. In particular note that p
cannot be src_root
.
relative ~to_dir p
is q
such that to_dir // q
represents the same path as p
. Note that q
is not necessarily relative: if to_dir
is relative and p
is absolute p
is returned.
Warning. This function is mostly broken at the moment.
Raises Invalid_argument
if path to_dir
contains ".."
.
val is_relative : t -> bool
is_relative p
is true
iff p
is a relative path, i.e. the root directory separator is missing in p
.
val is_absolute : t -> bool
is_absolute p
is true
iff p
is an absolute path, i.e. the root directory separator is present in p
.
val is_root : t -> bool
is_root p
is true
iff p
is a root directory, i.e. p
has the root directory separator and a single, empty, segment.
val is_null : t -> bool
is_null p
is equal p null
.
val is_dash : t -> bool
is_dash p
is equal p dash
.
val is_current_dir : t -> bool
is_current_dir p
is true
iff p
is either "."
or "./"
.
val is_parent_dir : t -> bool
is_parent_dir p
is true
iff p
is either ".."
or "../"
.
equal_basename p0 p1
is String.equal (basename p0) (basename p1)
.
The file extension (resp. multiple file extensions) of a path segment is the suffix that starts at the last (resp. first) occurence of a '.'
that is preceeded by at least one non '.'
character. If there is no such occurence in the segment, the extension is empty. With these definitions, "."
, ".."
, "..."
and dot files like ".ocamlinit"
or "..ocamlinit"
have no extension, but ".emacs.d"
and "..emacs.d"
do have a single one.
TODO In the fpath
package we correct e.g. has_ext
if the given ext
has no ext
. I think we should either check and raise Invalid_argument
or correct.
val exists_ext : t -> bool
exists_ext p
is true
iff p
has a file or multiple file extension.
val exists_multi_ext : t -> bool
exists_multi_ext p
is true
iff p
has a multiple file extension.
get_ext ~multi p
is the file extension or multiple file extension if multi
is true
of the basename
of p
.
The empty string is returned if there is no extension. By definition this operates on the directory name of directory paths, not on the final empty segment.
has_ext ext p
is true
iff String.equal (get_ext n multi:false p) e || String.equal (get_ext ~multi:true p) e
.
add_ext ext p
is p
with ext
concatenated to p
's basename.
Note. ext
is not required to start with a .
it can be used for arbitrary basename extension.
strip_ext multi p
is p
with the extension of p
's basename removed. If multi
is true
(defaults to false
), the multiple file extension is removed.
set_ext ~multi ext p
is add_ext
ext (strip_ext ~multi p)
.
val of_string : string -> (t, string) Stdlib.result
of_string s
is the string s
as a path. The following transformations are performed on the string:
0x2F
) occurence is converted to \ (0x5C
)An error returned if s
is ""
or if it contains a null byte. The error string mentions s
.
val to_string : t -> string
to_string p
is the path p
as a string. The result can be safely converted back with v
.
val to_url_path : ?escape_space:bool -> t -> string
to_url_path ~escape_space p
is the path p
as an URL path. This is p
with the directory separator replaced by '/'
and with the following characters percent encoded: '%'
, '?'
, '#'
, ' '
(if escape_space
is true
, default), and the US-ASCII control characters.
If Sys.win32
is true
and p
has a drive a '/' is prepended to the result.
Note. In 2019, the standard definition of URLs is in a sorry state. Assuming p
is UTF-8 encoded. It is believed the above function should lead to an URL path component that can be parsed by HTML5's definition of URL parsing.
val to_segments : t -> string list
to_segments p
is p
's non-empty list of segments. Absolute paths have an empty string added, this allows to recover the path's string with String.concat dir_sep
, note however that you may have lost the volume along the way.
pp ppf p
prints path p
on ppf
. The path is quoted with Filename.quote
if needed. For now this means if it contains spaces (U+0020).
val error :
t ->
('b, Stdlib.Format.formatter, unit, ('a, string) Stdlib.result)
Stdlib.format4 ->
'b
error p fmt …
is Fmt.error ("%a:" ^^ fmt) pp_unquoted p …
.
val prefix_msg : t -> string -> string
prefix_msg p msg
is Fmt.str "%a: %s" pp_unquoted msg
.
type path = t
module Set : sig ... end
Path sets.
module Map : sig ... end
Path maps.
sort_by_parent ps
maps elements of ps
by their Fpath.parent
.
val sort_by_ext : multi:bool -> Set.t -> Set.t String.Map.t
sort_by_ext ~multi ps
maps elements of ps
by their extension as determined by Fpath.get_ext
~multi
.
A search path is a list of paths separated by a designated separator in which elements are looked up in left to right priority order. A well known search path is PATH
in which executable binaries are looked up.
search_path_sep
is the default platform specific separator for search paths. This is ";"
if Sys.win32
and ":"
otherwise.
val list_of_search_path :
?sep:string ->
string ->
(t list, string) Stdlib.result
list_of_search_path ~sep s
splits s
on sep
(defaults to search_path_sep
) and parses the result with of_string
, ignoring empty strings.
This means that sep
is not allowed to appear in the file paths, consecutive sep
are ignored and the order in the resulting list matches the left-to-right order of paths in s
.
If one of_string
errors on a path p
with e
the function errors with the message:
Fmt.str "Illegal path %a in search path: %s" pp p e