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.
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 works on the directory name of directory paths.
TODO Is returning the empty string rather than an option really a good idea ? I vaguely remember option was an annoyance though.
has_ext ext p
is true
iff String.equal (get_ext n multi:false p) e || String.equal (get_ext ~multi:true p) e
.
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.
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.
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