aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.posix
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-07-01 17:07:04 +0100
committerLexi Winter <lexi@le-fay.org>2025-07-01 17:07:04 +0100
commit2e2d1bd3b6c7776b77c33b94f30ead89367a71e6 (patch)
tree54d37ffadf8e677938d9b7a28e4e9b71be1e75c1 /nihil.posix
parent36427c0966faa7aecd586b397ed9b845f18172f5 (diff)
downloadnihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.gz
nihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.bz2
add nihil.std
Diffstat (limited to 'nihil.posix')
-rw-r--r--nihil.posix/CMakeLists.txt14
-rw-r--r--nihil.posix/argv.ccm14
-rw-r--r--nihil.posix/argv.test.cc10
-rw-r--r--nihil.posix/ensure_dir.ccm12
-rw-r--r--nihil.posix/execl.ccm33
-rw-r--r--nihil.posix/execl.test.cc5
-rw-r--r--nihil.posix/execlp.ccm10
-rw-r--r--nihil.posix/execlp.test.cc5
-rw-r--r--nihil.posix/execshell.ccm5
-rw-r--r--nihil.posix/execshell.test.cc5
-rw-r--r--nihil.posix/executor.ccm17
-rw-r--r--nihil.posix/execv.ccm43
-rw-r--r--nihil.posix/execv.test.cc5
-rw-r--r--nihil.posix/execvp.ccm23
-rw-r--r--nihil.posix/execvp.test.cc1
-rw-r--r--nihil.posix/fd.ccm31
-rw-r--r--nihil.posix/fd.test.cc10
-rw-r--r--nihil.posix/fexecv.ccm58
-rw-r--r--nihil.posix/fexecvp.ccm37
-rw-r--r--nihil.posix/find_in_path.ccm14
-rw-r--r--nihil.posix/getenv.ccm22
-rw-r--r--nihil.posix/getenv.test.cc12
-rw-r--r--nihil.posix/open.ccm10
-rw-r--r--nihil.posix/open.test.cc1
-rw-r--r--nihil.posix/open_in_path.ccm14
-rw-r--r--nihil.posix/open_in_path.test.cc1
-rw-r--r--nihil.posix/paths.ccm27
-rw-r--r--nihil.posix/posix.ccm4
-rw-r--r--nihil.posix/process.ccm15
-rw-r--r--nihil.posix/read_file.ccm27
-rw-r--r--nihil.posix/rename.ccm16
-rw-r--r--nihil.posix/spawn.ccm128
-rw-r--r--nihil.posix/stat.ccm13
-rw-r--r--nihil.posix/stat.test.cc1
-rw-r--r--nihil.posix/tempfile.ccm22
-rw-r--r--nihil.posix/tempfile.test.cc7
-rw-r--r--nihil.posix/unistd.ccm23
-rw-r--r--nihil.posix/unlink.ccm28
-rw-r--r--nihil.posix/write_file.ccm43
39 files changed, 308 insertions, 458 deletions
diff --git a/nihil.posix/CMakeLists.txt b/nihil.posix/CMakeLists.txt
index 1fcc365..d76ae4d 100644
--- a/nihil.posix/CMakeLists.txt
+++ b/nihil.posix/CMakeLists.txt
@@ -2,7 +2,14 @@
add_library(nihil.posix STATIC)
target_link_libraries(nihil.posix PRIVATE
- nihil.core nihil.error nihil.flagset nihil.guard nihil.monad)
+ nihil.std
+ nihil.core
+ nihil.error
+ nihil.flagset
+ nihil.guard
+ nihil.monad
+ nihil.util
+)
target_sources(nihil.posix
PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
@@ -17,18 +24,19 @@ target_sources(nihil.posix
execvp.ccm
executor.ccm
fd.ccm
- fexecv.ccm
- fexecvp.ccm
find_in_path.ccm
getenv.ccm
open.ccm
open_in_path.ccm
+ paths.ccm
process.ccm
read_file.ccm
rename.ccm
spawn.ccm
stat.ccm
tempfile.ccm
+ unistd.ccm
+ unlink.ccm
write_file.ccm
)
diff --git a/nihil.posix/argv.ccm b/nihil.posix/argv.ccm
index de75770..230ae9a 100644
--- a/nihil.posix/argv.ccm
+++ b/nihil.posix/argv.ccm
@@ -1,16 +1,8 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <memory>
-#include <ranges>
-#include <string>
-#include <vector>
-
+// This source code is released into the public domain.
export module nihil.posix:argv;
+import nihil.std;
+
namespace nihil {
/*
diff --git a/nihil.posix/argv.test.cc b/nihil.posix/argv.test.cc
index 3cc218d..e71c3da 100644
--- a/nihil.posix/argv.test.cc
+++ b/nihil.posix/argv.test.cc
@@ -1,14 +1,8 @@
-/*
- * This source code is released into the public domain
- */
-
-#include <algorithm>
-#include <string>
-#include <type_traits>
-#include <vector>
+// This source code is released into the public domain
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
namespace {
diff --git a/nihil.posix/ensure_dir.ccm b/nihil.posix/ensure_dir.ccm
index 7eecea8..8d3e7a8 100644
--- a/nihil.posix/ensure_dir.ccm
+++ b/nihil.posix/ensure_dir.ccm
@@ -1,15 +1,7 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <expected>
-#include <filesystem>
-#include <system_error>
-
+// This source code is released into the public domain.
export module nihil.posix:ensure_dir;
+import nihil.std;
import nihil.error;
namespace nihil {
diff --git a/nihil.posix/execl.ccm b/nihil.posix/execl.ccm
index f3cbf9a..99b9169 100644
--- a/nihil.posix/execl.ccm
+++ b/nihil.posix/execl.ccm
@@ -1,40 +1,25 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <expected>
-#include <string>
-
-#include "nihil.hh"
-
+// This source code is released into the public domain.
export module nihil.posix:execl;
+import nihil.std;
import nihil.error;
import :argv;
import :execv;
-import :fexecv;
+import :fd;
namespace nihil {
-/*
- * execl: equivalent to (f)execv, except the arguments are passed as a
- * variadic pack of string-like objects.
- */
+// execl: equivalent to execv, except the arguments are passed as a
+// variadic pack of string-like objects.
-export [[nodiscard]] auto execl(std::string_view path, auto &&...args) -> execv
+export [[nodiscard]] auto execl(std::filesystem::path path, auto &&...args) -> execv
{
- return execv(path, argv({std::string_view(args)...}));
+ return execv(std::move(path), argv({std::string_view(args)...}));
}
-#ifdef NIHIL_HAVE_FEXECVE
-
-export [[nodiscard]] auto execl(fd &&executable, auto &&...args) -> fexecv
+export [[nodiscard]] auto execl(fd &&executable, auto &&...args) -> execv
{
- return fexecv(std::move(executable), argv({std::string_view(args)...}));
+ return execv(std::move(executable), argv({std::string_view(args)...}));
}
-#endif // NIHIL_HAVE_FEXECVE
-
} // namespace nihil
diff --git a/nihil.posix/execl.test.cc b/nihil.posix/execl.test.cc
index 5aaaa25..51c2bb9 100644
--- a/nihil.posix/execl.test.cc
+++ b/nihil.posix/execl.test.cc
@@ -1,9 +1,8 @@
-/*
- * This source code is released into the public domain.
- */
+// This source code is released into the public domain.
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
namespace {
diff --git a/nihil.posix/execlp.ccm b/nihil.posix/execlp.ccm
index ab3737c..12f2c24 100644
--- a/nihil.posix/execlp.ccm
+++ b/nihil.posix/execlp.ccm
@@ -1,12 +1,7 @@
// This source code is released into the public domain.
-module;
-
-#include <expected>
-#include <format>
-#include <string>
-
export module nihil.posix:execlp;
+import nihil.std;
import nihil.error;
import :argv;
import :execvp;
@@ -15,8 +10,9 @@ namespace nihil {
// execlp: equivalent to execvp, except the arguments are passed as a
// variadic pack of string-like objects.
+
export [[nodiscard]] auto
-execlp(std::string_view file, auto &&...args) -> std::expected<execv, error>
+execlp(std::filesystem::path const &file, auto &&...args) -> std::expected<execv, error>
{
return execvp(file, argv({std::string_view(args)...}));
}
diff --git a/nihil.posix/execlp.test.cc b/nihil.posix/execlp.test.cc
index aa32253..6fdccea 100644
--- a/nihil.posix/execlp.test.cc
+++ b/nihil.posix/execlp.test.cc
@@ -1,9 +1,8 @@
-/*
- * This source code is released into the public domain.
- */
+// This source code is released into the public domain.
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
namespace {
diff --git a/nihil.posix/execshell.ccm b/nihil.posix/execshell.ccm
index 1fbfccf..e0263e5 100644
--- a/nihil.posix/execshell.ccm
+++ b/nihil.posix/execshell.ccm
@@ -1,10 +1,7 @@
// This source code is released into the public domain.
-module;
-
-#include <string>
-
export module nihil.posix:execshell;
+import nihil.std;
import nihil.error;
import :execv;
import :execl;
diff --git a/nihil.posix/execshell.test.cc b/nihil.posix/execshell.test.cc
index b64953a..47e3313 100644
--- a/nihil.posix/execshell.test.cc
+++ b/nihil.posix/execshell.test.cc
@@ -1,9 +1,8 @@
-/*
- * This source code is released into the public domain.
- */
+// This source code is released into the public domain.
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
namespace {
diff --git a/nihil.posix/executor.ccm b/nihil.posix/executor.ccm
index f348dc8..d9bde88 100644
--- a/nihil.posix/executor.ccm
+++ b/nihil.posix/executor.ccm
@@ -1,19 +1,12 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <concepts>
-#include <type_traits>
-
+// This source code is released into the public domain.
export module nihil.posix:executor;
+import nihil.std;
+
namespace nihil {
-/*
- * A concept to mark spawn executors.
- */
+// A concept to mark spawn executors, which should contain:
+// using tag = exec_tag;
export struct exec_tag{};
diff --git a/nihil.posix/execv.ccm b/nihil.posix/execv.ccm
index ef9d259..d598d94 100644
--- a/nihil.posix/execv.ccm
+++ b/nihil.posix/execv.ccm
@@ -1,17 +1,17 @@
// This source code is released into the public domain.
module;
-#include <expected>
-#include <filesystem>
-#include <string>
-
-#include <unistd.h>
+#include <unistd.h> // execv()
export module nihil.posix:execv;
+import nihil.std;
import nihil.error;
+import nihil.match;
+import nihil.util;
import :argv;
import :executor;
+import :fd;
namespace nihil {
@@ -20,12 +20,19 @@ export struct execv final
{
using tag = exec_tag;
+ // Construct an execv from a filename.
execv(std::filesystem::path path, argv &&args) noexcept
- : m_path(std::move(path))
+ : m_executable(std::move(path))
, m_args(std::move(args))
{
}
+ // Construct an execv from a file descriptor
+ execv(fd &&executable, argv &&argv) noexcept
+ : m_executable(std::move(executable))
+ , m_args(std::move(argv))
+ {}
+
~execv() = default;
// Movable
@@ -39,12 +46,30 @@ export struct execv final
// Perform the execv(). This only returns on failure.
[[nodiscard]] auto exec(this execv &self) -> std::expected<void, error>
{
- ::execv(self.m_path.string().c_str(), self.m_args.data());
- return std::unexpected(error("execve failed", error(std::errc(errno))));
+ auto guard = save_errno();
+
+ return self.m_executable | match {
+ [&] (std::filesystem::path const &path) {
+ ::execv(path.string().c_str(), self.m_args.data());
+ return std::unexpected(error("execve failed", error(sys_error())));
+ },
+
+ [&] (fd const &file) {
+#if NIHIL_HAVE_FEXECVE == 1
+ ::fexecv(file.get(), self.m_args.data());
+ return std::unexpected(error("execve failed", error(sys_error())));
+#else
+ std::ignore = file;
+ return std::unexpected(error(std::errc::function_not_supported));
+#endif
+ }
+ };
}
private:
- std::filesystem::path m_path;
+ // The thing we will execute.
+ std::variant<std::filesystem::path, fd> m_executable;
+ // Arguments to pass to the thing.
argv m_args;
};
diff --git a/nihil.posix/execv.test.cc b/nihil.posix/execv.test.cc
index aaeead7..8c3ef0c 100644
--- a/nihil.posix/execv.test.cc
+++ b/nihil.posix/execv.test.cc
@@ -1,9 +1,8 @@
-/*
- * This source code is released into the public domain.
- */
+// This source code is released into the public domain.
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
namespace {
diff --git a/nihil.posix/execvp.ccm b/nihil.posix/execvp.ccm
index 270e311..14e548e 100644
--- a/nihil.posix/execvp.ccm
+++ b/nihil.posix/execvp.ccm
@@ -1,29 +1,26 @@
// This source code is released into the public domain.
-module;
-
-#include <coroutine>
-#include <string>
-#include <expected>
-#include <format>
-
export module nihil.posix:execvp;
+import nihil.std;
+import nihil.core;
import nihil.error;
import nihil.monad;
import :argv;
import :execv;
import :find_in_path;
+import :open_in_path;
namespace nihil {
-// execvp: equivalent to execv, except the command is passed as
-// a filename instead of a file descriptor. If the filename is not
-// an absolute path, it will be searched for in $PATH.
+// execvp: equivalent to execv, except the command will be searched for in $PATH.
+
export [[nodiscard]] auto
-execvp(std::string_view file, argv &&argv) -> std::expected<execv, error>
+execvp(std::filesystem::path const &file, argv &&args) -> std::expected<execv, error>
{
- auto filename = co_await find_in_path(file);
- co_return execv(std::move(filename), std::move(argv));
+ if constexpr (features::fexecve)
+ co_return execv(co_await open_in_path(file), std::move(args));
+ else
+ co_return execv(co_await find_in_path(file), std::move(args));
}
} // namespace nihil
diff --git a/nihil.posix/execvp.test.cc b/nihil.posix/execvp.test.cc
index e34823d..5f1b979 100644
--- a/nihil.posix/execvp.test.cc
+++ b/nihil.posix/execvp.test.cc
@@ -2,6 +2,7 @@
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
namespace {
diff --git a/nihil.posix/fd.ccm b/nihil.posix/fd.ccm
index 7faf2f1..8210b6d 100644
--- a/nihil.posix/fd.ccm
+++ b/nihil.posix/fd.ccm
@@ -1,24 +1,23 @@
// This source code is released into the public domain.
module;
-#include <coroutine>
-#include <expected>
-#include <ranges>
-#include <span>
-#include <stdexcept>
-#include <system_error>
-
#include <fcntl.h>
#include <unistd.h>
export module nihil.posix:fd;
+import nihil.std;
import nihil.flagset;
import nihil.error;
import nihil.monad;
namespace nihil {
+// Useful constants
+export inline int constexpr stdin_fileno = STDIN_FILENO;
+export inline int constexpr stdout_fileno = STDOUT_FILENO;
+export inline int constexpr stderr_fileno = STDERR_FILENO;
+
// F_{GET,SET}FL flags
struct fd_flags_tag
{
@@ -96,7 +95,7 @@ export struct fd final
if (ret == 0)
return {};
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
// Return the stored fd.
@@ -124,7 +123,7 @@ export struct fd final
if (ret >= 0)
return ret;
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
// Read data from the fd to the provided buffer. Returns a
@@ -136,7 +135,7 @@ export struct fd final
if (ret >= 0)
return buffer.subspan(0, ret);
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
private:
@@ -152,7 +151,7 @@ export [[nodiscard]] auto dup(fd const &self) -> std::expected<fd, error>
if (newfd != -1)
return fd(newfd);
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
// Create a copy of this fd by calling dup2(). Note that because this results
@@ -170,7 +169,7 @@ export [[nodiscard]] auto dup(fd const &self, int newfd) -> std::expected<fd, er
if (ret != -1)
return fd(newfd);
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
// Create a copy of this fd by calling dup().
@@ -180,7 +179,7 @@ export [[nodiscard]] auto raw_dup(fd const &self) -> std::expected<int, error>
if (newfd != -1)
return newfd;
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
// Create a copy of this fd by calling dup2().
@@ -190,7 +189,7 @@ export [[nodiscard]] auto raw_dup(fd const &self, int newfd) -> std::expected<in
if (ret != -1)
return newfd;
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
}
// Call fcntl() on this fd. Prefer one of the type-safe wrappers to this, if available.
@@ -199,7 +198,7 @@ export [[nodiscard]] auto fcntl(fd const &fd, int op, int arg = 0)
{
auto const ret = ::fcntl(fd.get(), op, arg);
if (ret == -1)
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
return ret;
}
@@ -277,7 +276,7 @@ export [[nodiscard]] auto pipe() -> std::expected<std::pair<fd, fd>, error>
auto fds = std::array<int, 2>{};
if (auto const ret = ::pipe(fds.data()); ret != 0)
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
return {{fd(fds[0]), fd(fds[1])}};
}
diff --git a/nihil.posix/fd.test.cc b/nihil.posix/fd.test.cc
index 870ddde..65b2ad3 100644
--- a/nihil.posix/fd.test.cc
+++ b/nihil.posix/fd.test.cc
@@ -1,15 +1,11 @@
-/*
- * This source code is released into the public domain.
- */
-
-#include <coroutine>
-#include <span>
-#include <stdexcept>
+// This source code is released into the public domain.
#include <fcntl.h>
+#include <unistd.h>
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.error;
import nihil.posix;
diff --git a/nihil.posix/fexecv.ccm b/nihil.posix/fexecv.ccm
deleted file mode 100644
index 4001726..0000000
--- a/nihil.posix/fexecv.ccm
+++ /dev/null
@@ -1,58 +0,0 @@
-// This source code is released into the public domain.
-module;
-
-#include <expected>
-#include <string>
-
-#include "nihil.hh"
-
-export module nihil.posix:fexecv;
-
-import nihil.error;
-import :argv;
-import :executor;
-import :fd;
-
-namespace nihil {
-
-#ifdef NIHIL_HAVE_FEXECVE
-
-/*
- * 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
- : m_execfd(std::move(execfd))
- , m_args(std::move(args))
- {
- }
-
- [[nodiscard]] auto exec(this fexecv &self) -> std::expected<void, error>
- {
- ::fexecve(self.m_execfd.get(), self.m_args.data(), environ);
- return std::unexpected(error("fexecve failed", error(std::errc(errno))));
- }
-
- // Movable
- fexecv(fexecv &&) noexcept = default;
- auto operator=(this fexecv &, fexecv &&) noexcept -> fexecv & = default;
-
- // 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;
-};
-
-#endif // NIHIL_HAVE_FEXECVE
-
-} // namespace nihil
diff --git a/nihil.posix/fexecvp.ccm b/nihil.posix/fexecvp.ccm
deleted file mode 100644
index d61240c..0000000
--- a/nihil.posix/fexecvp.ccm
+++ /dev/null
@@ -1,37 +0,0 @@
-// This source code is released into the public domain.
-module;
-
-#include <expected>
-#include <filesystem>
-#include <format>
-#include <string>
-
-#include "nihil.hh"
-
-export module nihil.posix:fexecvp;
-
-#ifdef NIHIL_HAVE_FEXECVE
-
-import nihil.error;
-import :argv;
-import :execv;
-import :open_in_path;
-
-namespace nihil {
-
-// execvp: equivalent to execv, except the command is passed as
-// a filename instead of a file descriptor. If the filename is not
-// an absolute path, it will be searched for in $PATH.
-export [[nodiscard]] auto
-fexecvp(std::filesystem::path const &file, argv &&argv) -> std::expected<execv, error>
-{
- auto execfd = open_in_path(file);
- if (!execfd)
- return std::unexpected(error(
- std::format("executable not found in path: {}", file)));
- return fexecv(std::move(*execfd), std::move(argv));
-}
-
-} // namespace nihil
-
-#endif // NIHIL_HAVE_FEXECVE
diff --git a/nihil.posix/find_in_path.ccm b/nihil.posix/find_in_path.ccm
index 61df669..dabe358 100644
--- a/nihil.posix/find_in_path.ccm
+++ b/nihil.posix/find_in_path.ccm
@@ -1,19 +1,15 @@
// This source code is released into the public domain.
module;
-#include <expected>
-#include <filesystem>
-#include <optional>
-#include <ranges>
-
-#include <paths.h>
-#include <unistd.h>
+#include <unistd.h> // access()
export module nihil.posix:find_in_path;
+import nihil.std;
import nihil.error;
import :fd;
import :getenv;
+import :paths;
namespace nihil {
@@ -28,7 +24,7 @@ export [[nodiscard]] auto find_in_path(std::filesystem::path const &file, std::s
auto ret = ::access(file.string().c_str(), X_OK);
if (ret == 0)
return {std::move(file)};
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
};
// Absolute pathname skips the search.
@@ -59,7 +55,7 @@ export [[nodiscard]] auto find_in_path(std::filesystem::path const &file, std::s
export [[nodiscard]] auto
find_in_path(std::filesystem::path const &file) -> std::expected<std::filesystem::path, error>
{
- auto const path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT
+ auto const path = getenv("PATH").value_or(std::string(paths::defpath)); // NOLINT
return find_in_path(file, path);
}
diff --git a/nihil.posix/getenv.ccm b/nihil.posix/getenv.ccm
index 5967bf7..ddffeb3 100644
--- a/nihil.posix/getenv.ccm
+++ b/nihil.posix/getenv.ccm
@@ -2,18 +2,15 @@
module;
#include <cerrno>
-#include <expected>
-#include <string>
-#include <system_error>
-#include <vector>
-
-#include <unistd.h>
+#include <stdlib.h> // NOLINT: getenv_r
#include "nihil.hh"
export module nihil.posix:getenv;
+import nihil.std;
import nihil.error;
+import nihil.util;
namespace nihil {
@@ -23,9 +20,10 @@ namespace nihil {
// future calls to setenv().
export [[nodiscard]] auto getenv(std::string_view varname) -> std::expected<std::string, error>
{
+ auto errno_guard = save_errno();
auto cvarname = std::string(varname);
-#ifdef NIHIL_HAVE_GETENV_R
+#if NIHIL_HAVE_GETENV_R == 1
// Start with a buffer of this size, and double it every iteration.
constexpr auto bufinc = std::size_t{1024};
@@ -44,16 +42,14 @@ export [[nodiscard]] auto getenv(std::string_view varname) -> std::expected<std:
return std::unexpected(error(std::errc(errno)));
}
#else // NIHIL_HAVE_GETENV_R
- errno = 0;
- auto *v = ::getenv(cvarname.c_str()); // NOLINT
+ // getenv() may not set errno on failure, so initialise it to a reasonable value.
+ errno = ENOENT;
+ auto const *v = ::getenv(cvarname.c_str()); // NOLINT
if (v != nullptr)
return {std::string(v)};
- if (errno != 0)
- return std::unexpected(error(std::errc(errno)));
-
- return std::unexpected(error(std::errc::no_such_file_or_directory));
+ return error(sys_error());
#endif // NIHIL_HAVE_GETENV_R
}
diff --git a/nihil.posix/getenv.test.cc b/nihil.posix/getenv.test.cc
index 9e10c16..3ba1d94 100644
--- a/nihil.posix/getenv.test.cc
+++ b/nihil.posix/getenv.test.cc
@@ -1,18 +1,14 @@
-/*
- * This source code is released into the public domain.
- */
-
-#include <ranges>
-#include <string>
-#include <system_error>
+// This source code is released into the public domain.
#include <unistd.h>
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.error;
import nihil.posix;
+namespace {
TEST_CASE("getenv: existing value", "[getenv]")
{
auto constexpr *name = "NIHIL_TEST_VAR";
@@ -48,3 +44,5 @@ TEST_CASE("getenv: long value")
REQUIRE(s);
REQUIRE(*s == value);
}
+
+} // anonymous namespace
diff --git a/nihil.posix/open.ccm b/nihil.posix/open.ccm
index 59f80af..f2f5ecd 100644
--- a/nihil.posix/open.ccm
+++ b/nihil.posix/open.ccm
@@ -1,20 +1,20 @@
// This source code is released into the public domain.
module;
-#include <expected>
-#include <filesystem>
-
#include <fcntl.h>
#include <unistd.h>
export module nihil.posix:open;
+import nihil.std;
import nihil.error;
import nihil.flagset;
+import nihil.util;
import :fd;
namespace nihil {
+// Flags which can be passed to open().
struct open_flags_tag
{
};
@@ -70,7 +70,7 @@ export [[nodiscard]] auto open(std::filesystem::path const &filename, open_flags
if (fdno != -1)
return fd(fdno);
- return std::unexpected(error(std::errc(errno)));
+ return error(sys_error());
}
// Like open(), but resolve relative to an open file descriptor, which must refer to a directory.
@@ -81,7 +81,7 @@ export [[nodiscard]] auto openat(fd &where, std::filesystem::path const &filenam
if (fdno != -1)
return fd(fdno);
- return std::unexpected(error(std::errc(errno)));
+ return error(sys_error());
}
} // namespace nihil
diff --git a/nihil.posix/open.test.cc b/nihil.posix/open.test.cc
index bb8bcc9..e49f4c4 100644
--- a/nihil.posix/open.test.cc
+++ b/nihil.posix/open.test.cc
@@ -2,6 +2,7 @@
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.error;
import nihil.posix;
diff --git a/nihil.posix/open_in_path.ccm b/nihil.posix/open_in_path.ccm
index e8c1761..0733c8d 100644
--- a/nihil.posix/open_in_path.ccm
+++ b/nihil.posix/open_in_path.ccm
@@ -1,20 +1,12 @@
// This source code is released into the public domain.
-module;
-
-#include <expected>
-#include <filesystem>
-#include <optional>
-#include <ranges>
-#include <string>
-
-#include <paths.h>
-
export module nihil.posix:open_in_path;
+import nihil.std;
import nihil.error;
import :fd;
import :getenv;
import :open;
+import :paths;
namespace nihil {
@@ -51,7 +43,7 @@ open_in_path(std::filesystem::path const &file, std::string_view path) -> std::e
export [[nodiscard]] auto
open_in_path(std::filesystem::path const &file) -> std::expected<fd, error>
{
- auto const path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT
+ auto const path = getenv("PATH").value_or(std::string(paths::defpath)); // NOLINT
return open_in_path(file, path);
}
diff --git a/nihil.posix/open_in_path.test.cc b/nihil.posix/open_in_path.test.cc
index 13d6b49..ebd1405 100644
--- a/nihil.posix/open_in_path.test.cc
+++ b/nihil.posix/open_in_path.test.cc
@@ -2,6 +2,7 @@
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.error;
import nihil.posix;
diff --git a/nihil.posix/paths.ccm b/nihil.posix/paths.ccm
new file mode 100644
index 0000000..775e566
--- /dev/null
+++ b/nihil.posix/paths.ccm
@@ -0,0 +1,27 @@
+// This source code is released into the public domain.
+module;
+
+#include <paths.h>
+
+export module nihil.posix:paths;
+
+import nihil.std;
+
+namespace nihil::paths {
+
+export inline constexpr auto defpath = std::string_view(_PATH_DEFPATH);
+export inline constexpr auto stdpath = std::string_view(_PATH_STDPATH);
+
+#ifdef _PATH_LOCALBASE
+export inline constexpr auto localbase = std::string_view(_PATH_LOCALBASE);
+#else
+export inline constexpr auto localbase = std::string_view("/usr/local");
+#endif
+
+#ifdef _PATH_SYSPATH
+export inline constexpr auto syspath = std::string_view(_PATH_SYSPATH);
+#else
+export inline constexpr auto syspath = std::string_view("/sbin:/usr/sbin");
+#endif
+
+} // namespace nihil::paths
diff --git a/nihil.posix/posix.ccm b/nihil.posix/posix.ccm
index c49a992..aa21649 100644
--- a/nihil.posix/posix.ccm
+++ b/nihil.posix/posix.ccm
@@ -13,16 +13,16 @@ export import :execshell;
export import :execv;
export import :execvp;
export import :fd;
-export import :fexecv;
-export import :fexecvp;
export import :find_in_path;
export import :getenv;
export import :open;
export import :open_in_path;
+export import :paths;
export import :process;
export import :read_file;
export import :rename;
export import :spawn;
export import :stat;
export import :tempfile;
+export import :unlink;
export import :write_file;
diff --git a/nihil.posix/process.ccm b/nihil.posix/process.ccm
index ee7de15..9fbf34c 100644
--- a/nihil.posix/process.ccm
+++ b/nihil.posix/process.ccm
@@ -1,19 +1,17 @@
// This source code is released into the public domain.
module;
-#include <expected>
-#include <optional>
-#include <system_error>
-#include <utility>
-
#include <sys/wait.h>
export module nihil.posix:process;
+import nihil.std;
import nihil.error;
namespace nihil {
+export struct process;
+
// wait_result: the exit status of a process.
export struct wait_result final
{
@@ -58,7 +56,7 @@ private:
};
// Represents a process we created, which can be waited for.
-export struct process final
+struct process final
{
process() = delete;
@@ -83,7 +81,8 @@ export struct process final
// Movable.
process(process &&other) noexcept
: m_pid(std::exchange(other.m_pid, -1))
- {}
+ {
+ }
auto operator=(this process &self, process &&other) noexcept -> process &
{
@@ -113,7 +112,7 @@ export struct process final
auto status = int{};
auto ret = waitpid(self.m_pid, &status, 0);
if (ret == -1)
- return std::unexpected(error(std::errc(errno)));
+ return error(sys_error());
return wait_result(status);
}
diff --git a/nihil.posix/read_file.ccm b/nihil.posix/read_file.ccm
index 3b4fd5b..61c5085 100644
--- a/nihil.posix/read_file.ccm
+++ b/nihil.posix/read_file.ccm
@@ -1,20 +1,4 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <algorithm>
-#include <expected>
-#include <filesystem>
-#include <iterator>
-#include <ranges>
-#include <span>
-#include <system_error>
-
-#include <fcntl.h>
-#include <unistd.h>
-
+// This source code is released into the public domain.
export module nihil.posix:read_file;
import nihil.error;
@@ -24,12 +8,9 @@ import :open;
namespace nihil {
-/*
- * Read the contents of a file into an output iterator.
- */
+// Read the contents of a file into an output iterator.
export [[nodiscard]] auto
-read_file(std::filesystem::path const &filename,
- std::output_iterator<char> auto &&iter)
+read_file(std::filesystem::path const &filename, std::output_iterator<char> auto &&iter)
-> std::expected<void, error>
{
auto file = co_await open(filename, open_read);
@@ -38,7 +19,7 @@ read_file(std::filesystem::path const &filename,
auto buffer = std::array<char, bufsize>{};
for (;;) {
- auto read_buf = co_await(read(file, buffer));
+ auto read_buf = co_await (read(file, buffer));
if (read_buf.empty())
co_return {};
diff --git a/nihil.posix/rename.ccm b/nihil.posix/rename.ccm
index a1b292e..c46005e 100644
--- a/nihil.posix/rename.ccm
+++ b/nihil.posix/rename.ccm
@@ -1,12 +1,9 @@
// This source code is released into the public domain.
-module;
-
-#include <expected>
-#include <filesystem>
-
export module nihil.posix:rename;
+import nihil.std;
import nihil.error;
+import nihil.util;
namespace nihil {
@@ -15,12 +12,11 @@ export [[nodiscard]] auto
rename(std::filesystem::path const &oldp, std::filesystem::path const &newp)
-> std::expected<void, error>
{
- auto err = std::error_code();
-
- std::filesystem::rename(oldp, newp, err);
+ auto guard = save_errno();
- if (err)
- return std::unexpected(error(err));
+ auto const ret = std::rename(oldp.string().c_str(), newp.string().c_str());
+ if (ret == -1)
+ return std::unexpected(error(sys_error()));
return {};
}
diff --git a/nihil.posix/spawn.ccm b/nihil.posix/spawn.ccm
index a185bb3..1e4102a 100644
--- a/nihil.posix/spawn.ccm
+++ b/nihil.posix/spawn.ccm
@@ -1,52 +1,27 @@
// This source code is released into the public domain.
-module;
-
-/*
- * spawn(): fork and execute a child process.
- */
-
-#include <algorithm>
-#include <cerrno>
-#include <coroutine>
-#include <expected>
-#include <filesystem>
-#include <format>
-#include <iterator>
-#include <print>
-#include <string>
-#include <utility>
-
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-
export module nihil.posix:spawn;
+// spawn(): fork and execute a child process.
+
import nihil.monad;
import :argv;
import :executor;
+import :fd;
import :open;
import :process;
+import :unistd;
namespace nihil {
-// Useful constants
-export inline int constexpr stdin_fileno = STDIN_FILENO;
-export inline int constexpr stdout_fileno = STDOUT_FILENO;
-export inline int constexpr stderr_fileno = STDERR_FILENO;
-
-/*
- * fd_{read,write}_pipe: create a pipe with one end in the child and the other in the parent.
- * The child's side will be dup2()'d to the provided fd number.
- * The parent side fd can be retrieved via parent_fd().
- *
- * fd_read_pipe() puts the reading side in the child, while fd_write_pipe() puts the writing
- * side in the child.
- */
+// fd_{read,write}_pipe: create a pipe with one end in the child and the other in the parent.
+// The child's side will be dup2()'d to the provided fd number.
+// The parent side fd can be retrieved via parent_fd().
+//
+// fd_read_pipe() puts the reading side in the child, while fd_write_pipe() puts the writing
+// side in the child.
-struct fd_pipe_base {
+struct fd_pipe_base
+{
fd_pipe_base(int fdno, fd &&child_fd, fd &&parent_fd)
: m_fdno(fdno)
, m_child_fd(std::move(child_fd))
@@ -58,8 +33,8 @@ struct fd_pipe_base {
{
auto err = raw_dup(self.m_child_fd, self.m_fdno);
if (!err) {
- std::print("dup: {}\n", err.error());
- _exit(1);
+ std::println("dup: {}", err.error());
+ std::quick_exit(1);
}
/*
@@ -81,35 +56,34 @@ struct fd_pipe_base {
}
private:
- int m_fdno;
- fd m_child_fd;
- fd m_parent_fd;
-
+ int m_fdno;
+ fd m_child_fd;
+ fd m_parent_fd;
};
-export struct fd_read_pipe final : fd_pipe_base {
+export struct fd_read_pipe final : fd_pipe_base
+{
fd_read_pipe(int fdno, fd &&read_fd, fd &&write_fd)
: fd_pipe_base(fdno, std::move(read_fd), std::move(write_fd))
{
}
};
-export struct fd_write_pipe final : fd_pipe_base {
+export struct fd_write_pipe final : fd_pipe_base
+{
fd_write_pipe(int fdno, fd &&read_fd, fd &&write_fd)
: fd_pipe_base(fdno, std::move(write_fd), std::move(read_fd))
{
}
};
-export [[nodiscard]] auto
-make_fd_read_pipe(int fdno) -> std::expected<fd_read_pipe, error>
+export [[nodiscard]] auto make_fd_read_pipe(int fdno) -> std::expected<fd_read_pipe, error>
{
auto fds = co_await pipe();
co_return fd_read_pipe(fdno, std::move(fds.first), std::move(fds.second));
}
-export [[nodiscard]] auto
-make_fd_write_pipe(int fdno) -> std::expected<fd_write_pipe, error>
+export [[nodiscard]] auto make_fd_write_pipe(int fdno) -> std::expected<fd_write_pipe, error>
{
auto fds = co_await pipe();
co_return fd_write_pipe(fdno, std::move(fds.first), std::move(fds.second));
@@ -119,7 +93,8 @@ make_fd_write_pipe(int fdno) -> std::expected<fd_write_pipe, error>
* fd_file: open a file and provide it to the child as a file descriptor.
* open_flags and open_mode are as for ::open().
*/
-export struct fd_file final {
+export struct fd_file final
+{
fd_file(int fdno, fd &&file_fd)
: m_fdno(fdno)
, m_file_fd(std::move(file_fd))
@@ -136,20 +111,19 @@ export struct fd_file final {
auto err = raw_dup(self.m_file_fd, self.m_fdno);
if (!err) {
std::print("dup: {}\n", err.error());
- _exit(1);
+ std::quick_exit(1);
}
std::ignore = self.m_file_fd.close();
}
private:
- int m_fdno;
- fd m_file_fd;
+ int m_fdno;
+ fd m_file_fd;
};
export [[nodiscard]] auto
-make_fd_file(int fdno, std::filesystem::path const &file,
- open_flags flags, int mode = 0777)
+make_fd_file(int fdno, std::filesystem::path const &file, open_flags flags, int mode = 0777)
-> std::expected<fd_file, error>
{
auto fd = co_await open(file, flags, mode);
@@ -160,20 +134,17 @@ make_fd_file(int fdno, std::filesystem::path const &file,
* Shorthand for fd_file with /dev/null as the file.
*/
-export [[nodiscard]] inline auto
-stdin_devnull() -> std::expected<fd_file, error>
+export [[nodiscard]] inline auto stdin_devnull() -> std::expected<fd_file, error>
{
return make_fd_file(stdin_fileno, "/dev/null", open_read);
}
-export [[nodiscard]] inline auto
-stdout_devnull() -> std::expected<fd_file, error>
+export [[nodiscard]] inline auto stdout_devnull() -> std::expected<fd_file, error>
{
return make_fd_file(stdout_fileno, "/dev/null", open_write);
}
-export [[nodiscard]] inline auto
-stderr_devnull() -> std::expected<fd_file, error>
+export [[nodiscard]] inline auto stderr_devnull() -> std::expected<fd_file, error>
{
return make_fd_file(stderr_fileno, "/dev/null", open_write);
}
@@ -182,8 +153,9 @@ stderr_devnull() -> std::expected<fd_file, error>
* Capture the output of a pipe in the parent and read it into an
* output iterator.
*/
-export template<std::output_iterator<char> Iterator>
-struct fd_capture final {
+export template <std::output_iterator<char> Iterator>
+struct fd_capture final
+{
fd_capture(fd_write_pipe &&pipe, Iterator it)
: m_pipe(std::move(pipe))
, m_iterator(std::move(it))
@@ -204,7 +176,7 @@ struct fd_capture final {
auto &fd = self.m_pipe.parent_fd();
for (;;) {
auto ret = read(fd, buffer);
- if (!ret || ret->size() == 0)
+ if (!ret || ret->empty())
break;
std::ranges::copy(*ret, self.m_iterator);
@@ -215,21 +187,18 @@ struct fd_capture final {
}
private:
- fd_write_pipe m_pipe;
- Iterator m_iterator;
+ fd_write_pipe m_pipe;
+ Iterator m_iterator;
};
-export [[nodiscard]] auto
-make_capture(int fdno, std::output_iterator<char> auto &&it)
+export [[nodiscard]] auto make_capture(int fdno, std::output_iterator<char> auto &&it)
-> std::expected<fd_capture<decltype(it)>, error>
{
auto pipe = co_await make_fd_write_pipe(fdno);
- co_return fd_capture(std::move(pipe),
- std::forward<decltype(it)>(it));
+ co_return fd_capture(std::move(pipe), std::forward<decltype(it)>(it));
}
-export [[nodiscard]] auto
-make_capture(int fdno, std::string &str)
+export [[nodiscard]] auto make_capture(int fdno, std::string &str)
-> std::expected<fd_capture<decltype(std::back_inserter(str))>, error>
{
auto pipe = co_await make_fd_write_pipe(fdno);
@@ -241,14 +210,9 @@ make_capture(int fdno, std::string &str)
* Throws exec_error() on failure.
*/
export [[nodiscard]] auto
-spawn(executor auto &&executor, auto &&...actions)
- -> std::expected<process, error>
+spawn(executor auto &&executor, auto &&...actions) -> std::expected<process, error>
{
- auto const pid = ::fork();
- if (pid == -1)
- return std::unexpected(error("fork failed",
- error(std::errc(errno))));
-
+ auto const pid = co_await fork();
auto proc = process(pid);
if (pid == 0) {
@@ -257,13 +221,13 @@ spawn(executor auto &&executor, auto &&...actions)
std::ignore = std::move(proc).release();
auto err = executor.exec();
- std::print("{}\n", err.error());
- _exit(1);
+ std::println("{}", err.error());
+ std::quick_exit(1);
}
(actions.run_in_parent(proc), ...);
- return proc;
+ co_return proc;
}
} // namespace nihil
diff --git a/nihil.posix/stat.ccm b/nihil.posix/stat.ccm
index 6a0cabf..ee8113b 100644
--- a/nihil.posix/stat.ccm
+++ b/nihil.posix/stat.ccm
@@ -3,13 +3,12 @@ module;
// Basic wrappers around stat() and fstat().
-#include <expected>
-#include <filesystem>
-
#include <sys/stat.h>
export module nihil.posix:stat;
+import nihil.std;
+import nihil.util;
import :fd;
namespace nihil {
@@ -17,19 +16,23 @@ namespace nihil {
export [[nodiscard]] auto
stat(std::filesystem::path const &path) -> std::expected<struct ::stat, error>
{
+ auto guard = save_errno();
+
struct ::stat sb{};
auto ret = ::stat(path.string().c_str(), &sb);
if (ret == -1)
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
return sb;
}
export [[nodiscard]] auto stat(fd const &fd) -> std::expected<struct ::stat, error>
{
+ auto guard = save_errno();
+
struct ::stat sb{};
auto ret = ::fstat(fd.get(), &sb);
if (ret == -1)
- return std::unexpected(error(std::errc(errno)));
+ return std::unexpected(error(sys_error()));
return sb;
}
diff --git a/nihil.posix/stat.test.cc b/nihil.posix/stat.test.cc
index cf1e29c..535273b 100644
--- a/nihil.posix/stat.test.cc
+++ b/nihil.posix/stat.test.cc
@@ -1,5 +1,6 @@
// This source code is released into the public domain.
+import nihil.std;
import nihil.error;
import nihil.posix;
diff --git a/nihil.posix/tempfile.ccm b/nihil.posix/tempfile.ccm
index e1510e5..121c636 100644
--- a/nihil.posix/tempfile.ccm
+++ b/nihil.posix/tempfile.ccm
@@ -1,22 +1,15 @@
// This source code is released into the public domain.
-module;
-
-// tempfile: create a temporary file.
-
-#include <algorithm>
-#include <cstdint>
-#include <expected>
-#include <filesystem>
-#include <random>
-#include <string>
-
export module nihil.posix:tempfile;
+import nihil.std;
import nihil.error;
import nihil.flagset;
import :fd;
import :getenv;
import :open;
+import :unlink;
+
+// tempfile: create a temporary file.
namespace nihil {
@@ -60,9 +53,7 @@ export struct temporary_file final
throw std::logic_error("release() called on already-released tempfile");
if (!self.m_path.empty()) {
- auto ec = std::error_code(); // ignore errors
- remove(self.path(), ec);
-
+ std::ignore = unlink(self.path());
self.m_path.clear();
}
@@ -141,8 +132,7 @@ tempfile(tempfile_flags flags = tempfile_none) -> std::expected<temporary_file,
}
if (flags & tempfile_unlink) {
- auto ec = std::error_code();
- remove(filename, ec);
+ std::ignore = unlink(filename);
return temporary_file(std::move(*fd));
}
diff --git a/nihil.posix/tempfile.test.cc b/nihil.posix/tempfile.test.cc
index b1c7604..fcaafdc 100644
--- a/nihil.posix/tempfile.test.cc
+++ b/nihil.posix/tempfile.test.cc
@@ -1,11 +1,8 @@
-/*
- * This source code is released into the public domain.
- */
-
-#include <filesystem>
+// This source code is released into the public domain.
#include <catch2/catch_test_macros.hpp>
+import nihil.std;
import nihil.posix;
TEST_CASE("posix.tempfile: create", "[nihil][nihil.posix]")
diff --git a/nihil.posix/unistd.ccm b/nihil.posix/unistd.ccm
new file mode 100644
index 0000000..14c19ee
--- /dev/null
+++ b/nihil.posix/unistd.ccm
@@ -0,0 +1,23 @@
+// This source code is released into the public domain.
+module;
+
+#include <unistd.h>
+
+export module nihil.posix:unistd;
+
+import nihil.std;
+import nihil.error;
+
+// Symbols from unistd.h that might be useful.
+
+namespace nihil {
+
+export [[nodiscard]] auto fork() -> std::expected<::pid_t, error>
+{
+ auto const pid = ::fork();
+ if (pid == -1)
+ return std::unexpected(error(sys_error()));
+ return pid;
+}
+
+};
diff --git a/nihil.posix/unlink.ccm b/nihil.posix/unlink.ccm
new file mode 100644
index 0000000..d6c47cd
--- /dev/null
+++ b/nihil.posix/unlink.ccm
@@ -0,0 +1,28 @@
+// This source code is released into the public domain.
+module;
+
+#include <unistd.h>
+
+export module nihil.posix:unlink;
+
+// unlink: simple wrapper around ::unlink()
+
+import nihil.std;
+import nihil.error;
+import nihil.util;
+
+namespace nihil {
+
+export [[nodiscard]] auto unlink(std::filesystem::path const &path)
+ -> std::expected<void, error>
+{
+ auto guard = save_errno();
+
+ auto const ret = ::unlink(path.string().c_str());
+ if (ret == 0)
+ return {};
+
+ return std::unexpected(error(sys_error()));
+}
+
+} // namespace nihil
diff --git a/nihil.posix/write_file.ccm b/nihil.posix/write_file.ccm
index ce21e6b..4bdd6e2 100644
--- a/nihil.posix/write_file.ccm
+++ b/nihil.posix/write_file.ccm
@@ -1,34 +1,19 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <coroutine>
-#include <expected>
-#include <filesystem>
-#include <ranges>
-#include <system_error>
-#include <vector>
-
-#include <fcntl.h>
-#include <unistd.h>
-
+// This source code is released into the public domain.
export module nihil.posix:write_file;
+import nihil.std;
import nihil.error;
import nihil.guard;
import nihil.monad;
import :fd;
import :open;
import :rename;
+import :unlink;
namespace nihil {
-/*
- * Write the contents of a range to a file. Returns the number of bytes
- * written.
- */
+// Write the contents of a range to a file. Returns the number of bytes
+// written.
export [[nodiscard]]
auto write_file(std::filesystem::path const &filename,
std::ranges::contiguous_range auto &&range,
@@ -40,9 +25,7 @@ auto write_file(std::filesystem::path const &filename,
co_return nbytes;
}
-/*
- * Utility wrapper for non-contiguous ranges.
- */
+// Utility wrapper for non-contiguous ranges.
export [[nodiscard]]
auto write_file(std::filesystem::path const &filename,
std::ranges::range auto &&range)
@@ -52,12 +35,10 @@ requires(!std::ranges::contiguous_range<decltype(range)>)
return write_file(filename, std::vector(std::from_range, range));
}
-/*
- * Write the contents of a range to a file safely. The data will be written
- * to "<filename>.tmp", and if the write succeeds, the temporary file will be
- * renamed to the target filename. If an error occurs, the target file will
- * not be modified.
- */
+// Write the contents of a range to a file safely. The data will be written
+// to "<filename>.tmp", and if the write succeeds, the temporary file will be
+// renamed to the target filename. If an error occurs, the target file will
+// not be modified.
export [[nodiscard]]
auto safe_write_file(std::filesystem::path const &filename,
std::ranges::range auto &&range)
@@ -68,11 +49,11 @@ auto safe_write_file(std::filesystem::path const &filename,
tmpfile /= (filename.filename().native() + ".tmp");
auto tmpfile_guard = guard([&tmpfile] {
- ::unlink(tmpfile.c_str());
+ std::ignore = unlink(tmpfile.c_str());
});
co_await write_file(tmpfile, range);
- co_await nihil::rename(tmpfile, filename);
+ co_await rename(tmpfile, filename);
tmpfile_guard.release();
co_return {};