struct
include Filename
let string_rexists s ~f ~from:n =
let rec loop n =
if n = 0 then
None
else if f s.[n - 1] then
Some n
else
loop (n - 1)
in
loop n
let skip_end_slashes s ~from =
match string_rexists s ~from ~f:(fun c -> c <> '/') with
| Some v -> `Ends_at v
| None -> `All_slashes
let split = function
| "" -> ".", "."
| s ->
match skip_end_slashes s ~from:(String.length s) with
| `All_slashes -> "/", "/"
| `Ends_at basename_end ->
match string_rexists s ~f:(fun c -> c = '/') ~from:basename_end with
| None -> ".", String.sub ~pos:0 ~len:basename_end s
| Some basename_start ->
let basename =
String.sub s ~pos:basename_start
~len:(basename_end - basename_start)
in
let dirname =
match skip_end_slashes s ~from:basename_start with
| `All_slashes -> "/"
| `Ends_at dirname_end -> String.sub ~pos:0 ~len:dirname_end s
in
dirname, basename
let parts filename =
let rec loop acc filename =
match split filename with
| "." as base, "." -> base :: acc
| "/" as base, "/" -> base :: acc
| rest, dir ->
loop (dir :: acc) rest
in
loop [] filename
end