Module Fpath
File system paths, file extensions, path sets and maps.
A (file system) path specifies a file or a directory in a file system hierarchy. A path has three parts:
- An optional, platform-dependent, volume.
- An optional root directory separator
dir_sepwhose presence distinguishes absolute paths ("/a") from relative ones ("a") - A non-empty list of
dir_sepseparated segments. Segments are non empty strings except for maybe the last one. The latter distinguishes directory paths ("a/b/") from file paths ("a/b").
The path 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.
Consult a few important tips.
Note. Fpath processes paths without accessing the file system.
v0.7.2 - homepage
Separators and segments
val dir_sep : stringdir_sepis the platform dependent natural directory separator. This is"/"on POSIX and"\\"on Windows.
val is_seg : string -> boolis_seg sistrueiffsdoes not containdir_sepor'/'or a0x00byte.
Paths
val v : string -> tv sis the stringsas a path.- raises Invalid_argument
if
sis not a valid path. Useof_stringto deal with untrusted input.
val add_seg : t -> string -> tadd_seg p segadds segmentsegto the segments ofpifp's last segment is non-empty or replaces the last empty segment withseg. Examples.- raises Invalid_argument
if
is_segsegisfalse.
val append : t -> t -> tappend p qappendsqtopas follows:
val split_volume : t -> string * tsplit_volume pis the pair(vol, q)wherevolis the platform dependent volume ofpor the empty string if there is none andqthe pathpwithout its volume, that is its optional rootdir_sepand segments.On POSIX if
volis non-empty then it can only be"/"(e.g. inv "//a/b"). On Windowsvolmay be one of the following prefixes parsed before an absolute rootdir_sep, except in the first case where a relative path can follow:$(drive): \\$(server)\$(share) \\?\$(drive): \\?\$(server)\$(share) \\?\UNC\$(server)\$(share) \\.\$(device)The following invariant holds:
equal p (v @@ vol ^ (to_string q))
val segs : t -> string listsegs pisp's non-empty list of segments. Absolute paths have an initial empty string added, this allows to recover the path's string withString.concat~sep:dir_sep. Examples.The following invariant holds:
equal p (v @@ (fst @@ split_volume p) ^ (String.concat ~sep:dir_sep (segs p)))
File and directory paths
Note. The following functions use syntactic semantic properties of paths. Given a path, these properties can be different from the one your file system attributes to it.
val is_dir_path : t -> boolis_dir_path pistrueiffprepresents a directory. This means thatp's last segment is either empty ("") or relative. The property is invariant with respect to normalization. Examples.
val is_file_path : t -> boolis_file_path pistrueiffprepresents a file. This is the negation ofis_dir_path. This means thatp's last segment is neither empty ("") nor relative. The property is invariant with respect to normalization. Examples.
val to_dir_path : t -> tto_dir_path pisadd_segp "". It ensure that the result represents a directory and, if converted to a string, that it ends with adir_sep. Examples.
val filename : t -> stringfilename pis the file name ofp. This is the last segment ofpifpis a file path and the empty string otherwise. The result is invariant with respect to normalization. See alsobasename. Examples.
Base and parent paths
val split_base : t -> t * tsplit_base psplitspinto a directorydand a relative base pathbsuch that:bis a relative path that contains the segments ofpthat start at the last non-empty segment. This means thatbhas a single non-empty segment, and preserves directoryness ofp. Ifpis a root path there are no such segments andbis"./".dis a directory such thatd // brepresents the same path asp. They may however differ syntactically when converted to a string.
Note. Normalizing
pbefore using the function ensures thatbis a relative segment iffpcannot be named (like in".","../../","/", etc.).
val basename : t -> stringbasename pisp's last non-empty segment if non-relative or the empty string otherwise. The latter occurs only on root paths and on paths whose last non-empty segment is a relative segment. See alsofilenameandbase. Examples.Note. Normalizing
pbefore using the function ensures the empty string is only returned iffpcannot be named (like in".","../../","/", etc.)
val parent : t -> tparent pis a directory path that containsp. Ifpis a root path this ispitself. Examples.Warning.
parent p // base pmay not representp, usesplit_basefor this.
Normalization
val rem_empty_seg : t -> trem_empty_seg premoves an existing last empty segment ofpifpis not a root path. This ensure that ifpis converted to a string it will not have a trailingdir_sepunlesspis a root path. Note that this may affectp's directoryness. Examples.
val normalize : t -> tnormalize pis a path that represents the same path asp, directoryness included, and that has the following properties:- If
pis absolute the resulting path has no"."and".."segments. - If
pis relative the resulting path is either"./"or it has no"."segments and".."segments may only appear as initial segments. - If
pis a directory it always end with an empty segment; this means it doesn't end with"."or"..".
Warning. Like file and directory path functions this function does not consult the file system and is purely based on the syntactic semantic of paths which can be different from the one of your concrete file system attributes. For example in presence of symbolic links the resulting path may not point to the same entity. Use the normalization functions of your OS system library to ensure correct behaviour with respect to a concrete file system.
- If
Prefixes
Warning. The syntactic prefix relation between paths does not, in general, entail directory containement. The following examples show this:
is_prefix (v "..") (v "../..") = true
is_prefix (v "..") (v ".") = falseHowever, on normalized, absolute paths, the prefix relation does entail directory containement. See also is_rooted.
val is_prefix : t -> t -> boolis_prefix prefix pistrueifprefixis a prefix ofp. This checks that:prefixhas the same optional volume asp.prefixhas the same optional root directory separator asp.- The list of segments of
prefixis a prefix of those ofp, ignoring the last empty segment ofprefixif the number of non-empty segments ofpis strictly larger than those ofprefix. This means thatis_prefix (v "a/") (v "a/b")istruebutis_prefix (v "a/") (v "a")isfalse
val find_prefix : t -> t -> t optionfind_prefix p p'isSome prefixif there existsprefixsuch thatprefixis the longest path withis_prefix prefix p && is_prefix prefix p' = trueandNoneotherwise. Note that if bothpandp'are absolute and have the same volume then a prefix always exists: the root path of their volume. Examples.
val rem_prefix : t -> t -> t optionrem_prefix prefix pis:Noneifprefixis not a prefix ofpor ifprefixandpare equal.Some qotherwise whereqispwithout the prefixprefixand preservesp's directoryness. This means thatqis a always relative and that the pathprefix // qandprepresent the same paths. They may however differ syntactically when converted to a string.
Roots and relativization
val relativize : root:t -> t -> t optionrelativize ~root pis:Some qif there exists a relative pathqsuch thatroot // qandprepresent the same paths, directoryness included. They may however differ syntactically when converted to a string. Note thatqis normalized.Noneotherwise.
val is_rooted : root:t -> t -> boolis_rooted root pistrueiff the pathpis the directoryrootor contained inrootand thatpcan be relativized w.r.t.root(the normalized relative path will have no parent directory segments). Examples.
Predicates and comparison
val is_rel : t -> boolis_rel pistrueiffpis a relative path, i.e. the root directory separator is missing inp.
val is_abs : t -> boolis_abs pistrueiffpis an absolute path, i.e. the root directory separator is present inp.
val is_root : t -> boolis_root pistrueiffpis a root directory, i.e.phas the root directory separator and a single, empty, segment. Examples.Warning. By definition this is a syntactic test. For example it will return
falseon"/a/.."or"/..". Normalizing the path before testing avoids this problem.
val is_current_dir : ?prefix:bool -> t -> boolis_current_dir pis true iffpis the current relative directory, i.e. either"."or"./". Ifprefixistrue(defaults tofalse) simply checks thatpis relative and its first segment is".".Warning. By definition this is a syntactic test. For example it will return
falseon"./a/.."or"./.". Normalizing the path before testing avoids this problem.
val is_parent_dir : ?prefix:bool -> t -> boolis_parent_dir pistrueiffpis the relative parent directory, i.e. either".."or"../". Ifprefixistrue(defaults tofalse), simply checks thatpis relative and its first segment is"..".Warning. By definition this is a syntactic test. For example it will return
falseon"./a/../.."or"./..". Normalizing the path before testing avoids this problem.
val is_dotfile : t -> boolis_dotfile pistrueiffp's basename is non empty and starts with a'.'.Warning. By definition this is a syntactic test. For example it will return
falseon".ssh/.". Normalizing the path before testing avoids this problem.
val equal : t -> t -> boolequal p p'istrueifpandp'have the same volume are both relative or absolute and have the same segments.Warning. By definition this is a syntactic test. For example
equal (v "./") (v "a/..")isfalse. Normalizing the paths before testing avoids this problem.
Conversions and pretty printing
val to_string : t -> stringto_string pis the pathpas a string. The result can be safely converted back withv.
val of_string : string -> (t, [ `Msg of string ]) Result.resultof_string sis the stringsas a path. The following transformations are performed on the string:- On Windows any
'/'occurence is converted to'\\'before any processing occurs. - Non-initial empty segments are suppressed;
"a//b"becomes"a/b","//a////b//"becomes"//a/b/", etc. - On Windows empty absolute UNC paths are completed to their root. For example
"\\\\server\\share"becomes"\\\\server\\share\\", but incomplete UNC volumes like"\\\\a"returnResult.Error.
Result.Error (`Msg (strf "%S: invalid path" s))is returned ifsor the path following the volume is empty (""), except on Windows UNC paths, see above.shas null byte ('\x00').- On Windows,
sis an invalid UNC path (e.g."\\\\"or"\\\\a")
- On Windows any
val pp : Stdlib.Format.formatter -> t -> unitpp ppf pprints pathponppfusingto_string.
val dump : Stdlib.Format.formatter -> t -> unitdump ppf pprints pathponppfusingString.dump.
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.
Warning. The following functions act on paths whose basename is non empty and do nothing otherwise. Normalizing p before using the functions ensures that the functions do nothing iff p cannot be named, see basename.
val get_ext : ?multi:bool -> t -> extget_ext pisp's basename file extension or the empty string if there is no extension. Ifmultiistrue(defaults tofalse), returns the multiple file extension. Examples.
val has_ext : ext -> t -> boolhas_ext e pistrueiffget_ext p = e || get_ext ~multi:true p = e. Ifedoesn't start with a'.'one is prefixed before making the test. Examples.
val mem_ext : ext list -> t -> boolmem_ext exts pisList.mem (get_ext p) exts || List.mem (get_ext ~multi:true p) exts.
val exists_ext : ?multi:bool -> t -> boolexists_ext ~multi pistrueiffp's basename file extension is not empty. Ifmultiistrue(default tofalse) returnstrueiffphas more than one extension. Examples.
val add_ext : ext -> t -> tadd_ext ext pispwith the stringextconcatenated top's basename, if non empty. Ifextdoesn't start with a'.'one is prefixed to it before concatenation except ifextis"". Examples.- raises Invalid_argument
if
is_segextisfalse.
val rem_ext : ?multi:bool -> t -> trem_ext pispwith the extension ofp's basename removed. Ifmultiistrue(default tofalse), the multiple file extension is removed. Examples.
Path sets and maps
module Set : sig ... endPath sets.
type +'a mapThe type for maps from paths to values of type
'a. Paths are compared withcompare.
module Map : sig ... endPath maps.
Tips
- The documentation sometimes talks about the last non-empty segment of a path. This usually means that we don't care whether the path is a file path (e.g.
"a") or a directory path (e.g."a/"). - Windows accepts both
'\\'and'/'as directory separator. HoweverFpathon Windows converts'/'to'\\'on the fly. Therefore you should either use'/'for defining constant paths you inject withvor better, construct them directly with(/).to_stringthen converts paths to strings using the platform's specific directory separatordir_sep. - Avoid platform specific volumes or hard-coding file hierarchy conventions in your constants.
- Do not assume there is a single root path and that it is
"/". On Windows each volume can have a root path. Useis_rooton normalized paths to detect roots. - Do not use
to_stringto construct URIs,to_stringusesdir_septo separate segments, on Windows this is'\\'which is not what URIs expect. Access path segments directly with Separators and segments; note that you will need to percent encode these.
Examples
equal (add_seg (v "/a") "b") (v "/a/b")equal (add_seg (v "/a/") "b") (v "/a/b")equal (add_seg (v "/a/b") "") (v "/a/b/")equal (add_seg (v "/a/b/") "") (v "/a/b/")equal (add_seg (v "/") "") (v "/")equal (add_seg (v "/") "a") (v "/a")equal (add_seg (v ".") "") (v "./")equal (add_seg (v ".") "a") (v "./a")equal (add_seg (v "..") "") (v "../")equal (add_seg (v "..") "a") (v "../a")
equal (append (v "/a/b/") (v "e/f")) (v "/a/b/e/f")equal (append (v "/a/b") (v "e/f")) (v "/a/b/e/f")equal (append (v "/a/b/") (v "/e/f")) (v "/e/f")equal (append (v "a/b/") (v "e/f")) (v "a/b/e/f")equal (append (v "a/b") (v "C:e")) (v "C:e")(Windows)
segs (v "/a/b/") = [""; "a"; "b"; ""]segs (v "/a/b") = [""; "a"; "b"]segs (v "a/b/") = ["a"; "b"; ""]segs (v "a/b") = ["a"; "b"]segs (v "a") = ["a"]segs (v "/") = [""; ""]segs (v "\\\\.\\dev\\") = ["";""](Windows)segs (v "\\\\server\\share\\a") = ["";"a"](Windows)segs (v "C:a") = ["a"](Windows)segs (v "C:\\a") = ["";"a"](Windows)
is_dir_path (v ".") = trueis_dir_path (v "..") = trueis_dir_path (v "../") = trueis_dir_path (v "/") = trueis_dir_path (v "/a/b/") = trueis_dir_path (v "/a/b") = falseis_dir_path (v "a/") = trueis_dir_path (v "a") = falseis_dir_path (v "a/.") = trueis_dir_path (v "a/..") = trueis_dir_path (v "a/..b") = falseis_dir_path (v "C:\\") = true(Windows)is_dir_path (v "C:a") = false(Windows)
is_file_path (v ".") = falseis_file_path (v "..") = falseis_file_path (v "../") = falseis_file_path (v "/") = falseis_file_path (v "/a/b/") = falseis_file_path (v "/a/b") = trueis_file_path (v "a/") = falseis_file_path (v "a") = trueis_file_path (v "a/.") = falseis_file_path (v "a/..") = falseis_file_path (v "a/..b") = trueis_file_path (v "C:\\") = false(Windows)is_file_path (v "C:a") = true(Windows)
equal (to_dir_path @@ v ".") (v "./")equal (to_dir_path @@ v "..") (v "../")equal (to_dir_path @@ v "../") (v "../")equal (to_dir_path @@ v "/") (v "/")equal (to_dir_path @@ v "/a/b/") (v "/a/b/")equal (to_dir_path @@ v "/a/b") (v "/a/b/")equal (to_dir_path @@ v "a/") (v "a/")equal (to_dir_path @@ v "a") (v "a/")equal (to_dir_path @@ v "a/.") (v "a/./")equal (to_dir_path @@ v "a/..") (v "a/../")equal (to_dir_path @@ v "a/..b") (v "a/..b/")equal (to_dir_path @@ v "\\\\server\\share\\") (v "\\\\server\\share\\")(Windows)equal (to_dir_path @@ v "C:a") (v "C:a\\")(Windows)equal (to_dir_path @@ v "C:\\") (v "C:\\")(Windows)
filename (v ".") = ""filename (v "./") = ""filename (v "..") = ""filename (v "../") = ""filename (v "../..") = ""filename (v "/") = ""filename (v "/a/b/") = ""filename (v "/a/b") = "b"filename (v "a/") = ""filename (v "a") = "a"filename (v "a/.") = ""filename (v "a/..") = ""filename (v "a/..b") = "..b"filename (v "C:\\") = ""(Windows)filename (v "C:a") = "a"(Windows)
(split_base @@ v ".") = (v "./"), (v ".")(split_base @@ v "./") = (v "./"), (v "./")(split_base @@ v "..") = (v "./"), (v "..")(split_base @@ v "../") = (v "./"), (v "../")(split_base @@ v "../../") = (v "../"), (v "../")(split_base @@ v ".././") = (v "../"), (v "./")(split_base @@ v "../../../") = (v "../../"), (v "../")(split_base @@ v "/") = (v "/"), (v "./")(split_base @@ v "/a/b/") = (v "/a/"), (v "b/")(split_base @@ v "/a/b") = (v "/a/"), (v "b")(split_base @@ v "a/") = (v "./"), (v "a/")(split_base @@ v "a") = (v "./"), (v "a")(split_base @@ v "a/b") = (v "a/"), (v "b")(split_base @@ v "a/b/") = (v "a/b/"), (v "b/")(split_base @@ v "a/.") = (v "a/"), (v ".")(split_base @@ v "a/..") = (v "a/"), (v "..")(split_base @@ v "a/../..") = (v "a/../"), (v "..")(split_base @@ v "a/..b") = (v "a/"), (v "..b")(split_base @@ v "./a") = (v "./"), (v "a")(split_base @@ v "./a/") = (v "./"), (v "a/")(split_base @@ v "../a") = (v "../"), (v "a")(split_base @@ v "../a/") = (v "../"), (v "a/")
basename (v ".") = ""basename (v "..") = ""basename (v "../") = ""basename (v "../../") = ""basename (v "/") = ""basename (v "/a/b/") = "b"basename (v "/a/b") = "b"basename (v "a/") = "a"basename (v "a") = "a"basename (v "a/.") = ""basename (v "a/./") = ""basename (v "a/..") = ""basename (v "a/..b") = "..b"basename (v "./a") = "a"basename (v "../a") = "a"basename (v "C:\\") = ""(Windows)basename (v "C:a") = "a"(Windows)
equal (parent @@ v ".") (v "./../")equal (parent @@ v "..") (v "../../")equal (parent @@ v "../") (v "../../")equal (parent @@ v "../../") (v "../../../")equal (parent @@ v "/") (v "/")equal (parent @@ v "/a/b/") (v "/a/")equal (parent @@ v "/a/b") (v "/a/")equal (parent @@ v "a/") (v "./")equal (parent @@ v "a") (v "./")equal (parent @@ v "a/.") (v "a/./../")equal (parent @@ v "a/./") (v "a/./../")equal (parent @@ v "a/..") (v "a/../../")equal (parent @@ v "a/../") (v "a/../../")equal (parent @@ v "a/..b") (v "a/")equal (parent @@ v "./a") (v "./")equal (parent @@ v "../a") (v "../")equal (parent @@ v "../../a") (v "../../")equal (parent @@ v "\\\\server\\share\\") (v "\\\\server\\share\\")(Windows)equal (parent @@ v "C:\\") (v "C:\\")(Windows)equal (parent @@ v "C:a") (v "C:.\\")(Windows)
equal (rem_empty_seg @@ v ".") (v ".")equal (rem_empty_seg @@ v "..") (v "..")equal (rem_empty_seg @@ v "../") (v "..")equal (rem_empty_seg @@ v "../../") (v "../..")equal (rem_empty_seg @@ v "/") (v "/")equal (rem_empty_seg @@ v "/a/b/") (v "/a/b")equal (rem_empty_seg @@ v "/a/b") (v "/a/b")equal (rem_empty_seg @@ v "a/") (v "a")equal (rem_empty_seg @@ v "a") (v "a")equal (rem_empty_seg @@ v "a/.") (v "a/.")equal (rem_empty_seg @@ v "a/./") (v "a/.")equal (rem_empty_seg @@ v "a/..") (v "a/..")equal (rem_empty_seg @@ v "a/../") (v "a/..")equal (rem_empty_seg @@ v "a/..b") (v "a/..b")equal (rem_empty_seg @@ v "./a") (v "./a")equal (rem_empty_seg @@ v "../a") (v "../a")equal (rem_empty_seg @@ v "../../a") (v "../../a")equal (rem_empty_seg @@ v "\\\\server\\share\\") (v "\\\\server\\share\\")(Windows)equal (rem_empty_seg @@ v "C:\\") (v "C:\\")(Windows)equal (rem_empty_seg @@ v "C:a\\") (v "C:a")(Windows)
equal (normalize @@ v ".") (v "./")equal (normalize @@ v "..") (v "../")equal (normalize @@ v "../") (v "../")equal (normalize @@ v "../../") (v "../../")equal (normalize @@ v "/") (v "/")equal (normalize @@ v "/a/b/") (v "/a/b/")equal (normalize @@ v "/a/b") (v "/a/b")equal (normalize @@ v "a/") (v "a/")equal (normalize @@ v "a") (v "a")equal (normalize @@ v "a/.") (v "a/")equal (normalize @@ v "a/./") (v "a/")equal (normalize @@ v "a/..") (v "./")equal (normalize @@ v "a/../") (v "./")equal (normalize @@ v "a/..b") (v "a/..b")equal (normalize @@ v "./a") (v "a")equal (normalize @@ v "../a") (v "../a")equal (normalize @@ v "../../a") (v "../../a")equal (normalize @@ v "./a/..") (v "./")equal (normalize @@ v "/a/b/./..") (v "/a/")equal (normalize @@ v "/../..") (v "/")equal (normalize @@ v "/a/../..") (v "/")equal (normalize @@ v "./../..") (v "../../")equal (normalize @@ v "../../a/") (v "../../a/")equal (normalize @@ v "/a/b/c/./../../g") (v "/a/g")equal (normalize @@ v "/a/b/c/./../../g/") (v "/a/g/")equal (normalize @@ v "\\\\?\\UNC\\server\\share\\..") (v "\\\\?\\UNC\\server\\share\\")(Windows)equal (normalize @@ v "\\\\server\\share\\") (v "\\\\server\\share\\")(Windows)equal (normalize @@ v "C:\\") (v "C:\\")(Windows)equal (normalize @@ v "C:a\\") (v "C:a\\")(Windows)
is_prefix (v "/a/b") (v "/a/b") = trueis_prefix (v "/a/b") (v "/a/bc") = falseis_prefix (v "/a/b") (v "/a/b/") = trueis_prefix (v "a/b/") (v "a/b") = falseis_prefix (v "a/b/") (v "a/b/") = trueis_prefix (v "a/b/") (v "a/b/c") = trueis_prefix (v ".") (v "./") = trueis_prefix (v "..") (v ".") = falseis_prefix (v "C:a") (v "a") = false(Windows)
find_prefix (v "a/b/c") (v "a/b/d")isSome (v "a/b/")find_prefix (v "a/b/c") (v "a/b/cd")isSome (v "a/b/")find_prefix (v "a/b") (v "a/b")isSome (v "a/b")find_prefix (v "a/b") (v "a/b/")isSome (v "a/b")find_prefix (v "a/b") (v "e/f")isNonefind_prefix (v "/a/b") (v "/e/f")isSome (v "/")find_prefix (v "/a/b") (v "e/f")isNonefind_prefix (v "C:\\a") (v "\\a")isNone(Windows)
rem_prefix (v "a/b/") (v "a/b")isNonerem_prefix (v "a/b/") (v "a/b/")isNonerem_prefix (v "a/b") (v "a/b")isNonerem_prefix (v "a/b") (v "a/b/")isSome "./"rem_prefix (v "a/b") (v "a/b/c")isSome (v "c")rem_prefix (v "a/b/") (v "a/b/c")isSome (v "c")rem_prefix (v "a/b") (v "a/b/c/")isSome (v "c/")rem_prefix (v "a/b/") (v "a/b/c/")isSome (v "c/")rem_prefix (v "C:\\a") (v "C:\\a\\b")isSome (v "b")(Windows)
relativize ~root:(v "/a/b") (v "c")isNonerelativize ~root:(v "/a/b") (v "/c")isSome (v "../../c")relativize ~root:(v "/a/b") (v "/c/")isSome (v "../../c/")relativize ~root:(v "/a/b") (v "/c")isSome (v "../../c")relativize ~root:(v "/a/b") (v "/c/")isSome (v "../../c/")relativize ~root:(v "/a/b") (v "/a/b/c")isSome (v "c")relativize ~root:(v "/a/b") (v "/a/b/c/")isSome (v "c/")relativize ~root:(v "/a/b") (v "/a/b")isNonerelativize ~root:(v "/a/b") (v "/a/b/")isSome (v ".")relativize ~root:(v "a/b") (v "/c")isNone.relativize ~root:(v "a/b") (v "c")isSome (v "../../c")relativize ~root:(v "a/b") (v "c/")isSome (v "../../c/")relativize ~root:(v "a/b") (v "a/b/c")isSome (v "c")relativize ~root:(v "a/b") (v "a/b")isSome (v ".")relativize ~root:(v "a/b") (v "a/b/")isSome (v ".")relativize ~root:(v "../") (v "./")isNonerelativize ~root:(v "../a") (v "b")isNonerelativize ~root:(v "../a") (v "../b/c")isSome (v "../b/c")relativize ~root:(v "../../a") (v "../b")isNonerelativize ~root:(v "../a") (v "../../b")is(Some "../../b")
is_rooted ~root:(v "a/b") (v "a/b") = falseis_rooted ~root:(v "a/b") (v "a/b/") = trueis_rooted ~root:(v "a/b/") (v "a/b") = falseis_rooted ~root:(v "a/b/") (v "a/b/") = trueis_rooted ~root:(v "./") (v "a") = trueis_rooted ~root:(v "./") (v "a/") = trueis_rooted ~root:(v "./") (v "a/../") = trueis_rooted ~root:(v "./") (v "..") = falseis_rooted ~root:(v "../") (v "./") = falseis_rooted ~root:(v "../") (v "a") = falseis_rooted ~root:(v "../") (v "../") = trueis_rooted ~root:(v "../") (v "../a") = trueis_rooted ~root:(v "../a") (v "./") = falseis_rooted ~root:(v "/a") (v "/a/..") = trueis_rooted ~root:(v "/a") (v "/a/../") = trueis_rooted ~root:(v "/a") (v "/..") = true
is_root (v "/") = trueis_root (v "/a") = falseis_root (v "/a/..") = falseis_root (v "//") = true(POSIX)is_root (v "\\\\.\\dev\\") = true(Windows)is_root (v "\\\\.\\dev\\a") = false(Windows)is_root (v "\\\\server\\share\\") = true(Windows)is_root (v "\\\\server\\share\\a") = false(Windows)is_root (v "C:\\") = true(Windows)is_root (v "C:a") = false(Windows)is_root (v "C:\\a") = false(Windows)
get_ext (v "/") = ""get_ext (v "a/b") = ""get_ext (v "a/b.mli/..") = ""get_ext (v "a/b.mli/...") = ""get_ext (v "a/b.") = "."get_ext (v "a/b.mli") = ".mli"get_ext ~multi:true (v "a/b.mli") = ".mli"get_ext (v "a/b.mli/") = ".mli"get_ext (v "a/.ocamlinit") = ""get_ext (v "a/.emacs.d") = ".d"get_ext (v "a/.emacs.d/") = ".d"get_ext ~multi:true (v "a/.emacs.d") = ".d"get_ext (v "a.tar.gz") = ".gz"get_ext ~multi:true (v "a.tar.gz") = ".tar.gz"
has_ext "mli" (v "a/b.mli") = truehas_ext ".mli" (v "a/b.mli") = truehas_ext ".mli" (v "a/b.mli/") = truehas_ext ".mli" (v "a/bmli") = falsehas_ext "mli" (v "a/bmli") = falsehas_ext ".tar.gz" (v "a/f.tar.gz") = truehas_ext "tar.gz" (v "a/f.tar.gz") = truehas_ext ".gz" (v "a/f.tar.gz") = truehas_ext ".tar" (v "a/f.tar.gz") = falsehas_ext ".cache" (v "a/.cache") = falsehas_ext "" (v "a/b") = falsehas_ext "" (v "a/b.") = truehas_ext "." (v "a/b.") = true
exists_ext (v "a/f") = falseexists_ext (v "a/f.") = trueexists_ext (v "a/f.gz") = trueexists_ext ~multi:true (v "a/f.gz") = falseexists_ext (v "a/f.tar.gz") = trueexists_ext ~multi:true (v "a/f.tar.gz") = trueexists_ext (v "a/f.tar.gz/") = trueexists_ext (v ".emacs.d") = trueexists_ext (v ".emacs.d/") = trueexists_ext (v ".ocamlinit") = false
equal (add_ext "mli" (v "a/b")) (v "a/b.mli")equal (add_ext ".mli" (v "a/b")) (v "a/b.mli")equal (add_ext ".mli" (v "a/b/")) (v "a/b.mli/")equal (add_ext ".mli" (v "/")) (v "/")equal (add_ext ".mli" (v "a/b/..")) (v "a/b/..")equal (add_ext "." (v "a/b")) (v "a/b.")equal (add_ext "" (v "a/b")) (v "a/b")equal (add_ext "tar.gz" (v "a/f")) (v "a/f.tar.gz")equal (add_ext ".tar.gz" (v "a/f")) (v "a/f.tar.gz")equal (add_ext "gz" (v "a/f.tar") ) (v "a/f.tar.gz")equal (add_ext ".gz" (v "a/f.tar") ) (v "a/f.tar.gz")
equal (rem_ext @@ v "/") (v "/")equal (rem_ext @@ v "/a/b") (v "/a/b")equal (rem_ext @@ v "/a/b.mli") (v "/a/b")equal (rem_ext @@ v "/a/b.mli/") (v "/a/b/")equal (rem_ext @@ v "/a/b.mli/..") (v "/a/b.mli/..")equal (rem_ext @@ v "/a/b.mli/.") (v "/a/b.mli/.")equal (rem_ext @@ v "a/.ocamlinit") (v "a/.ocamlinit")equal (rem_ext @@ v "a/.emacs.d") (v "a/.emacs")equal (rem_ext @@ v "a/.emacs.d/") (v "a/.emacs/")equal (rem_ext @@ v "f.tar.gz") (v "f.tar")equal (rem_ext ~multi:true @@ v "f.tar.gz") (v "f")equal (rem_ext ~multi:true @@ v "f.tar.gz/") (v "f/")