Python's os.path.abspath
or Path.absolute
are great: you give them a path, which might not exist, and you get a path you
can use regardless of the current directory. os.path.abspath
will also
normalize it, while Path
will not by default because with Path
s a normal
form is less needed.
This is great to normalize input, regardless of if it's an existing file you're needing to open, or a new file you're needing to create.
In C++17, there is a filesystem library with methods with enticingly similar names, but which are almost, but not quite, totally unlike Python's abspath.
Because in my C++ code I need to normalize input, regardless of if it's an
existing file I'm needing to open or a new file I'm needing to create, here's
an apparently working Python-like abspath
for C++ implemented on top of the
std::filesystem
library:
std::filesystem::path abspath(const std::filesystem::path& path)
{
// weakly_canonical is defined as "the result of calling canonical() with a
// path argument composed of the leading elements of p that exist (as
// determined by status(p) or status(p, ec)), if any, followed by the
// elements of p that do not exist."
//
// This means that if no lead components of the path exist then the
// resulting path is not made absolute, and we need to work around that.
if (!path.is_absolute())
return abspath(std::filesystem::current_path() / path);
// This is further and needlessly complicated because we need to work
// around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118733
unsigned retry = 0;
while (true)
{
std::error_code code;
auto result = std::filesystem::weakly_canonical(path, code);
if (!code)
{
// fprintf(stderr, "%s: ok in %u tries\n", path.c_str(), retry+1);
return result;
}
if (code == std::errc::no_such_file_or_directory)
{
++retry;
if (retry > 50)
throw std::system_error(code);
}
else
throw std::system_error(code);
}
// Alternative implementation that however may not work on all platforms
// since, formally, "[std::filesystem::absolute] Implementations are
// encouraged to not consider p not existing to be an error", but they do
// not mandate it, and if they did, they might still be affected by the
// undefined behaviour outlined in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118733
//
// return std::filesystem::absolute(path).lexically_normal();
}
I added it to my wobble code repository, which is the thin repository of components I use to ease my C++ systems programming.