let find ?(follow = Skip) ?match_compile tst fln exec user_acc =
let user_test =
compile_filter ?match_compile tst
in
let process_file ((user_acc, already_read) as acc) st fln =
if user_test ~pre_stat:st fln then
(exec user_acc fln), already_read
else
acc
in
let skip_action =
match follow with
| Skip | AskFollow _ | Follow ->
ignore
| SkipInform f ->
f
in
let should_skip fln already_followed =
match follow with
| Skip | SkipInform _ ->
true
| AskFollow f ->
if not already_followed then
(f fln)
else
true
| Follow ->
if already_followed then
raise (RecursiveLink fln)
else
false
in
let rec find_aux acc fln =
try
(
let st =
stat fln
in
if st.kind = Dir then
(
if st.is_link then
(
let (user_acc, dir_links) =
acc
in
let cur_link =
readlink fln
in
let dir_links, already_followed =
try
(prevent_recursion dir_links cur_link), false
with RecursiveLink _ ->
dir_links, true
in
let acc =
user_acc, dir_links
in
if should_skip fln already_followed then
(
skip_action fln;
acc
)
else
(
find_in_dir
(process_file acc st fln)
fln
)
)
else
(
find_in_dir
(process_file acc st fln)
fln
)
)
else
(
process_file acc st fln
)
)
with FileDoesntExist _ ->
acc
and find_in_dir acc drn =
Array.fold_left
(fun acc rfln ->
if is_parent rfln || is_current rfln then
acc
else
find_aux acc (concat drn rfln))
acc
(Sys.readdir drn)
in
let user_acc, _ =
find_aux
(user_acc, SetFilename.empty)
(reduce fln)
in
user_acc