]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/extlib/hExtlib.ml
added list_concat
[helm.git] / helm / ocaml / extlib / hExtlib.ml
1 (* Copyright (C) 2005, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26
27 (** PROFILING *)
28
29 let profiling_enabled = true
30
31 type profiler = { profile : 'a 'b. ('a -> 'b) -> 'a -> 'b }
32 let profile =
33  if profiling_enabled then
34   function s ->
35    let total = ref 0.0 in
36    let profile f x =
37     let before = Unix.gettimeofday () in
38     try
39      let res = f x in
40      let after = Unix.gettimeofday () in
41       total := !total +. (after -. before);
42       res
43     with
44      exc ->
45       let after = Unix.gettimeofday () in
46        total := !total +. (after -. before);
47        raise exc
48    in
49    at_exit
50     (fun () ->
51       print_endline
52        ("!! TOTAL TIME SPENT IN " ^ s ^ ": " ^ string_of_float !total));
53    { profile = profile }
54  else
55   function _ -> { profile = fun f x -> f x }
56
57 (** {2 Optional values} *)
58
59 let map_option f = function None -> None | Some v -> Some (f v)
60 let unopt = function None -> failwith "unopt: None" | Some v -> v
61
62 (** {2 String processing} *)
63
64 let split ?(sep = ' ') s =
65   let pieces = ref [] in
66   let rec aux idx =
67     match (try Some (String.index_from s idx sep) with Not_found -> None) with
68     | Some pos ->
69         pieces := String.sub s idx (pos - idx) :: !pieces;
70         aux (pos + 1)
71     | None -> pieces := String.sub s idx (String.length s - idx) :: !pieces
72   in
73   aux 0;
74   List.rev !pieces
75
76 let trim_blanks s =
77   let rec find_left idx =
78     match s.[idx] with
79     | ' ' | '\t' | '\r' | '\n' -> find_left (idx + 1)
80     | _ -> idx
81   in
82   let rec find_right idx =
83     match s.[idx] with
84     | ' ' | '\t' | '\r' | '\n' -> find_right (idx - 1)
85     | _ -> idx
86   in
87   let s_len = String.length s in
88   let left, right = find_left 0, find_right (s_len - 1) in
89   String.sub s left (right - left + 1)
90
91 (** {2 List processing} *)
92
93 let rec list_uniq = function 
94   | [] -> []
95   | h::[] -> [h]
96   | h1::h2::tl when h1 = h2 -> list_uniq (h2 :: tl) 
97   | h1::tl (* when h1 <> h2 *) -> h1 :: list_uniq tl
98
99 let rec filter_map f =
100   function
101   | [] -> []
102   | hd :: tl ->
103       (match f hd with
104       | None -> filter_map f tl
105       | Some v -> v :: filter_map f tl)
106
107 let list_concat ?(sep = []) =
108   let rec aux acc =
109     function
110     | [] -> []
111     | [ last ] -> List.flatten (List.rev (last :: acc))
112     | hd :: tl -> aux ([sep; hd] @ acc) tl
113   in
114   aux []
115
116 (** {2 File predicates} *)
117
118 let is_dir fname =
119   try
120     (Unix.stat fname).Unix.st_kind = Unix.S_DIR
121   with Unix.Unix_error _ -> false
122
123 let is_regular fname =
124   try
125     (Unix.stat fname).Unix.st_kind = Unix.S_REG
126   with Unix.Unix_error _ -> false
127
128 let mkdir path =
129   let components = split ~sep:'/' path in
130   let rec aux where = function
131     | [] -> ()
132     | piece::tl -> 
133         let path = where ^ "/" ^ piece in
134         (try
135           Unix.mkdir path 0o755
136         with 
137         | Unix.Unix_error (Unix.EEXIST,_,_) -> ()
138         | Unix.Unix_error (e,_,_) -> 
139             raise 
140               (Failure 
141                 ("Unix.mkdir " ^ path ^ " 0o755 :" ^ (Unix.error_message e))));
142         aux path tl
143   in
144   aux "" components
145
146 (** {2 Filesystem} *)
147
148 let input_file fname =
149   let size = (Unix.stat fname).Unix.st_size in
150   let buf = Buffer.create size in
151   let ic = open_in fname in
152   Buffer.add_channel buf ic size;
153   close_in ic;
154   Buffer.contents buf
155
156 let input_all ic =
157   let size = 10240 in
158   let buf = Buffer.create size in
159   let s = String.create size in
160   (try
161     while true do
162       let bytes = input ic s 0 size in
163       if bytes = 0 then raise End_of_file
164       else Buffer.add_substring buf s 0 bytes
165     done
166   with End_of_file -> ());
167   Buffer.contents buf
168
169 let output_file ~filename ~text = 
170   let oc = open_out filename in
171   output_string oc text;
172   close_out oc
173   
174 let find ?(test = fun _ -> true) path = 
175   let rec aux acc todo = 
176     match todo with
177     | [] -> acc
178     | path :: tl ->
179         try
180           let handle = Unix.opendir path in
181           let dirs = ref [] in
182           let matching_files = ref [] in 
183           (try 
184             while true do 
185               match Unix.readdir handle with
186               | "." | ".." -> ()
187               | entry ->
188                   let qentry = path ^ "/" ^ entry in
189                   (try
190                     if is_dir qentry then
191                       dirs := qentry :: !dirs
192                     else if test qentry then
193                       matching_files := qentry :: !matching_files;
194                   with Unix.Unix_error _ -> ())
195             done
196           with End_of_file -> Unix.closedir handle);
197           aux (!matching_files @ acc) (!dirs @ tl)
198         with Unix.Unix_error _ -> aux acc tl
199   in
200   aux [] [path]
201
202 (** {2 Exception handling} *)
203
204 let finally at_end f arg =
205   let res =
206     try f arg
207     with exn -> at_end (); raise exn
208   in
209   at_end ();
210   res
211