Module B0_std.Fpath

File paths.

A file system path specifies a file or a directory in a file system hierarchy. It is made of three parts:

  1. An optional, platform-dependent, volume.
  2. An optional root directory separator Fpath.dir_sep whose presence distinguishes absolute paths ("/a") from relative ones ("a")
  3. A non-empty list of Fpath.dir_sep separated segments. Segments are non empty strings except for maybe the last one. The latter syntactically distinguishes directory paths ("a/b/") from file paths ("a/b").

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 "..").

Separators and segments

val dir_sep_char : char

dir_sep_char is the platform dependent natural directory separator. This is / on POSIX and \ on Windows.

val dir_sep : string

dir_sep is dir_sep_char as a string.

val has_dir_sep : string -> bool

has_dir_sep s is true iff s contains dir_sep_char (on Windows also if it contains '/').

val is_seg : string -> bool

is_seg s is true iff s does not contain a dir_sep_char (on Windows also that it does not contain '/') or a null byte.

val is_rel_seg : string -> bool

is_rel_seg s is true iff s is a relative segment in other words either "." or "..".

Paths

type t

The type for paths

val v : string -> t

v s is the string s as a path.

Warning. In code only use "/" as the directory separator even on Windows platforms (don't be upset, the module gives them back to you with backslashes).

Raises Invalid_argument if s is not a valid path. Use of_string to deal with untrusted input.

val fmt : ('a, Stdlib.Format.formatter, unit, t) Stdlib.format4 -> 'a

fmt … is Fmt.kstr v ….

val add_seg : t -> string -> (t, string) Stdlib.result

add_seg p seg if p's last segment is non-empty this is p with seg added. If p's last segment is empty, this is p with the empty segment replaced by seg.

This errors if is_seg seg is false.

val append : t -> t -> t

append p q appends q to p as follows:

  • If q is absolute or has a non-empty volume then q is returned.
  • Otherwise appends q's segments to p using add_seg.
val (/) : t -> string -> t

p / seg is add_seg p seg |> Result.get_ok'. Left associative. Warning. Use add_seg to deal with untrusted seg values.

val (//) : t -> t -> t

p // p' is append p p'. Left associative.

Famous file paths

val null : t

null represents a file on the OS that discards all writes and returns end of file on reads.

val dash : t

dash is "-". This value is used in cli interface to respectively denote standard input and output.

Directory paths

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 is_dir_path : t -> bool

is_dir_path p is true iff p syntactically represents a directory. This means that p is ., .. or ends with /, /. or /...

val add_dir_sep : t -> t

add_dir_sep p is add_seg p "". It ensures that the resulting path syntactically represents a directory and thus, if converted to a string, that it ends with a dir_sep.

val strip_dir_sep : t -> t

strip_dir_sep p is p without an existing last empty segment when p is not a root path, ensuring the result has no trailing dir_sep when converted to a string.

Basename and parent directory

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_ext: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_ext is true (default to false) the basename's multiple extension, if any, is removed from the result.

val parent : t -> t

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 ./.

Strict prefixes and roots

val is_prefix : t -> t -> bool

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:

  1. not Fpath.(equal (to_dir_path prefix) (to_dir_path p))
  2. 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.

val strip_prefix : t -> t -> t option

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 directoryness and that Fpath.(equal (prefix // q) p) holds.

Warning. By definition strip_prefix p p is None.

val drop_prefixed : t list -> t list

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.

val reroot : src_root:t -> dst_root:t -> t -> t

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.

val relative : to_dir:t -> t -> t

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 "..".

Predicates and comparison

val is_rel : t -> bool

is_rel p is true iff p is a relative path, i.e. the root directory separator is missing in p.

val is_abs : t -> bool

is_abs 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_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 "../".

val equal : t -> t -> bool

equal p0 p1 is true iff p0 and p1 are stringwise equal.

val equal_basename : t -> t -> bool

equal_basename p0 p1 is String.equal (basename p0) (basename p1).

val compare : t -> t -> int

compare p0 p1 is a total order on paths compatible with equal.

File extensions

The file extension (resp. multiple file extension) 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 one.

type ext = string

The type for file extensions, '.' separator included.

val get_ext : ?multi:bool -> t -> ext

get_ext p is p's basename file extension or the empty string if there is no extension. If multi is true (defaults to false), returns the multiple file extension.

val has_ext : ext -> t -> bool

has_ext ext p is true iff String.equal (get_ext p) e || String.equal (get_ext ~multi:true p) e.

val mem_ext : ext list -> t -> bool

mem_ext exts p is List.exists (fun e -> has_ext e p) exts

val add_ext : ext -> t -> t

add_ext ext p is p with ext concatenated to p's basename.

val strip_ext : ?multi:bool -> t -> t

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 set_ext : ?multi:bool -> ext -> t -> t

set_ext ?multi p is add_ext ext (strip_ext ?multi p).

val cut_ext : ?multi:bool -> t -> t * ext

cut_ext ?multi p is (strip_ext ?multi p, get_ext ?multi p).

val (+) : t -> ext -> t

p + ext is add_ext p ext. Left associative.

val (-+) : t -> ext -> t

p -+ ext is set_ext p ext. Left associative.

Converting

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:

  • On Windows any / (0x2F) occurence is converted to \ (0x5C)
  • Non initial empty segments are suppressed; "a//b" becomes "a/b", "//a////b//" becomes "//a/b/", etc

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 p is the path p as an URL path. This is p with the system specific dir_sep_char directory separator replaced by '/' and with the following characters percent encoded: '%', '?', '#', ' ' (unless escape_space is false, defaults to true), 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 stirng added, this allows to recover the path's string with String.concat dir_sep.

Formatting

val pp : t Fmt.t

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 pp_quoted : t Fmt.t

pp_quoted ppf p prints path p on ppf using Filename.quote.

val pp_unquoted : t Fmt.t

pp_unquoted ppf p prints path p on ppf using to_string.

val pp_dump : t Fmt.t

pp_dump ppf p prints path p on ppf using String.pp_dump.

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

Uniqueness

val distinct : t list -> t list

distinct ps is ps without duplicates, the list order is preserved.

Paths map and sets

type path = t
module Set : sig ... end

Path sets.

module Map : sig ... end

Path maps.

Sorts

val sort_by_parent : Set.t -> Set.t Map.t

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.

Search paths

A search path is a list of paths separated by a designated separator. A well known search path is PATH in which executable binaries are looked up.

val search_path_sep : string

search_path_sep is the default platform specific separator for search paths, this is ";" if Sys.win32 is true and ":" otherwise.

val list_of_search_path : ?sep:string -> string -> (t list, string) Stdlib.result

list_of_search_path ~sep s parses sep separated file paths from s. sep is not allowed to appear in the file paths, it defaults to search_path_sep. The order in the list matches the order from left to right in s.