%{^
#include <sys/stat.h>
%}
staload Loc = "ats_location.sats"
staload Sym = "ats_symbol.sats"
overload = with $Sym.eq_symbol_symbol
overload <> with $Sym.neq_symbol_symbol
staload "ats_filename.sats"
staload "ats_reference.sats"
staload _ = "ats_reference.dats"
fn prerr_interror () = prerr "INTERNAL ERROR (ats_filename)"
local
#include "prelude/params_system.hats"
#if OPERATING_SYSTEM_IS_UNIX_LIKE #then
val theDirsep: char = '/'
val theCurdir: string = "./"
val thePredir: string = "../"
#endif
in
extern fun getcwd0 (): String = "atslib_getcwd0"
implement theDirsep_get () = theDirsep
implement theCurdir_get () = theCurdir
implement thePredir_get () = thePredir
end
#define THISFILENAME "ats_filename.dats"
implement
filename_is_relative (name) = let
val name = string1_of_string name
fn aux {n,i:nat | i <= n}
(name: string n, i: size_t i, dirsep: char): bool =
if string_is_at_end (name, i) then true else name[i] <> dirsep
val dirsep = theDirsep_get ()
in
aux (name, 0, dirsep)
end
%{^
//
ATSinline()
ats_bool_type
atsopt_filename_is_exist
(ats_ptr_type name) {
struct stat st ;
return stat ((char*)name, &st) ? ats_false_bool : ats_true_bool ;
} /* end of [atsopt_filename_is_exist] */
//
%}
%{$
ats_ptr_type
atsopt_filename_append (
ats_ptr_type dir, ats_ptr_type bas
) {
int n1, n2, n ;
char dirsep, *dirbas ;
//
dirsep = atsopt_filename_theDirsep_get () ;
//
n1 = strlen ((char*)dir) ;
n2 = strlen ((char*)bas) ;
n = n1 + n2 ;
if (n1 > 0 && ((char*)dir)[n1-1] != dirsep) n += 1 ;
dirbas = ATS_MALLOC (n + 1) ;
memcpy (dirbas, dir, n1) ;
if (n > n1 + n2) { dirbas[n1] = dirsep ; n1 += 1 ; }
memcpy (dirbas + n1, bas, n2) ;
dirbas[n] = '\000' ;
return dirbas ;
} /* end of [atsopt_filename_append] */
%}
typedef filename = '{
filename_full= string, filename_full_sym= $Sym.symbol_t
}
assume filename_t = filename
implement filename_none = '{
filename_full= "(none)"
, filename_full_sym= $Sym.symbol_empty
}
implement filename_stdin = '{
filename_full= "stdin"
, filename_full_sym= $Sym.symbol_STDIN
}
implement lt_filename_filename
(x1, x2) = x1.filename_full < x2.filename_full
implement lte_filename_filename
(x1, x2) = x1.filename_full <= x2.filename_full
implement gt_filename_filename
(x1, x2) = x1.filename_full > x2.filename_full
implement gte_filename_filename
(x1, x2) = x1.filename_full >= x2.filename_full
implement eq_filename_filename (x1, x2) = x1.filename_full_sym = x2.filename_full_sym
implement neq_filename_filename (x1, x2) = x1.filename_full_sym <> x2.filename_full_sym
implement compare_filename_filename (x1, x2) =
compare (x1.filename_full, x2.filename_full)
implement fprint_filename (pf | out, x) =
fprint_string (pf | out, x.filename_full)
implement print_filename (x) = print_mac (fprint_filename, x)
implement prerr_filename (x) = prerr_mac (fprint_filename, x)
implement print_filename_base (x) = print_mac (fprint_filename_base, x)
implement prerr_filename_base (x) = prerr_mac (fprint_filename_base, x)
typedef path = string
staload "ats_list.sats"
staload _ = "ats_list.dats"
fun path_normalize (s0: path): path = let
fun loop1 {n0,i0:nat | i0 <= n0} (
dirsep: char
, s0: string n0, n0: size_t n0, i0: size_t i0, dirs: &List_vt string
) : void =
if i0 < n0 then loop2 (dirsep, s0, n0, i0, i0, dirs) else ()
and loop2 {n0,i0,i:nat | i0 < n0; i0 <= i; i <= n0} (
dirsep: char
, s0: string n0, n0: size_t n0, i0: size_t i0, i: size_t i, dirs: &List_vt string
) : void =
if i < n0 then let
in
if s0[i] <> dirsep then
loop2 (dirsep, s0, n0, i0, i+1, dirs)
else let
val sbp = string_make_substring (s0, i0, i - i0 + 1)
val dir = string1_of_strbuf (sbp)
in
dirs := list_vt_cons (dir, dirs); loop1 (dirsep, s0, n0, i + 1, dirs)
end end else let
val sbp = string_make_substring (s0, i0, i - i0)
val dir = string1_of_strbuf (sbp)
in
dirs := list_vt_cons (dir, dirs)
end fun dirs_process (
curdir: string, predir: string
, npre: Nat, dirs: List_vt string, res: List_vt string
) : List_vt string = case+ dirs of
| ~list_vt_cons (dir, dirs) => begin
if dir = curdir then
dirs_process (curdir, predir, npre, dirs, res)
else if dir = predir then
dirs_process (curdir, predir, npre + 1, dirs, res)
else begin
if npre > 0 then begin
dirs_process (curdir, predir, npre - 1, dirs, res)
end else begin
dirs_process (curdir, predir, 0, dirs, list_vt_cons (dir, res))
end
end
end | ~list_vt_nil () => loop (predir, npre, res) where {
fun loop (
predir: string, npre: Nat, res: List_vt string
) : List_vt string =
if npre > 0 then loop (predir, npre - 1, list_vt_cons (predir, res))
else res
} val dirsep = theDirsep_get ()
val curdir = theCurdir_get () and predir = thePredir_get ()
var dirs: List_vt string = list_vt_nil ()
val s0 = string1_of_string s0; val n0 = string_length s0
val () = loop1 (dirsep, s0, n0, 0, dirs)
val () = dirs := dirs_process (curdir, predir, 0, dirs, list_vt_nil ())
val fullname =
stringlst_concat (__cast dirs) where {
extern castfn __cast (x: !List_vt string): List string
} val () = list_vt_free (dirs)
in
string_of_strptr (fullname)
end
typedef pathlst = List path
local
val the_pathlst = ref_make_elt<pathlst> (list_nil ())
val the_prepathlst = ref_make_elt<pathlst> (list_nil ())
in
fn the_pathlst_get (): pathlst = !the_pathlst
fn the_pathlst_reset () = !the_pathlst := list_nil ()
implement the_pathlst_pop () = begin
case+ !the_pathlst of
| list_cons (_, ps) => !the_pathlst := ps
| list_nil () => begin
prerr_interror ();
prerr (": pathlst_pop: the_pathlst is empty."); prerr_newline ();
exit (1)
end end
implement the_pathlst_push (dirname) = let
val dirname_full = (case+ 0 of
| _ when filename_is_relative dirname => let
val cwd = getcwd0 () in filename_append (cwd, dirname)
end | _ => dirname
) : string
val dirname_full = path_normalize (dirname_full)
in
!the_pathlst := list_cons (dirname_full, !the_pathlst)
end
fun the_prepathlst_get (): pathlst = !the_prepathlst
implement the_prepathlst_push (dirname) = let
val () = if filename_is_relative dirname then begin
prerr_interror ();
prerr (": the_prepathlst_push: dirname = "); prerr dirname; prerr_newline ();
exit {void} (1)
end in
!the_prepathlst := list_cons (dirname, !the_prepathlst)
end
end
local
typedef filenamelst = List filename
val the_filename = ref_make_elt<filename> filename_none
val the_filenamelst = ref_make_elt<filenamelst> (list_nil ())
in
fn the_filename_reset (): void = !the_filename := filename_none
fn the_filenamelst_reset (): void = !the_filenamelst := list_nil ()
implement the_filename_get (): filename = !the_filename
val the_filenamelst_pop_err = lam () =<fun1> begin
prerr_interror ();
prerr (": the_filenamelst_pop: the_filenamelst is empty"); prerr_newline ();
exit (1)
end
implement the_filenamelst_pop () = begin
case+ !the_filenamelst of
| list_cons (f, fs) => begin
!the_filename := f; !the_filenamelst := fs
end | list_nil () => the_filenamelst_pop_err ()
end
implement the_filenamelst_push (f0) = let
val fs = list_cons (!the_filename, !the_filenamelst)
in
!the_filenamelst := fs; !the_filename := f0;
end
implement
the_filenamelst_push_xit (loc0, f0) = let
val loc0 = __cast loc0 where {
extern castfn __cast (x: location_t): $Loc.location_t
} val fs = list_cons (!the_filename, !the_filenamelst)
val isexi = loop1 (fs, f0) where {
fun loop1 (fs: filenamelst, f0: filename): bool =
case+ fs of
| list_cons (f, fs) => if f = f0 then true else loop1 (fs, f0)
| list_nil () => false
} val () = if isexi then let
val () = $Loc. prerr_location loc0
val () = prerr (": error(0)")
val () = prerr (": loading or including the file [");
val () = prerr_filename (f0)
val () = prerr ("] generates a looping trace that is given as follows:\n")
val () = loop2 (fs, f0) where {
fun loop2 (fs: filenamelst, f0: filename): void =
case+ fs of
| list_cons (f, fs) => let
val () = prerr_filename f in if (f <> f0) then loop2 (fs, f0)
end | list_nil () => ()
} val () = prerr_newline ()
in
exit (1) end in
!the_filenamelst := fs; !the_filename := f0;
end
end
implement filename_full f = f.filename_full
implement filename_full_sym f = f.filename_full_sym
implement filename_make_absolute (fullname) = let
val fullname_id = fullname
val fullname_sym = $Sym.symbol_make_string fullname
in '{
filename_full= fullname
, filename_full_sym= fullname_sym
} end
implement
filenameopt_make_relative (basename) = let
val basename = string1_of_string basename
fun aux_try (paths: pathlst, basename: String): Stropt =
case+ paths of
| list_cons (path, paths) => let
val fullname = filename_append (path, basename)
val fullname = string1_of_string fullname
in
case+ 0 of
| _ when filename_is_exist (fullname) => stropt_some fullname
| _ => aux_try (paths, basename)
end
| list_nil () => stropt_none
fun aux_relative (basename: String): Stropt = let
val fullnameopt = aux_try (the_prepathlst_get (), basename)
in
case+ 0 of
| _ when stropt_is_some fullnameopt => fullnameopt
| _ when filename_is_exist basename => let
val cwd = getcwd0 ()
val fullname = filename_append (cwd, basename)
val fullname = string1_of_string fullname
in
stropt_some fullname
end
| _ => aux_try (the_pathlst_get (), basename)
end
val fullnameopt = (case+ 0 of
| _ when filename_is_relative basename => aux_relative basename
| _ => begin
if filename_is_exist basename then stropt_some basename else stropt_none
end ) : Stropt in
if stropt_is_some fullnameopt then let
val fullname = stropt_unsome fullnameopt
val fullname = path_normalize fullname
in
Some_vt (filename_make_absolute fullname)
end else begin
None_vt ()
end end
implement
atsopt_filename_prerr () =
prerr_filename (the_filename_get ())
implement
atsopt_filename_initialize () = begin
the_pathlst_reset (); the_filename_reset (); the_filenamelst_reset ()
end
%{$
//
ats_void_type
atsopt_filename_fprint_filename_base
(ats_ptr_type out, ats_ptr_type fil) {
char dirsep, *name, *basename ;
dirsep = atsopt_filename_theDirsep_get () ;
name = (char*)atsopt_filename_full (fil) ;
basename = strrchr (name, dirsep) ;
if (basename) {
++basename ; fputs (basename, (FILE*)out) ;
} else {
fputs (name, (FILE*)out) ;
} /* end of [if] */
return ;
} /* end of [atsopt_filename_fprint_filename_base] */
//
%}