// This source code is released into the public domain. module; #include #include #include #include #include export module nihil.posix:open_in_path; import nihil.error; import :fd; import :getenv; import :open; namespace nihil { // Find an executable in $PATH and open it with O_EXEC. If $PATH is not set, uses _PATH_DEFPATH. // If the file can't be found or opened, returns std::nullopt. export [[nodiscard]] auto open_in_path(std::filesystem::path const &file) -> std::optional { using namespace std::literals; auto try_open = [](std::filesystem::path const &file) -> std::optional { auto ret = open(file, open_exec); if (ret) return {std::move(*ret)}; return {}; }; // Absolute pathname skips the search. if (file.is_absolute()) return try_open(file); auto path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT for (auto &&dir : path | std::views::split(':')) { // An empty $PATH element means cwd. auto sdir = dir.empty() ? std::filesystem::path(".") : std::filesystem::path(std::string_view(dir)); if (auto ret = try_open(sdir / file); ret) return ret; } return {}; } } // namespace nihil