## Author: Matthias Blume (blume@cs.princeton.edu)
# Compiled by:
#
src/app/makelib/stuff/makelib-stuff.sublib# Opening files for output while automagically creating any
# necessary directories.
stipulate
package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkg package p = winix__premicrothread::path; # winix__premicrothread is from
src/lib/std/winix--premicrothread.pkg package f = winix__premicrothread::file;
herein
package autodir
:
api {
open_binary_output: String -> data_file__premicrothread::Output_Stream;
open_text_output: String -> fil::Output_Stream;
make_all_directories_on_path: String -> Void;
}
{
fun file_exists n
=
f::access (n, [])
except
_ = FALSE;
fun open_either fileopener p
=
{ fun make_directory d
=
f::make_directory d
except
exn = if (not (file_exists d))
#
raise exception exn;
fi;
fun generic' (maker, pmaker, p)
=
maker p
except
exn
=
{ dir = p::dir p;
# If the parent dir exists, then we must consider
# these cases:
# - non-parallel: we should signal an error
# - parallel: somebody else may have made this dir
# in the meantime, so we should try again
# Both cases can be handled by simply calling maker
# again. (It will fail in the non-parallel case, but
# that's actually what we want.)
if (dir == "" or file_exists dir)
maker p;
else
pmaker dir;
maker p;
fi;
};
fun makedirs dir
=
generic' (make_directory, makedirs, dir);
fun advertisemakedirs dir
=
{ fil::say {. cat ["\n autodir.pkg: Creating directory ", dir, "\n\n"]; };
#
makedirs dir;
};
generic' (fileopener, advertisemakedirs, p);
};
# In the open-for-output case we first
# get rid of the file if it
# already existed...
fun open fileopener
=
open_either (\\ n = { if (file_exists n)
#
f::remove_file n
except
_ = ();
fi;
fileopener n;
}
);
open_text_output = open fil::open_for_write;
open_binary_output = open data_file__premicrothread::open_for_write;
# make_all_directories_on_path is supposed to make all directories
# leading up to a given file. The file itself is supposed to be
# left alone if it already existed. The trick here is to (ab)use
# our open function with a "maker" parameter set to "data_file__premicrothread::open_for_read".
# This is pretty hack-ish, but it allows us to reuse the existing logic.
#
stipulate
exception NONEXISTENT_FILE;
#
fun binary_open_for_input f
=
data_file__premicrothread::open_for_read f
except _
=
raise exception NONEXISTENT_FILE;
herein
fun make_all_directories_on_path f
=
data_file__premicrothread::close_input (open_either binary_open_for_input f)
except
NONEXISTENT_FILE
=
();
end;
};
end;