1 (**************************************************************************)
2 (* *)
3 (* OCaml *)
4 (* *)
5 (* Jeremie Dimino, Jane Street Europe *)
6 (* *)
7 (* Copyright 2018 Jane Street Group LLC *)
8 (* *)
9 (* All rights reserved. This file is distributed under the terms of *)
10 (* the GNU Lesser General Public License version 2.1, with the *)
11 (* special exception on linking described in the file LICENSE. *)
12 (* *)
13 (**************************************************************************)
14
15 module SMap = Misc.Stdlib.String.Map
16
17 (* Mapping from basenames to full filenames *)
18 type registry = string SMap.t ref
19
20 let files : registry = ref SMap.empty
21 let files_uncap : registry = ref SMap.empty
22
23 module Dir = struct
24 type t = {
25 path : string;
26 files : string list;
27 }
28
29 let path t = t.path
30 let files t = t.files
31
32 (* For backward compatibility reason, simulate the behavior of
33 [Misc.find_in_path]: silently ignore directories that don't exist
34 + treat [""] as the current directory. *)
35 let readdir_compat dir =
36 try
37 Sys.readdir (if dir = "" then Filename.current_dir_name else dir)
38 with Sys_error _ ->
39 [||]
40
41 let create path =
42 { path; files = Array.to_list (readdir_compat path) }
43 end
44
45 let dirs = ref []
46
47 let reset () =
48 files := SMap.empty;
49 files_uncap := SMap.empty;
50 dirs := []
51
52 let get () = !dirs
53 let get_paths () = List.map Dir.path !dirs
54
55 let add dir =
56 let add_file base =
57 let fn = Filename.concat dir.Dir.path base in
58 files := SMap.add base fn !files;
59 files_uncap := SMap.add (String.uncapitalize_ascii base) fn !files_uncap;
60 in
61 List.iter add_file dir.Dir.files;
62 dirs := dir :: !dirs
63
64 let remove_dir dir =
65 let new_dirs = List.filter (fun d -> Dir.path d <> dir) !dirs in
66 if new_dirs <> !dirs then begin
67 reset ();
68 List.iter add (List.rev new_dirs)
69 end
70
71 let add_dir dir = add (Dir.create dir)
72
73 let init l =
74 reset ();
75 List.iter add_dir (List.rev l)
76
77 let is_basename fn = Filename.basename fn = fn
78
79 let find fn =
80 if is_basename fn then
81 SMap.find fn !files
82 else
83 Misc.find_in_path (get_paths ()) fn
84
85 let find_uncap fn =
86 if is_basename fn then
87 SMap.find (String.uncapitalize_ascii fn) !files_uncap
88 else
89 Misc.find_in_path_uncap (get_paths ()) fn
90