1996-02-15 08:25:44 -08:00
|
|
|
(***********************************************************************)
|
|
|
|
(* *)
|
1996-04-30 07:53:58 -07:00
|
|
|
(* Objective Caml *)
|
1996-02-15 08:25:44 -08:00
|
|
|
(* *)
|
1996-10-31 08:03:04 -08:00
|
|
|
(* Xavier Leroy and Damien Doligez, INRIA Rocquencourt *)
|
1996-02-15 08:25:44 -08:00
|
|
|
(* *)
|
1996-04-30 07:53:58 -07:00
|
|
|
(* Copyright 1996 Institut National de Recherche en Informatique et *)
|
1999-11-17 10:59:06 -08:00
|
|
|
(* en Automatique. All rights reserved. This file is distributed *)
|
2001-12-07 05:41:02 -08:00
|
|
|
(* under the terms of the GNU Library General Public License, with *)
|
|
|
|
(* the special exception on linking described in file ../LICENSE. *)
|
1996-02-15 08:25:44 -08:00
|
|
|
(* *)
|
|
|
|
(***********************************************************************)
|
|
|
|
|
|
|
|
(* $Id$ *)
|
|
|
|
|
2002-03-12 08:16:56 -08:00
|
|
|
let generic_quote quotequote s =
|
|
|
|
let l = String.length s in
|
|
|
|
let b = Buffer.create (l + 20) in
|
|
|
|
Buffer.add_char b '\'';
|
|
|
|
for i = 0 to l - 1 do
|
|
|
|
if s.[i] = '\''
|
|
|
|
then Buffer.add_string b quotequote
|
|
|
|
else Buffer.add_char b s.[i]
|
|
|
|
done;
|
|
|
|
Buffer.add_char b '\'';
|
|
|
|
Buffer.contents b
|
|
|
|
|
2006-04-16 16:28:22 -07:00
|
|
|
let generic_basename rindex_dir_sep current_dir_name name =
|
|
|
|
let raw_name =
|
|
|
|
try
|
|
|
|
let p = rindex_dir_sep name + 1 in
|
|
|
|
String.sub name p (String.length name - p)
|
|
|
|
with Not_found ->
|
|
|
|
name
|
|
|
|
in
|
|
|
|
if raw_name = "" then current_dir_name else raw_name
|
|
|
|
|
|
|
|
let generic_dirname rindex_dir_sep current_dir_name dir_sep name =
|
|
|
|
try
|
|
|
|
match rindex_dir_sep name with
|
|
|
|
0 -> dir_sep
|
|
|
|
| n -> String.sub name 0 n
|
|
|
|
with Not_found ->
|
|
|
|
current_dir_name
|
|
|
|
|
2000-08-10 02:58:08 -07:00
|
|
|
module Unix = struct
|
|
|
|
let current_dir_name = "."
|
|
|
|
let parent_dir_name = ".."
|
2004-05-30 02:41:53 -07:00
|
|
|
let dir_sep = "/"
|
|
|
|
let is_dir_sep s i = s.[i] = '/'
|
|
|
|
let rindex_dir_sep s = String.rindex s '/'
|
2000-08-10 02:58:08 -07:00
|
|
|
let is_relative n = String.length n < 1 || n.[0] <> '/';;
|
|
|
|
let is_implicit n =
|
|
|
|
is_relative n
|
|
|
|
&& (String.length n < 2 || String.sub n 0 2 <> "./")
|
|
|
|
&& (String.length n < 3 || String.sub n 0 3 <> "../")
|
|
|
|
let check_suffix name suff =
|
|
|
|
String.length name >= String.length suff &&
|
|
|
|
String.sub name (String.length name - String.length suff)
|
|
|
|
(String.length suff) = suff
|
2006-01-04 08:55:50 -08:00
|
|
|
let temp_dir_name =
|
2000-08-10 02:58:08 -07:00
|
|
|
try Sys.getenv "TMPDIR" with Not_found -> "/tmp"
|
2005-10-25 11:34:07 -07:00
|
|
|
let quote = generic_quote "'\\''"
|
2006-04-16 16:28:22 -07:00
|
|
|
let basename = generic_basename rindex_dir_sep current_dir_name
|
|
|
|
let dirname = generic_dirname rindex_dir_sep current_dir_name dir_sep
|
2000-08-10 02:58:08 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
module Win32 = struct
|
|
|
|
let current_dir_name = "."
|
|
|
|
let parent_dir_name = ".."
|
2004-05-30 02:41:53 -07:00
|
|
|
let dir_sep = "\\"
|
|
|
|
let is_dir_sep s i = let c = s.[i] in c = '/' || c = '\\' || c = ':'
|
|
|
|
let rindex_dir_sep s =
|
|
|
|
let rec pos i =
|
|
|
|
if i < 0 then raise Not_found
|
2006-04-16 16:28:22 -07:00
|
|
|
else if is_dir_sep s i then i
|
2004-05-30 02:41:53 -07:00
|
|
|
else pos (i - 1)
|
|
|
|
in pos (String.length s - 1)
|
2000-08-10 02:58:08 -07:00
|
|
|
let is_relative n =
|
|
|
|
(String.length n < 1 || n.[0] <> '/')
|
|
|
|
&& (String.length n < 1 || n.[0] <> '\\')
|
|
|
|
&& (String.length n < 2 || n.[1] <> ':')
|
|
|
|
let is_implicit n =
|
|
|
|
is_relative n
|
|
|
|
&& (String.length n < 2 || String.sub n 0 2 <> "./")
|
|
|
|
&& (String.length n < 2 || String.sub n 0 2 <> ".\\")
|
|
|
|
&& (String.length n < 3 || String.sub n 0 3 <> "../")
|
|
|
|
&& (String.length n < 3 || String.sub n 0 3 <> "..\\")
|
|
|
|
let check_suffix name suff =
|
|
|
|
String.length name >= String.length suff &&
|
|
|
|
(let s = String.sub name (String.length name - String.length suff)
|
|
|
|
(String.length suff) in
|
|
|
|
String.lowercase s = String.lowercase suff)
|
2006-01-04 08:55:50 -08:00
|
|
|
let temp_dir_name =
|
2003-03-24 07:26:35 -08:00
|
|
|
try Sys.getenv "TEMP" with Not_found -> "."
|
2002-03-12 08:16:56 -08:00
|
|
|
let quote s =
|
|
|
|
let l = String.length s in
|
|
|
|
let b = Buffer.create (l + 20) in
|
|
|
|
Buffer.add_char b '\"';
|
2007-01-09 05:42:17 -08:00
|
|
|
let rec loop i =
|
2008-12-03 10:09:09 -08:00
|
|
|
if i = l then Buffer.add_char b '\"' else
|
2002-03-12 08:16:56 -08:00
|
|
|
match s.[i] with
|
2007-01-09 05:42:17 -08:00
|
|
|
| '\"' -> loop_bs 0 i;
|
|
|
|
| '\\' -> loop_bs 0 i;
|
|
|
|
| c -> Buffer.add_char b c; loop (i+1);
|
|
|
|
and loop_bs n i =
|
2008-12-03 10:09:09 -08:00
|
|
|
if i = l then begin
|
|
|
|
Buffer.add_char b '\"';
|
|
|
|
add_bs n;
|
|
|
|
end else begin
|
|
|
|
match s.[i] with
|
|
|
|
| '\"' -> add_bs (2*n+1); Buffer.add_char b '\"'; loop (i+1);
|
|
|
|
| '\\' -> loop_bs (n+1) (i+1);
|
|
|
|
| c -> add_bs n; loop i
|
|
|
|
end
|
2007-01-09 05:42:17 -08:00
|
|
|
and add_bs n = for j = 1 to n do Buffer.add_char b '\\'; done
|
|
|
|
in
|
|
|
|
loop 0;
|
2002-03-12 08:16:56 -08:00
|
|
|
Buffer.contents b
|
2006-04-16 16:28:22 -07:00
|
|
|
let has_drive s =
|
|
|
|
let is_letter = function
|
|
|
|
| 'A' .. 'Z' | 'a' .. 'z' -> true
|
|
|
|
| _ -> false
|
|
|
|
in
|
|
|
|
String.length s >= 2 && is_letter s.[0] && s.[1] = ':'
|
|
|
|
let drive_and_path s =
|
|
|
|
if has_drive s
|
|
|
|
then (String.sub s 0 2, String.sub s 2 (String.length s - 2))
|
|
|
|
else ("", s)
|
|
|
|
let dirname s =
|
|
|
|
let (drive, path) = drive_and_path s in
|
|
|
|
let dir = generic_dirname rindex_dir_sep current_dir_name dir_sep path in
|
|
|
|
drive ^ dir
|
|
|
|
let basename s =
|
|
|
|
let (drive, path) = drive_and_path s in
|
|
|
|
generic_basename rindex_dir_sep current_dir_name path
|
2000-08-10 02:58:08 -07:00
|
|
|
end
|
|
|
|
|
2003-07-07 02:07:45 -07:00
|
|
|
module Cygwin = struct
|
|
|
|
let current_dir_name = "."
|
|
|
|
let parent_dir_name = ".."
|
2004-05-30 02:41:53 -07:00
|
|
|
let dir_sep = "/"
|
|
|
|
let is_dir_sep = Win32.is_dir_sep
|
|
|
|
let rindex_dir_sep = Win32.rindex_dir_sep
|
2003-07-07 02:07:45 -07:00
|
|
|
let is_relative = Win32.is_relative
|
|
|
|
let is_implicit = Win32.is_implicit
|
|
|
|
let check_suffix = Win32.check_suffix
|
2006-01-04 08:55:50 -08:00
|
|
|
let temp_dir_name = Unix.temp_dir_name
|
2003-07-07 02:07:45 -07:00
|
|
|
let quote = Unix.quote
|
2006-04-16 16:28:22 -07:00
|
|
|
let basename = generic_basename rindex_dir_sep current_dir_name
|
|
|
|
let dirname = generic_dirname rindex_dir_sep current_dir_name dir_sep
|
2003-07-07 02:07:45 -07:00
|
|
|
end
|
|
|
|
|
2004-05-30 02:41:53 -07:00
|
|
|
let (current_dir_name, parent_dir_name, dir_sep, is_dir_sep, rindex_dir_sep,
|
2006-04-16 16:28:22 -07:00
|
|
|
is_relative, is_implicit, check_suffix, temp_dir_name, quote, basename,
|
|
|
|
dirname) =
|
1996-11-07 03:00:19 -08:00
|
|
|
match Sys.os_type with
|
2003-07-07 02:07:45 -07:00
|
|
|
"Unix" ->
|
2005-10-25 11:34:07 -07:00
|
|
|
(Unix.current_dir_name, Unix.parent_dir_name, Unix.dir_sep,
|
2004-05-30 02:41:53 -07:00
|
|
|
Unix.is_dir_sep, Unix.rindex_dir_sep,
|
2000-08-10 02:58:08 -07:00
|
|
|
Unix.is_relative, Unix.is_implicit, Unix.check_suffix,
|
2006-04-16 16:28:22 -07:00
|
|
|
Unix.temp_dir_name, Unix.quote, Unix.basename, Unix.dirname)
|
2000-08-10 02:58:08 -07:00
|
|
|
| "Win32" ->
|
2005-10-25 11:34:07 -07:00
|
|
|
(Win32.current_dir_name, Win32.parent_dir_name, Win32.dir_sep,
|
2004-05-30 02:41:53 -07:00
|
|
|
Win32.is_dir_sep, Win32.rindex_dir_sep,
|
2000-08-10 02:58:08 -07:00
|
|
|
Win32.is_relative, Win32.is_implicit, Win32.check_suffix,
|
2006-04-16 16:28:22 -07:00
|
|
|
Win32.temp_dir_name, Win32.quote, Win32.basename, Win32.dirname)
|
2003-07-07 02:07:45 -07:00
|
|
|
| "Cygwin" ->
|
2005-10-25 11:34:07 -07:00
|
|
|
(Cygwin.current_dir_name, Cygwin.parent_dir_name, Cygwin.dir_sep,
|
2004-05-30 02:41:53 -07:00
|
|
|
Cygwin.is_dir_sep, Cygwin.rindex_dir_sep,
|
2003-07-07 02:07:45 -07:00
|
|
|
Cygwin.is_relative, Cygwin.is_implicit, Cygwin.check_suffix,
|
2006-04-16 16:28:22 -07:00
|
|
|
Cygwin.temp_dir_name, Cygwin.quote, Cygwin.basename, Cygwin.dirname)
|
1997-10-24 08:54:07 -07:00
|
|
|
| _ -> assert false
|
1996-02-15 08:25:44 -08:00
|
|
|
|
2004-05-30 02:41:53 -07:00
|
|
|
let concat dirname filename =
|
|
|
|
let l = String.length dirname in
|
|
|
|
if l = 0 || is_dir_sep dirname (l-1)
|
|
|
|
then dirname ^ filename
|
|
|
|
else dirname ^ dir_sep ^ filename
|
|
|
|
|
1996-02-15 08:25:44 -08:00
|
|
|
let chop_suffix name suff =
|
|
|
|
let n = String.length name - String.length suff in
|
|
|
|
if n < 0 then invalid_arg "Filename.chop_suffix" else String.sub name 0 n
|
1996-10-06 09:38:09 -07:00
|
|
|
|
1996-02-15 08:25:44 -08:00
|
|
|
let chop_extension name =
|
2004-05-30 02:41:53 -07:00
|
|
|
let rec search_dot i =
|
|
|
|
if i < 0 || is_dir_sep name i then invalid_arg "Filename.chop_extension"
|
|
|
|
else if name.[i] = '.' then String.sub name 0 i
|
|
|
|
else search_dot (i - 1) in
|
|
|
|
search_dot (String.length name - 1)
|
1996-02-15 08:25:44 -08:00
|
|
|
|
2003-12-08 11:50:26 -08:00
|
|
|
external open_desc: string -> open_flag list -> int -> int = "caml_sys_open"
|
2003-12-16 10:09:44 -08:00
|
|
|
external close_desc: int -> unit = "caml_sys_close"
|
2002-04-15 04:42:45 -07:00
|
|
|
|
2003-06-12 09:49:32 -07:00
|
|
|
let prng = Random.State.make_self_init ();;
|
2002-04-15 04:42:45 -07:00
|
|
|
|
2010-01-20 08:26:46 -08:00
|
|
|
let temp_file_name temp_dir prefix suffix =
|
2003-06-12 09:49:32 -07:00
|
|
|
let rnd = (Random.State.bits prng) land 0xFFFFFF in
|
2010-01-20 08:26:46 -08:00
|
|
|
concat temp_dir (Printf.sprintf "%s%06x%s" prefix rnd suffix)
|
2003-06-12 09:49:32 -07:00
|
|
|
;;
|
1996-02-15 08:25:44 -08:00
|
|
|
|
2010-01-20 08:26:46 -08:00
|
|
|
let temp_file ?(temp_dir=temp_dir_name) prefix suffix =
|
1996-02-15 08:25:44 -08:00
|
|
|
let rec try_name counter =
|
2010-01-20 08:26:46 -08:00
|
|
|
let name = temp_file_name temp_dir prefix suffix in
|
2002-04-15 04:42:45 -07:00
|
|
|
try
|
|
|
|
close_desc(open_desc name [Open_wronly; Open_creat; Open_excl] 0o600);
|
|
|
|
name
|
2005-01-18 06:33:08 -08:00
|
|
|
with Sys_error _ as e ->
|
|
|
|
if counter >= 1000 then raise e else try_name (counter + 1)
|
1996-02-15 08:25:44 -08:00
|
|
|
in try_name 0
|
1996-10-31 08:03:04 -08:00
|
|
|
|
2010-01-20 08:26:46 -08:00
|
|
|
let open_temp_file ?(mode = [Open_text]) ?(temp_dir=temp_dir_name) prefix suffix =
|
2002-04-15 04:42:45 -07:00
|
|
|
let rec try_name counter =
|
2010-01-20 08:26:46 -08:00
|
|
|
let name = temp_file_name temp_dir prefix suffix in
|
2002-04-15 04:42:45 -07:00
|
|
|
try
|
|
|
|
(name,
|
|
|
|
open_out_gen (Open_wronly::Open_creat::Open_excl::mode) 0o600 name)
|
2005-01-18 06:33:08 -08:00
|
|
|
with Sys_error _ as e ->
|
|
|
|
if counter >= 1000 then raise e else try_name (counter + 1)
|
2002-04-15 04:42:45 -07:00
|
|
|
in try_name 0
|