module Kwfile:sig
..end
These don't do I/O in general, but include functions that read
directories and perform stats.
Author(s): Keith Waclena
val filesplit : ?sep:string -> string -> string list
filesplit ?sep fn
: split a filename into its components
Filename.dirname
and Filename.basename
have all sorts of wild
boundary conditions!
This is "supposedly" better than a string split on "/" because we
get a. automatic normalization and b. portability across different
pathseps
sep
: the path separator (default: Filename.dir_sep
)fn
: the filenameval join : string -> string -> string
join dir file
returns a file name that designates file file
in directory dir
.
This is what Filename.concat does, but that function is more literal
than I want it to be, e.g. Filename.concat "." "/etc/motd"
returns ".//etc/motd"
, which I think is weird; join "."
"/etc/motd"
instead returns "/etc/motd"
.
Returns "joined" filename
dir
: directory pathnameval extsplit : string -> string * string option
extsplit path
splits a file path into two parts by separating the extension (if any).
Returns a pair, the fst of which is the path with the extension
removed, and the snd of which is the extension as a string option
.
Returns the pair, front part and optional extension
path
: a pathnameval extjoin : string * string option -> string
extjoin path
joins an optional extension onto a file path; the dual of Kwfile.extsplit
.
So, p = extjoin (extsplit p)
. Useful for changing an extension:
# Kwfile.extsplit "foo.xml" |> (id &&& k (Some "jpg")) |> extjoin;; \- : string = "foo.jpg" # Kwfile.extsplit "foo.xml" |> (id &&& k None) |> extjoin;; \- : string = "foo" #
pair
: a pathname and extension option, as returned by Kwfile.extsplit
val extension : string -> string
extension file
returns the file's extension, without the '.'
if no extension, return ""val squiggle : ?respect_env:bool -> string -> string
"HOME"
env var is respected unless ~respect_env
is false
respect_env
: respect (i.e. trust) the value of env dir "HOME"? (default: true
)fn
: file nameval (~~) : ?respect_env:bool -> string -> string
val makesafe : string -> string
makesafe path
returns a "safe" version of the pathname (intended for web applications).
"Safe" means all instances of "."
, ".."
and any leading "/"
's
are eliminated. "Safe" does not mean that any shell
metacharacters are eliminated! This function assumes you will be
using system calls on the resulting "safe" pathname, not passing
it to a shell.
find(1)
.val mkdirs : ?mode:Unix.file_perm -> string -> unit
mkdirs ?mode path
: make all the directories in path
(including parent directories, as needed).
Like the shell's mkdir -p
. No error if any of the directories exist.
mode
: the mode of newly-created directoriespath
: the path of the new directoryval fold_dir : ('a -> string -> 'a) -> 'a -> string -> 'a
fold_dir f init dir
: fold over the files in a directory (not recursive).
Tail-recursive. Applies f acc fn
to each file in dir
(excluding .
and ..
);
sub-directories are not recursed into.
f
: function f acc filename
to apply to each filedir
: the directory (or file, even) to fold overval fold : ?follow:bool ->
?err:(int -> 'a -> string -> exn -> 'a) ->
(int -> 'a -> string -> 'a) -> 'a -> string -> 'a
fold ?follow ?err f acc dir
: fold over a directory hierarchy (recursive).
NOT tail-recursive in depth of tree, but is tail-recursive in
breadth of any given sub-directory.
follow
: whether to descend into symlinked sub-directories (default: false
, as per find(1))err
: alternate function err depth acc filename exn
called (instead of f
) if there's an
exception exn
associated with stat
'ing or opendir
'ing dir
(default: re-raise exn
)f
: function f depth acc filename
to apply to each fileacc
: the accumulatordir
: the directory (or file, even) to fold overKwfile.fold
.
Examples:
fold (igndepth (flip cons)) [] "." fold (maxdepth 2 (flip cons)) [] "."
val igndepth : 'a -> 'b -> 'a
igndepth f
: makes a function that's suitable for List.fold_left
suitable for Kwfile.fold
by
ignoring the depth parameter.
Use this if you don't care about how deep you are when you process a file.
val maxdepth : 'a -> ('b -> 'c -> 'b) -> 'a -> 'b -> 'c -> 'b
maxdepth n f
: converts a function that's suitable for List.fold_left
into a function
suitable for Kwfile.fold
that's only applied to files up to a maximum depth of n
.val pred : ('a -> 'b -> bool) -> ('a -> 'c -> 'b -> 'c) -> 'a -> 'c -> 'b -> 'c
pred p f
: converts a function that's suitable for Kwfile.fold
into one that that's only
applied if p depth filename
returns true.val ignexn : ('a -> 'b -> 'c -> 'd) -> 'a -> 'b -> 'c -> 'e -> 'd
ignexn f
: makes function that's suitable for Kwfile.fold
's f
parameter suitable for
its ~err
parameter by ignoring the exception.
Use this if you want to process un-stat-able files the same way as stat-able ones. For example, to simply count all files in a directory hierarchy, do:
let count _ a _ = a+1 in fold ~err:(ignexn count) count 0
module Find:sig
..end
val glob : ?pred:(string -> bool) ->
(string -> string -> string -> 'a) -> string -> 'a list
Kwfile.fold_dir
.glob ?pred map dir
: return list of results of
applying map
to each file in a directory
NOT tail-recursive.
Returns list of "mapped" results of all matching files
pred
: predicate (string -> bool)
on a filename (default: (fun x -> true)
)map
: function (string -> string -> string -> 'a)
to apply to each filename in result list; saves you a List.map
over the result; parameters are directoryname, basename, and full path (i.e. (Filename.concat directoryname basename)
)dir
: directory to processval isemptydir : string -> bool
path
(presumed a directory) an empty directory?
This is faster (and uses less space) than
0 = List.length (glob (fun _ _ _ -> ()) path)
if the directory contains a lot of files.
Raises Unix.Unix_error
(Unix.ENOTDIR, "opendir", ...) if path
not a directory
Returns bool
path
: path to a directoryval isfile : string -> bool
bool
f
: filenameval isdirectory : string -> bool
bool
f
: filenameval ischaracter : string -> bool
bool
f
: filenameval isblock : string -> bool
bool
f
: filenameval islink : string -> bool
bool
f
: filenameval isfifo : string -> bool
bool
f
: filenameval issocket : string -> bool
bool
f
: filenameval access : string -> Unix.access_permission list -> bool
bool
range and no exceptionsbool
f
: filenameperms
: Unix.access_permission list
val isreadable : string -> bool
bool
f
: filenameval iswriteable : string -> bool
bool
f
: filenameval isexecutable : string -> bool
bool
f
: filenameval isexefile : string -> bool
bool
f
: filenameval exists : string -> bool
bool
f
: filenameval which : string -> string list
PATH
Lookup a (potential) executable name in (Sys.getenv "$PATH")
and
return all the candidates found, in PATH
order.
Returns list of (basename,fullpath) pairs for each executable found
sought
: name of the executable in questiontype
tempfile = {
|
filename : |
|
chan : |
val temp_file_name : ?tmpdir:string -> string -> string -> string
temp_file_name ?tmpdir prefix suffix
: return a random filenametmpdir
: directory in which to make tmpfile (default: value of TMPDIR
env var, else /tmp
)prefix
: temp filename prefixsuffix
: temp filename suffixval open_temp_file : ?tmpdir:string ->
?mode:Pervasives.open_flag list ->
?perm:int -> string -> string -> string * Pervasives.out_channel
(filename,out_channel)
tmpdir
: directory in which to make tmpfile (default: value of TMPDIR
env var, else /tmp
)mode
: list of open modesperm
: file permissions (default: 0o600
)prefix
: temp filename prefixsuffix
: temp filename suffixval tempfiles : ?n:int ->
?tmpdir:string ->
string -> string list -> (string, tempfile) Hashtbl.t
tempfile
's
Example:
let t = Kwfile.tempfiles "myself" ["foo"; "bar"] in
Printf.fprintf (Hashtbl.find t "foo").Kwfile.chan "foo stuff";
Printf.fprintf (Hashtbl.find t "bar").Kwfile.chan "bar stuff";
Hashtbl.iter (fun _ {Kwfile.chan=c} -> close_out c) t;
Hashtbl.iter (fun _ {Kwfile.filename=f} -> Sys.remove f) t;
n
: initial size of hash table (default: 2
)tmpdir
: directory in which to make tmpfileprefix
: string to prefix to each temp file name, typically something like (Filename.basename Sys.argv(0))
handles
: list of tempfile "handles" (strings)val with_temp_file : ?remove:(string -> unit) ->
?tmpdir:string -> string -> string -> (string -> 'a) -> 'a
with_temp_file ?remove ?tmpdir prefix suffix f
: call f tmp
where tmp
is a newly-created
temp file, making sure to remove the temp file after the evaluation of f
.
If you want to examine the temp file for debugging purposes, you can use e..g.
with_temp_file ~remove:ignore
or to see the name of the temp file, something like:
with_temp_file ~remove:(fun fn -> prerr_endline fn; Sys.remove fn)
.
If it's possible that f
might not create the temp file, and you want to avoid a
Sys_error
"No such file or directory" exception, you can use e.g.
with_temp_file ~remove:(ignex Sys.remove)
.
remove
: function to remove the temp file (default: Sys.remove
)tmpdir
: directory in which to make tmpfile (default: value of TMPDIR
env var, else /tmp
)prefix
: temp filename prefixsuffix
: temp filename suffixf
: the function