Skip to content
Snippets Groups Projects
filenameExtras.ml 2.2 KiB
Newer Older
(* Time-stamp: <modified the 26/02/2015 (at 09:53) by Erwan Jahier> *)


let (to_list : string -> string list) =
  fun f -> 
    let rec aux acc f =
      let dir = Filename.dirname f
      and base = Filename.basename f in
        if dir = f then dir::acc else
          aux (base::acc) dir
    in
      aux [] f
        

(* exported *)
let (simplify : string -> string) =
  fun f -> 
    let rec simplify_aux l =
      match l with
        | []
        | _::[] -> l
        | x1::x2::tail -> 
            if x1 = Filename.current_dir_name then
              simplify_aux (x2::tail)
            else if x1 = Filename.parent_dir_name then 
              (* x1=.. -> nothing to do *)
              x1 :: (simplify_aux (x2::tail))
            else if x2 = Filename.parent_dir_name then
              (* "x1/.." -> we simplify into "" *)
              simplify_aux tail
            else
              (* x2 maybe also be ".." after simplifications -> fixpointing *)
              match simplify_aux (x2::tail) with
                | [] -> [] (* dead code *)
                | head::tail -> 
                    if head = Filename.parent_dir_name then 
                      tail (* bingo! we simplify *)
                    else
                      x1::head::tail
    in
    let l = to_list f in
    let l = 
      match l with
        | [] -> []
        | head::tail -> 
            (* simplify_aux removes all the "." in the path, so we preserve the first
               one here if necessary *)
            if head = Filename.current_dir_name then  
              head::(simplify_aux tail) 
            else
              simplify_aux l
    in
      (* build the filename back *)
      List.fold_left (fun x acc -> Filename.concat x acc) (List.hd l) (List.tl l)


(* A few unit tests *)
let _ = if Sys.os_type <> "Win32" then ( (* fails on win32 because of path *)
  assert(simplify "/home/name/dir/file" = "/home/name/dir/file");
  assert(simplify "/home/name/dir/../file" = "/home/name/file");
  assert(simplify "/home/name/dir/../../file" = "/home/file");
  assert(simplify "/home/./name/././././dir/.././../file" = "/home/file");
  assert(simplify "" = "./."); (* hum, that one is not simpler... *)
  assert(simplify "./a/b/../../../x" = "./../x")