staload "libc/SATS/dirent.sats"
staload "libc/sys/SATS/stat.sats"
staload "libc/sys/SATS/types.sats"
%{^
#define MAXPATHLEN 1024
%} #define MAXPATHLEN 1024
extern fun fsize (name: string): void
extern fun dirwalk (dir: string, f: (string) -> void): void
implement main (argc, argv) = let
fun loop {n,i:nat | i <= n}
(A: &(@[string][n]), n: int n, i: int i): void =
if i < n then (fsize A.[i]; loop (A, n, i+1)) else ()
in
if argc = 1 then fsize "." else loop (argv, argc, 1)
end
implement fsize (name) = let
var stbuf: stat? val err = stat_err (name, stbuf)
in
if err >= 0 then let
prval () = opt_unsome {stat} (stbuf)
val mode = stbuf.st_mode
in
if S_ISDIR (mode) then
dirwalk (name, fsize)
else let
val sz_off = stbuf.st_size
val sz_lint = lint_of_off (sz_off)
in
printf ("%8ld %s\n", @(sz_lint, name))
end end else let
prval () = opt_unnone {stat} (stbuf)
in
end end
extern
fun dirent_is_self (dp: &dirent):<> bool = "atslib_dirent_is_self"
extern
fun dirent_is_parent (dp: &dirent):<> bool = "atslib_dirent_is_parent"
%{^
ATSinline()
ats_bool_type
atslib_dirent_is_self (ats_ref_type dp) {
int cmp = strcmp (((ats_dirent_type*)dp)->d_name, ".") ;
if (cmp == 0) return ats_true_bool ;
return ats_false_bool ;
} /* end of [atslib_dirent_is_self] */
ATSinline()
ats_bool_type
atslib_dirent_is_parent (ats_ref_type dp) {
int cmp = strcmp (((ats_dirent_type*)dp)->d_name, "..") ;
if (cmp == 0) return ats_true_bool ;
return ats_false_bool ;
} /* end of [atslib_dirent_is_self] */
%}
implement
dirwalk (dirname, f) = let
#define M MAXPATHLEN
typedef buf_t = bytes M
var !p_name with pf_name = @[byte][M]()
val () = pf_name := bytes_v_of_b0ytes_v (pf_name)
val (pfopt_dir | p_dir) = opendir_err (dirname)
in
if (p_dir > null) then let
prval Some_v pf_dir = pfopt_dir
fun loop (
buf: &buf_t, dir: &DIR
) :<cloref1> void = let
val (pfopt | p_ent) = readdir (dir)
in
if (p_ent > null) then let
prval Some_v @(pf, fpf) = pfopt
val () = case+ 0 of
| _ when dirent_is_self (!p_ent) =>
$effmask_ref (loop (buf, dir))
| _ when dirent_is_parent (!p_ent) =>
$effmask_ref (loop (buf, dir))
| _ => let
val direntnameopt =
direntnameopt_make (
buf, dirname, !p_ent
) where {
extern fun direntnameopt_make (
buf: &buf_t, dir: string, ent: &dirent
) :<> Stropt = "direntnameopt_make"
} val () = begin
if stropt_is_some (direntnameopt) then begin
$effmask_ref (f (stropt_unsome direntnameopt))
end end in
$effmask_ref (loop (buf, dir))
end prval () = fpf (pf)
in
end else let
prval None_v () = pfopt in
end end val () = loop (!p_name, !p_dir)
in
closedir_exn (pf_dir | p_dir)
end else let
prval None_v () = pfopt_dir
in
prerrf ("*** ERROR ***: dirwalk: can't open [%s]\n", @(dirname))
end end
%{^
ats_ptr_type
direntnameopt_make (
ats_ref_type buf, ats_ptr_type dir, ats_ref_type ent
) {
int cnt ;
cnt = snprintf
((char*)buf, MAXPATHLEN, "%s/%s", dir, ((ats_dirent_type*)ent)->d_name) ;
if (cnt < MAXPATHLEN) return buf ;
return (ats_ptr_type)0 ;
} // end of [direntnameopt_make]
%}