aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format6
-rw-r--r--.gitignore3
-rw-r--r--nihil.cli/command_tree.cc1
-rw-r--r--nihil.core/CMakeLists.txt1
-rw-r--r--nihil.core/nihil.hh26
-rw-r--r--nihil.posix/CMakeLists.txt50
-rw-r--r--nihil.posix/argv.cc (renamed from nihil.posix/posix.argv.cc)0
-rw-r--r--nihil.posix/argv.ccm (renamed from nihil.posix/posix.argv.ccm)0
-rw-r--r--nihil.posix/ensure_dir.cc (renamed from nihil.posix/posix.ensure_dir.cc)0
-rw-r--r--nihil.posix/ensure_dir.ccm (renamed from nihil.posix/posix.ensure_dir.ccm)0
-rw-r--r--nihil.posix/exec.cc (renamed from nihil.posix/posix.exec.cc)0
-rw-r--r--nihil.posix/exec.ccm (renamed from nihil.posix/posix.exec.ccm)0
-rw-r--r--nihil.posix/executor.ccm27
-rw-r--r--nihil.posix/execv.cc43
-rw-r--r--nihil.posix/execv.ccm47
-rw-r--r--nihil.posix/fd.cc (renamed from nihil.posix/posix.fd.cc)0
-rw-r--r--nihil.posix/fd.ccm (renamed from nihil.posix/posix.fd.ccm)0
-rw-r--r--nihil.posix/fexecv.ccm53
-rw-r--r--nihil.posix/find_in_path.cc52
-rw-r--r--nihil.posix/find_in_path.ccm24
-rw-r--r--nihil.posix/getenv.cc (renamed from nihil.posix/posix.getenv.cc)13
-rw-r--r--nihil.posix/getenv.ccm (renamed from nihil.posix/posix.getenv.ccm)0
-rw-r--r--nihil.posix/open.cc (renamed from nihil.posix/posix.open.cc)0
-rw-r--r--nihil.posix/open.ccm (renamed from nihil.posix/posix.open.ccm)0
-rw-r--r--nihil.posix/open_in_path.cc (renamed from nihil.posix/posix.find_in_path.cc)3
-rw-r--r--nihil.posix/open_in_path.ccm23
-rw-r--r--nihil.posix/posix.ccm18
-rw-r--r--nihil.posix/process.cc (renamed from nihil.posix/posix.process.cc)0
-rw-r--r--nihil.posix/process.ccm (renamed from nihil.posix/posix.process.ccm)0
-rw-r--r--nihil.posix/read_file.ccm (renamed from nihil.posix/posix.read_file.ccm)1
-rw-r--r--nihil.posix/rename.cc (renamed from nihil.posix/posix.rename.cc)0
-rw-r--r--nihil.posix/rename.ccm (renamed from nihil.posix/posix.rename.ccm)0
-rw-r--r--nihil.posix/spawn.ccm (renamed from nihil.posix/posix.spawn.ccm)0
-rw-r--r--nihil.posix/tempfile.cc (renamed from nihil.posix/posix.tempfile.cc)0
-rw-r--r--nihil.posix/tempfile.ccm (renamed from nihil.posix/posix.tempfile.ccm)0
-rw-r--r--nihil.posix/write_file.ccm (renamed from nihil.posix/posix.write_file.ccm)0
36 files changed, 352 insertions, 39 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..c2dc3e0
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,6 @@
+TabWidth: 8
+IndentWidth: 8
+PPIndentWidth: -1
+UseTab: AlignWithSpaces
+IndentPPDirectives: AfterHash
+ColumnLimit: 100 \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ad0c823..a8dc4b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-/build
+/build*
/dist
*.sw?
+/.idea
diff --git a/nihil.cli/command_tree.cc b/nihil.cli/command_tree.cc
index 7cea8da..2d14669 100644
--- a/nihil.cli/command_tree.cc
+++ b/nihil.cli/command_tree.cc
@@ -5,6 +5,7 @@
module;
#include <iostream>
+#include <memory>
#include <print>
#include <ranges>
#include <string>
diff --git a/nihil.core/CMakeLists.txt b/nihil.core/CMakeLists.txt
index 4564640..2a7b3e2 100644
--- a/nihil.core/CMakeLists.txt
+++ b/nihil.core/CMakeLists.txt
@@ -1,6 +1,7 @@
# This source code is released into the public domain.
add_library(nihil.core STATIC)
+target_include_directories(nihil.core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_sources(nihil.core
PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
nihil.core.ccm
diff --git a/nihil.core/nihil.hh b/nihil.core/nihil.hh
new file mode 100644
index 0000000..cd7e789
--- /dev/null
+++ b/nihil.core/nihil.hh
@@ -0,0 +1,26 @@
+/*
+* This source code is released into the public domain.
+ */
+
+#ifndef NIHIL_HH_INCLUDED
+#define NIHIL_HH_INCLUDED
+
+#if __has_include(<sys/param.h>)
+# include <sys/param.h>
+#endif
+
+#if defined(__FreeBSD_version)
+
+/* fexecve() added in FreeBSD 8.0 */
+#if (__FreeBSD_version >= 800000)
+# define NIHIL_HAVE_FEXECVE
+#endif
+
+/* getenv_r() added in FreeBSD 15.0 */
+#if (__FreeBSD_version >= 1500000)
+# define NIHIL_HAVE_GETENV_R
+#endif
+
+#endif // defined(__FreeBSD_version)
+
+#endif // !NIHIL_HH_INCLUDED
diff --git a/nihil.posix/CMakeLists.txt b/nihil.posix/CMakeLists.txt
index 6f410ce..62f6aaf 100644
--- a/nihil.posix/CMakeLists.txt
+++ b/nihil.posix/CMakeLists.txt
@@ -2,36 +2,40 @@
add_library(nihil.posix STATIC)
target_link_libraries(nihil.posix PRIVATE
- nihil.error nihil.flagset nihil.guard nihil.monad)
+ nihil.core nihil.error nihil.flagset nihil.guard nihil.monad)
target_sources(nihil.posix
PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
posix.ccm
- posix.argv.ccm
- posix.ensure_dir.ccm
- posix.exec.ccm
- posix.fd.ccm
- posix.getenv.ccm
- posix.open.ccm
- posix.process.ccm
- posix.read_file.ccm
- posix.rename.ccm
- posix.spawn.ccm
- posix.tempfile.ccm
- posix.write_file.ccm
+ argv.ccm
+ ensure_dir.ccm
+ exec.ccm
+ execv.ccm
+ executor.ccm
+ fd.ccm
+ find_in_path.ccm
+ getenv.ccm
+ open.ccm
+ process.ccm
+ read_file.ccm
+ rename.ccm
+ spawn.ccm
+ tempfile.ccm
+ write_file.ccm
PRIVATE
- posix.argv.cc
- posix.ensure_dir.cc
- posix.exec.cc
- posix.getenv.cc
- posix.fd.cc
- posix.find_in_path.cc
- posix.open.cc
- posix.process.cc
- posix.rename.cc
- posix.tempfile.cc
+ argv.cc
+ ensure_dir.cc
+ exec.cc
+ execv.cc
+ getenv.cc
+ fd.cc
+ find_in_path.cc
+ open.cc
+ process.cc
+ rename.cc
+ tempfile.cc
)
if(NIHIL_TESTS)
diff --git a/nihil.posix/posix.argv.cc b/nihil.posix/argv.cc
index e6b1389..e6b1389 100644
--- a/nihil.posix/posix.argv.cc
+++ b/nihil.posix/argv.cc
diff --git a/nihil.posix/posix.argv.ccm b/nihil.posix/argv.ccm
index 6f60f4b..6f60f4b 100644
--- a/nihil.posix/posix.argv.ccm
+++ b/nihil.posix/argv.ccm
diff --git a/nihil.posix/posix.ensure_dir.cc b/nihil.posix/ensure_dir.cc
index 88e8898..88e8898 100644
--- a/nihil.posix/posix.ensure_dir.cc
+++ b/nihil.posix/ensure_dir.cc
diff --git a/nihil.posix/posix.ensure_dir.ccm b/nihil.posix/ensure_dir.ccm
index fa92a90..fa92a90 100644
--- a/nihil.posix/posix.ensure_dir.ccm
+++ b/nihil.posix/ensure_dir.ccm
diff --git a/nihil.posix/posix.exec.cc b/nihil.posix/exec.cc
index 5bdcbf7..5bdcbf7 100644
--- a/nihil.posix/posix.exec.cc
+++ b/nihil.posix/exec.cc
diff --git a/nihil.posix/posix.exec.ccm b/nihil.posix/exec.ccm
index 6098318..6098318 100644
--- a/nihil.posix/posix.exec.ccm
+++ b/nihil.posix/exec.ccm
diff --git a/nihil.posix/executor.ccm b/nihil.posix/executor.ccm
new file mode 100644
index 0000000..f348dc8
--- /dev/null
+++ b/nihil.posix/executor.ccm
@@ -0,0 +1,27 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <concepts>
+#include <type_traits>
+
+export module nihil.posix:executor;
+
+namespace nihil {
+
+/*
+ * A concept to mark spawn executors.
+ */
+
+export struct exec_tag{};
+
+export template<typename T>
+concept executor =
+ requires (T e) {
+ std::same_as<exec_tag, typename std::remove_cvref_t<T>::tag>;
+ { e.exec() };
+ };
+
+} // namespace nihil
diff --git a/nihil.posix/execv.cc b/nihil.posix/execv.cc
new file mode 100644
index 0000000..63f9698
--- /dev/null
+++ b/nihil.posix/execv.cc
@@ -0,0 +1,43 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <coroutine>
+#include <expected>
+#include <format>
+#include <string>
+#include <utility>
+
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+extern char **environ;
+
+module nihil.posix;
+
+import nihil.error;
+import nihil.monad;
+
+namespace nihil {
+
+execv::execv(std::filesystem::path path, argv &&args) noexcept
+ : m_path(std::move(path))
+ , m_args(std::move(args))
+{
+}
+
+auto execv::exec(this execv &self) -> std::expected<void, error>
+{
+ ::execve(self.m_path.string().c_str(), self.m_args.data(), environ);
+ return std::unexpected(error("execve failed", error(std::errc(errno))));
+}
+
+execv::execv(execv &&) noexcept = default;
+execv::execv(execv const &) = default;
+auto execv::operator=(this execv &, execv &&) -> execv & = default;
+auto execv::operator=(this execv &, execv const &) -> execv & = default;
+
+} // namespace nihil
diff --git a/nihil.posix/execv.ccm b/nihil.posix/execv.ccm
new file mode 100644
index 0000000..ca036a1
--- /dev/null
+++ b/nihil.posix/execv.ccm
@@ -0,0 +1,47 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <expected>
+#include <filesystem>
+#include <string>
+
+export module nihil.posix:execv;
+
+import nihil.error;
+import :argv;
+import :executor;
+
+namespace nihil {
+
+/*
+ * execv: use a filename and an argument vector to call ::execve().
+ * This is the lowest-level executor which all others are implemented
+ * in terms of, if fexecve is not available.
+ *
+ * TODO: Should have a way to pass the environment (envp).
+ */
+export struct execv final
+{
+ using tag = exec_tag;
+
+ execv(std::filesystem::path, argv &&) noexcept;
+
+ [[nodiscard]] auto exec(this execv &) -> std::expected<void, error>;
+
+ // Movable
+ execv(execv &&) noexcept;
+ auto operator=(this execv &, execv &&) noexcept -> execv &;
+
+ // Copyable.
+ execv(execv const &);
+ auto operator=(this execv &, execv const &) -> execv &;
+
+private:
+ std::filesystem::path m_path;
+ argv m_args;
+};
+
+} // namespace nihil
diff --git a/nihil.posix/posix.fd.cc b/nihil.posix/fd.cc
index 6d5e54f..6d5e54f 100644
--- a/nihil.posix/posix.fd.cc
+++ b/nihil.posix/fd.cc
diff --git a/nihil.posix/posix.fd.ccm b/nihil.posix/fd.ccm
index b937f46..b937f46 100644
--- a/nihil.posix/posix.fd.ccm
+++ b/nihil.posix/fd.ccm
diff --git a/nihil.posix/fexecv.ccm b/nihil.posix/fexecv.ccm
new file mode 100644
index 0000000..5ad6c62
--- /dev/null
+++ b/nihil.posix/fexecv.ccm
@@ -0,0 +1,53 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <expected>
+#include <string>
+
+#include "nihil.hh"
+
+#ifdef NIHIL_HAVE_FEXECVE
+
+export module nihil.posix:fexecv;
+
+import nihil.error;
+import :argv;
+import :executor;
+import :fd;
+
+namespace nihil {
+
+/*
+ * fexecv: use a file descriptor and an argument vector to call ::fexecve().
+ * This is the lowest-level executor which all others are implemented
+ * in terms of (if it's available).
+ *
+ * TODO: Should have a way to pass the environment (envp).
+ */
+export struct fexecv final {
+ using tag = exec_tag;
+
+ fexecv(fd &&execfd, argv &&args) noexcept;
+
+ [[nodiscard]] auto exec(this fexecv &self)
+ -> std::expected<void, error>;
+
+ // Movable
+ fexecv(fexecv &&) noexcept;
+ auto operator=(this fexecv &, fexecv &&) noexcept -> fexecv&;
+
+ // Not copyable (because we hold the open fd object)
+ fexecv(fexecv const &) = delete;
+ auto operator=(this fexecv &, fexecv const &) -> fexecv& = delete;
+
+private:
+ fd m_execfd;
+ argv m_args;
+};
+
+} // namespace nihil
+
+#endif // NIHIL_HAVE_FEXECVE \ No newline at end of file
diff --git a/nihil.posix/find_in_path.cc b/nihil.posix/find_in_path.cc
new file mode 100644
index 0000000..7b03faa
--- /dev/null
+++ b/nihil.posix/find_in_path.cc
@@ -0,0 +1,52 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <filesystem>
+#include <optional>
+#include <ranges>
+#include <string>
+
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+
+module nihil.posix;
+
+namespace nihil {
+
+auto find_in_path(std::filesystem::path const &file) -> std::optional<std::filesystem::path>
+{
+ using namespace std::literals;
+
+ auto try_return = [](std::filesystem::path file)
+ -> std::optional<std::filesystem::path>
+ {
+ auto ret = ::access(file.string().c_str(), X_OK);
+ if (ret == 0)
+ return {std::move(file)};
+ return {};
+ };
+
+ // Absolute pathname skips the search.
+ if (file.is_absolute())
+ return try_return(file);
+
+ auto path = getenv("PATH").value_or(_PATH_DEFPATH);
+
+ 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_return(sdir / file); ret)
+ return ret;
+ }
+
+ return {};
+}
+
+} // namespace nihil
diff --git a/nihil.posix/find_in_path.ccm b/nihil.posix/find_in_path.ccm
new file mode 100644
index 0000000..4988a12
--- /dev/null
+++ b/nihil.posix/find_in_path.ccm
@@ -0,0 +1,24 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <filesystem>
+#include <optional>
+
+export module nihil.posix:find_in_path;
+
+import nihil.error;
+import :fd;
+
+namespace nihil {
+
+/*
+ * Find an executable in $PATH and return the full path. If $PATH is not set, uses _PATH_DEFPATH.
+ * If the file can't be found or opened, returns std::nullopt.
+ */
+export [[nodiscard]] auto find_in_path(std::filesystem::path const &file)
+ -> std::optional<std::filesystem::path>;
+
+} // namespace nihil
diff --git a/nihil.posix/posix.getenv.cc b/nihil.posix/getenv.cc
index 36df950..ad93305 100644
--- a/nihil.posix/posix.getenv.cc
+++ b/nihil.posix/getenv.cc
@@ -1,4 +1,3 @@
-
/*
* This source code is released into the public domain.
*/
@@ -13,6 +12,8 @@ module;
#include <unistd.h>
+#include "nihil.hh"
+
module nihil.posix;
import nihil.error;
@@ -21,10 +22,12 @@ namespace nihil {
auto getenv(std::string_view varname) -> std::expected<std::string, error>
{
+ auto cvarname = std::string(varname);
+
+#ifdef NIHIL_HAVE_GETENV_R
// Start with a buffer of this size, and double it every iteration.
constexpr auto bufinc = std::size_t{1024};
- auto cvarname = std::string(varname);
auto buf = std::vector<char>(bufinc);
for (;;) {
auto const ret = ::getenv_r(cvarname.c_str(),
@@ -40,6 +43,12 @@ auto getenv(std::string_view varname) -> std::expected<std::string, error>
return std::unexpected(error(std::errc(errno)));
}
+#else // NIHIL_HAVE_GETENV_R
+ auto *v = ::getenv(cvarname.c_str());
+ if (v == nullptr)
+ return std::unexpected(error(std::errc(errno)));
+ return {std::string(v)};
+#endif // NIHIL_HAVE_GETENV_R
}
} // namespace nihil
diff --git a/nihil.posix/posix.getenv.ccm b/nihil.posix/getenv.ccm
index 465f7e7..465f7e7 100644
--- a/nihil.posix/posix.getenv.ccm
+++ b/nihil.posix/getenv.ccm
diff --git a/nihil.posix/posix.open.cc b/nihil.posix/open.cc
index 9ef6538..9ef6538 100644
--- a/nihil.posix/posix.open.cc
+++ b/nihil.posix/open.cc
diff --git a/nihil.posix/posix.open.ccm b/nihil.posix/open.ccm
index eaedacd..eaedacd 100644
--- a/nihil.posix/posix.open.ccm
+++ b/nihil.posix/open.ccm
diff --git a/nihil.posix/posix.find_in_path.cc b/nihil.posix/open_in_path.cc
index 6be963c..30021ca 100644
--- a/nihil.posix/posix.find_in_path.cc
+++ b/nihil.posix/open_in_path.cc
@@ -16,8 +16,7 @@ module nihil.posix;
namespace nihil {
-auto find_in_path(std::filesystem::path const &file)
- -> std::optional<fd>
+auto open_in_path(std::filesystem::path const &file) -> std::optional<fd>
{
using namespace std::literals;
diff --git a/nihil.posix/open_in_path.ccm b/nihil.posix/open_in_path.ccm
new file mode 100644
index 0000000..1fae56b
--- /dev/null
+++ b/nihil.posix/open_in_path.ccm
@@ -0,0 +1,23 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <filesystem>
+#include <optional>
+
+export module nihil.posix:find_in_path;
+
+import nihil.error;
+import :fd;
+
+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<fd>;
+
+} // namespace nihil
diff --git a/nihil.posix/posix.ccm b/nihil.posix/posix.ccm
index e63ad6b..ea13f81 100644
--- a/nihil.posix/posix.ccm
+++ b/nihil.posix/posix.ccm
@@ -9,6 +9,8 @@ module;
#include <optional>
#include <string>
+#include "nihil.hh"
+
export module nihil.posix;
import nihil.error;
@@ -16,7 +18,9 @@ import nihil.error;
export import :argv;
export import :ensure_dir;
export import :exec;
+export import :execv;
export import :fd;
+export import :find_in_path;
export import :getenv;
export import :open;
export import :process;
@@ -26,14 +30,6 @@ export import :spawn;
export import :tempfile;
export import :write_file;
-export namespace nihil {
-
-/*
- * Find an executable in $PATH, open it with O_EXEC and return the fd.
- * If $PATH is not set, uses _PATH_DEFPATH. If the file can't be found
- * or opened, returns std::nullopt.
- */
-[[nodiscard]] auto find_in_path(std::filesystem::path const &file)
- -> std::optional<fd>;
-
-} // namespace nihil
+#ifdef NIHIL_HAVE_FEXECVE
+export import :fexecv;
+#endif
diff --git a/nihil.posix/posix.process.cc b/nihil.posix/process.cc
index 70e84b7..70e84b7 100644
--- a/nihil.posix/posix.process.cc
+++ b/nihil.posix/process.cc
diff --git a/nihil.posix/posix.process.ccm b/nihil.posix/process.ccm
index 425deac..425deac 100644
--- a/nihil.posix/posix.process.ccm
+++ b/nihil.posix/process.ccm
diff --git a/nihil.posix/posix.read_file.ccm b/nihil.posix/read_file.ccm
index c950f67..be9e102 100644
--- a/nihil.posix/posix.read_file.ccm
+++ b/nihil.posix/read_file.ccm
@@ -4,6 +4,7 @@
module;
+#include <algorithm>
#include <expected>
#include <filesystem>
#include <iterator>
diff --git a/nihil.posix/posix.rename.cc b/nihil.posix/rename.cc
index 9203d08..9203d08 100644
--- a/nihil.posix/posix.rename.cc
+++ b/nihil.posix/rename.cc
diff --git a/nihil.posix/posix.rename.ccm b/nihil.posix/rename.ccm
index 796ec5b..796ec5b 100644
--- a/nihil.posix/posix.rename.ccm
+++ b/nihil.posix/rename.ccm
diff --git a/nihil.posix/posix.spawn.ccm b/nihil.posix/spawn.ccm
index 4cce334..4cce334 100644
--- a/nihil.posix/posix.spawn.ccm
+++ b/nihil.posix/spawn.ccm
diff --git a/nihil.posix/posix.tempfile.cc b/nihil.posix/tempfile.cc
index b1d3dee..b1d3dee 100644
--- a/nihil.posix/posix.tempfile.cc
+++ b/nihil.posix/tempfile.cc
diff --git a/nihil.posix/posix.tempfile.ccm b/nihil.posix/tempfile.ccm
index 82f3be4..82f3be4 100644
--- a/nihil.posix/posix.tempfile.ccm
+++ b/nihil.posix/tempfile.ccm
diff --git a/nihil.posix/posix.write_file.ccm b/nihil.posix/write_file.ccm
index 867e0db..867e0db 100644
--- a/nihil.posix/posix.write_file.ccm
+++ b/nihil.posix/write_file.ccm