(* EZFIO is an automatic generator of I/O libraries Copyright (C) 2009 Anthony SCEMAMA, CNRS This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Anthony Scemama LCPQ - IRSAMC - CNRS Universite Paul Sabatier 118, route de Narbonne 31062 Toulouse Cedex 4 scemama@irsamc.ups-tlse.fr *) (*$HEAD*) (* Exceptions ========== *) exception Read_only of string;; (* State variables =============== *) let read_only = ref false;; let ezfio_filename = ref "EZFIO_File";; (* Helper functions ================= *) let check_readonly = if !read_only then raise (Read_only "Read only attribute is set"); ;; let exists path = let filename = path^"/.version" in Sys.file_exists filename ;; let has group name = let dirname = !ezfio_filename ^ "/" ^ group in if (exists dirname) then (Sys.file_exists (dirname ^ "/" ^ name) ) else false ;; let has_array group name = has group (name^".gz");; let mkdir path = check_readonly; if (exists path) then raise (Failure (path^" already exists")); Unix.mkdir path 0o777; let out_channel = open_out (path^"/.version") in Printf.fprintf out_channel "%s\n" version ; close_out out_channel; ;; let create_group group = let dirname = !ezfio_filename ^ "/" ^ group in if not (exists dirname) then mkdir dirname; ;; let split line s = let rec do_work lst word = function | 0 -> word::lst | i -> begin match line.[i-1] with | a when a == s -> if word <> "" then do_work (word::lst) "" (i-1) else do_work lst "" (i-1) | a -> do_work lst ( (Char.escaped a)^word) (i-1) end in do_work [] "" (String.length line) ;; let ltrim s = let rec do_work s l = match s.[0] with | '\n' | ' ' -> do_work (String.sub s 1 (l-1)) (l-1) | _ -> s in do_work s (String.length s) ;; let rtrim s = let rec do_work s l = let newl = l-1 in match s.[newl] with | '\n' | ' ' -> do_work (String.sub s 0 (newl)) (newl) | _ -> s in do_work s (String.length s) ;; let trim s = ltrim (rtrim s) ;; let maxval l = match l with | [] -> None | [a] -> Some a | hd::tail -> Some (List.fold_left max hd tail) ;; let minval l = match l with | [] -> None | [a] -> Some a | hd::tail -> Some (List.fold_left min hd tail) ;; let at arr idx = arr.(idx);; let size (_) = 0;; let n_count_ch (str,_,v) = let rec do_work accu = function | 0 -> accu | i -> let newaccu = if str.[i-1] == v then accu+1 else accu in do_work newaccu (i-1) in do_work 0 (String.length str) ;; let n_count (l,_,v) = let rec do_work accu = function | [] -> accu | h::tail -> let newaccu = if h == v then accu+1 else accu in do_work newaccu tail in do_work 0 l ;; (* Scalars ======= *) (* Read ---- *) let read_scalar type_conversion group name = let in_filename = !ezfio_filename ^ "/" ^ group ^ "/" ^ name in let in_channel = open_in in_filename in let trimmed_line = trim (input_line in_channel) in let result = type_conversion trimmed_line in begin close_in in_channel ; result end ;; let fortran_bool_of_string = function | "T" | "t" -> true | "F" | "f" -> false | x -> raise (Failure ("fortran_bool_of_string should be T or F: "^x)) ;; let fortran_string_of_bool = function | true -> "T\n" | false-> "F\n" ;; let read_int = read_scalar int_of_string ;; let read_float = read_scalar float_of_string ;; let read_string= read_scalar (fun (x:string) -> x);; let read_bool = read_scalar fortran_bool_of_string;; (* Write ----- *) let print_int out_channel i = Printf.fprintf out_channel "%16d\n" i and print_float out_channel f = Printf.fprintf out_channel "%24.15e\n" f and print_string out_channel s = Printf.fprintf out_channel "%s\n" s and print_bool out_channel b = Printf.fprintf out_channel "%s\n" (fortran_string_of_bool b);; let write_scalar print_fun group name s = check_readonly; create_group group; let out_filename = !ezfio_filename ^ "/" ^ group ^ "/" ^ name in let out_channel = open_out out_filename in begin print_fun out_channel s; close_out out_channel; end ;; let write_int = write_scalar print_int and write_float = write_scalar print_float and write_bool = write_scalar print_bool and write_string = write_scalar print_string ;; (* Arrays ====== *) type 'a ezfio_data = | Ezfio_item of 'a array | Ezfio_data of ('a ezfio_data) array ;; type 'a ezfio_array = { rank : int ; dim : int array; data : 'a ezfio_data ; } ;; let ezfio_get_element { rank=r ; dim=d ; data=data } coord = (*assert ((List.length coord) == r);*) let rec do_work buffer = function | [c] -> begin match buffer with | Ezfio_item buffer -> buffer.(c) | Ezfio_data buffer -> raise (Failure "Error in ezfio_get_element") end | c::tail -> begin match buffer with | Ezfio_item buffer -> raise (Failure "Error in ezfio_get_element") | Ezfio_data buffer -> do_work buffer.(c) tail end | [] -> raise (Failure "Error in ezfio_get_element") in do_work data coord ;; let flattened_ezfio_data d = match d with | Ezfio_item d -> d | Ezfio_data d -> let d = Array.to_list d in let rec do_work accu = function | [] -> accu | (Ezfio_item x)::tail -> do_work (Array.append accu x) tail | (Ezfio_data x)::tail -> let newaccu = do_work accu (Array.to_list x ) in do_work newaccu tail in do_work (Array.of_list []) d ;; (* Read ---- *) let unzipped_filename filename = if not (Sys.file_exists filename) then raise (Failure ("file "^filename^" doesn't exist")); let uz_filename = Filename.temp_file "" ".tmp" ~temp_dir:(Sys.getcwd ()) in let command = "zcat "^filename^" > "^uz_filename in if (Sys.command command) == 0 then uz_filename else begin Sys.remove uz_filename ; raise (Failure ("Unable to execute :\n"^command)) end ;; let read_rank in_channel = let trimmed_line = trim (input_line in_channel) in int_of_string trimmed_line ;; let read_dimensions in_channel = let trimmed_line = trim (input_line in_channel) in let list_of_str = split trimmed_line ' ' in Array.of_list (List.map int_of_string list_of_str) ;; let read_array type_conversion group name : 'a ezfio_array = let in_filename = !ezfio_filename ^ "/" ^ group ^ "/" ^ name ^ ".gz" in let uz_filename = unzipped_filename in_filename in let in_channel = open_in uz_filename in (* Read rank *) let rank = read_rank in_channel (* Read dimensions *) and dimensions = read_dimensions in_channel in begin assert (rank == Array.length dimensions) ; (* Read one-dimensional arrays *) let read_1d nmax = let rec do_work accu = function | 0 -> Array.of_list (List.rev accu) | n -> let trimmed_line = trim (input_line in_channel) in do_work ( (type_conversion trimmed_line)::accu ) (n-1) in Ezfio_item (do_work [] nmax) in (* Read multi-dimensional arrays *) let rec read_nd = function | m when m<1 -> raise (Failure "dimension should not be <1") | 1 -> read_1d dimensions.(0) | m -> let rec do_work accu = function | 0 -> Array.of_list (List.rev accu) | n -> let newlist = read_nd (m-1) in do_work (newlist::accu) (n-1) in Ezfio_data (do_work [] dimensions.(m-1)) in let result = { rank = rank ; dim = dimensions ; data = read_nd rank ; } in close_in in_channel ; Sys.remove uz_filename ; result; end ;; let read_int_array = read_array int_of_string and read_float_array = read_array float_of_string and read_bool_array = read_array fortran_bool_of_string and read_string_array = read_array (fun (x:string) -> x) ;; (* Write ----- *) let write_array print_fun group name a = check_readonly; create_group group; let out_filename = !ezfio_filename ^ "/" ^ group ^ "/" ^ name ^".gz" in let uz_filename = Filename.temp_file "" ".tmp" ~temp_dir:(Sys.getcwd ()) in let out_channel = open_out uz_filename in let { rank=rank ; dim=dimensions ; data=data } = a in let data = flattened_ezfio_data data in begin (* Write rank *) Printf.fprintf out_channel "%4d\n" rank; (* Write dimensions *) Array.iter (Printf.fprintf out_channel " %8d") dimensions; Printf.fprintf out_channel "\n"; Array.iter (print_fun out_channel) data; close_out out_channel ; let command = "gzip -c < "^uz_filename^" > "^out_filename in if (Sys.command command == 0) then (Sys.remove uz_filename ) else raise (Failure ("command failed:\n"^command)) end ;; let write_int_array = write_array print_int and write_float_array = write_array print_float and write_string_array = write_array print_string and write_bool_array = write_array print_bool;; (* Library routines *) let set_file filename = if not (exists filename) then begin mkdir filename; mkdir (filename^"/ezfio"); let command = Printf.sprintf " LANG= date > %s/ezfio/creation echo $USER > %s/ezfio/user echo %s > %s/ezfio/library" filename filename library filename in if (Sys.command command <> 0) then raise (Failure ("Unable to create new ezfio file:\n"^filename)) end ; ezfio_filename := filename ;; (*$TAIL*)