## Author: Matthias Blume (blume@kurims.kyoto-u.ac.jp)
# Compiled by:
#
src/app/makelib/paths/srcpath.sublib# Abstract file IDs.
# - IDs for files regardless whether they exist or not.
# - For existing files equivalent to winix__premicrothread::file::file_id.
#
### "Real Programmers don't comment their code.
### It was hard to write; it should be hard to read."
api File_Id {
Id;
Key = Id;
compare: (Id, Id) -> Order;
file_id: String -> Id;
canonical: String -> String;
};
package file_id: File_Id { # File_Id is from
src/app/makelib/paths/fileid.pkg #
package f = winix__premicrothread::file; # winix__premicrothread is from
src/lib/std/winix--premicrothread.pkg package p = winix__premicrothread::path;
Id
= PRESENT f::File_Id
| ABSENT String;
Key = Id;
fun compare (PRESENT fid, PRESENT fid') => f::compare (fid, fid');
compare (ABSENT _, PRESENT _ ) => LESS;
compare (PRESENT _, ABSENT _ ) => GREATER;
compare (ABSENT s, ABSENT s' ) => string::compare (s, s');
end;
fun file_id f
=
{ # To maximize our chances of recognizing
# equivalent path names to non-existing files,
# we use f::full_path to expand the largest
# possible prefix of the path.
fun expand_path f
=
{ fun loop { dir, file }
=
p::cat (f::full_path dir, file)
except
_
=
{ my { dir => dir', file => file' }
=
p::split_path_into_dir_and_file dir;
loop {
dir => dir',
file => p::cat (file', file)
};
};
# An initial call to split_path_into_dir_and_file
# is ok because we already know
# that the complete path does not
# refer to an existing file:
loop (p::split_path_into_dir_and_file f);
};
PRESENT (f::file_id f)
except
_ = ABSENT (expand_path f);
};
fun canonical ""
=>
"";
canonical f
=>
if (f::access (f, [])
except
_ = FALSE
)
f' = p::make_canonical f;
if (f::compare (f::file_id f, f::file_id f') == EQUAL)
f';
else f; fi;
else
my { dir, file }
=
p::split_path_into_dir_and_file f;
p::make_path_from_dir_and_file { dir => canonical dir, file };
fi;
end;
};