aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nihil.config/option.ccm8
-rw-r--r--nihil.config/write.ccm4
-rw-r--r--nihil/command_map.ccm11
-rw-r--r--nihil/ctype.ccm15
-rw-r--r--nihil/error.ccm2
-rw-r--r--nihil/fd.ccm42
-rw-r--r--nihil/find_in_path.ccm3
-rw-r--r--nihil/getenv.ccm2
-rw-r--r--nihil/guard.ccm12
-rw-r--r--nihil/match.ccm4
-rw-r--r--nihil/next_word.ccm2
-rw-r--r--nihil/open_file.ccm4
-rw-r--r--nihil/process.ccm17
-rw-r--r--nihil/rename_file.ccm7
-rw-r--r--nihil/skipws.ccm2
-rw-r--r--nihil/spawn.ccm23
-rw-r--r--nihil/tabulate.ccm94
-rw-r--r--nihil/tests/command_map.cc4
18 files changed, 160 insertions, 96 deletions
diff --git a/nihil.config/option.ccm b/nihil.config/option.ccm
index c095d34..c6ebcae 100644
--- a/nihil.config/option.ccm
+++ b/nihil.config/option.ccm
@@ -78,17 +78,17 @@ protected:
/*
* Get or set this option as a string.
*/
- virtual auto get_string() const
+ [[nodiscard]] virtual auto get_string() const
-> std::string = 0;
- virtual auto set_string(std::string_view)
+ [[nodiscard]] virtual auto set_string(std::string_view)
-> std::expected<void, error> = 0;
/*
* Get or set this option as a UCL object.
*/
- virtual auto get_ucl() const
+ [[nodiscard]] virtual auto get_ucl() const
-> std::expected<ucl::object, error> = 0;
- virtual auto set_ucl(ucl::object const &)
+ [[nodiscard]] virtual auto set_ucl(ucl::object const &)
-> std::expected<void, error> = 0;
private:
diff --git a/nihil.config/write.ccm b/nihil.config/write.ccm
index cb35d76..8fb8151 100644
--- a/nihil.config/write.ccm
+++ b/nihil.config/write.ccm
@@ -11,12 +11,12 @@ export module nihil.config:write;
import nihil;
-export namespace nihil::config {
+namespace nihil::config {
/*
* Write all config values (except defaults) to disk.
*/
-auto write_to(std::filesystem::path const &filename) ->
+export [[nodiscard]] auto write_to(std::filesystem::path const &filename) ->
std::expected<void, error>;
};
diff --git a/nihil/command_map.ccm b/nihil/command_map.ccm
index 979657b..4e55211 100644
--- a/nihil/command_map.ccm
+++ b/nihil/command_map.ccm
@@ -30,12 +30,13 @@ struct command_base {
{
}
- auto path(this command_base const &self) -> std::string_view
+ [[nodiscard]] auto path(this command_base const &self)
+ -> std::string_view
{
return self._path;
}
- virtual auto invoke(int argc, char **argv) -> int = 0;
+ [[nodiscard]] virtual auto invoke(int argc, char **argv) -> int = 0;
private:
std::string_view _path;
@@ -59,7 +60,7 @@ struct command final : command_base {
register_command(path, this);
}
- auto invoke(int argc, char **argv) -> int override
+ [[nodiscard]] auto invoke(int argc, char **argv) -> int final
{
return std::invoke(_func, argc, argv);
}
@@ -69,7 +70,7 @@ private:
};
// The public API.
-export auto dispatch_command(int argc, char **argv) -> int;
-export void print_usage(std::string_view prefix);
+export [[nodiscard]] auto dispatch_command(int argc, char **argv) -> int;
+export auto print_usage(std::string_view prefix) -> void;
} // namespace nihil
diff --git a/nihil/ctype.ccm b/nihil/ctype.ccm
index cc058cd..5f45703 100644
--- a/nihil/ctype.ccm
+++ b/nihil/ctype.ccm
@@ -24,20 +24,21 @@ namespace nihil {
export struct ctype_is final {
ctype_is(std::ctype_base::mask mask_,
std::locale const &locale_ = std::locale())
- : mask(mask_)
- , locale(locale_)
+ : m_mask(mask_)
+ , m_locale(locale_)
{}
- auto operator()(this ctype_is const &self, std::integral auto c)
+ [[nodiscard]] auto operator()(this ctype_is const &self,
+ std::integral auto c)
{
using ctype = std::ctype<decltype(c)>;
- auto &facet = std::use_facet<ctype>(self.locale);
- return facet.is(self.mask, c);
+ auto &facet = std::use_facet<ctype>(self.m_locale);
+ return facet.is(self.m_mask, c);
}
private:
- std::ctype_base::mask mask;
- std::locale locale;
+ std::ctype_base::mask m_mask;
+ std::locale m_locale;
};
// Predefined tests for the current global locale.
diff --git a/nihil/error.ccm b/nihil/error.ccm
index 7d220e1..0500f2e 100644
--- a/nihil/error.ccm
+++ b/nihil/error.ccm
@@ -121,7 +121,7 @@ export struct error : std::exception {
[[nodiscard]] auto condition(this error const &)
-> std::optional<std::error_condition>;
- auto what() const noexcept -> char const * final;
+ [[nodiscard]] auto what() const noexcept -> char const * final;
private:
friend auto operator==(error const &, error const &) -> bool;
diff --git a/nihil/fd.ccm b/nihil/fd.ccm
index 3503833..3349fbd 100644
--- a/nihil/fd.ccm
+++ b/nihil/fd.ccm
@@ -68,7 +68,7 @@ private:
};
// Create a copy of this fd by calling dup().
-export auto dup(fd const &self) -> std::expected<fd, error>;
+export [[nodiscard]] auto dup(fd const &self) -> std::expected<fd, error>;
// Create a copy of this fd by calling dup2(). Note that because this results
// in the existing fd and the new fd both being managed by an fd instance,
@@ -79,47 +79,58 @@ export auto dup(fd const &self) -> std::expected<fd, error>;
//
// In both of these cases, either use raw_dup() instead, or immediately call
// release() on the returned fd to prevent the fd instance from closing it.
-export auto dup(fd const &self, int newfd) -> std::expected<fd, error>;
+export [[nodiscard]] auto dup(fd const &self, int newfd)
+ -> std::expected<fd, error>;
// Create a copy of this fd by calling dup().
-export auto raw_dup(fd const &self) -> std::expected<int, error>;
+export [[nodiscard]] auto raw_dup(fd const &self)
+ -> std::expected<int, error>;
// Create a copy of this fd by calling dup2().
-export auto raw_dup(fd const &self, int newfd) -> std::expected<int, error>;
+export [[nodiscard]] auto raw_dup(fd const &self, int newfd)
+ -> std::expected<int, error>;
// Return the fnctl flags for this fd.
-export auto getflags(fd const &self) -> std::expected<int, error>;
+export [[nodiscard]] auto getflags(fd const &self)
+ -> std::expected<int, error>;
// Replace the fnctl flags for this fd.
-export auto replaceflags(fd &self, int newflags) -> std::expected<void, error>;
+export [[nodiscard]] auto replaceflags(fd &self, int newflags)
+ -> std::expected<void, error>;
// Add bits to the fcntl flags for this fd. Returns the new flags.
-export auto setflags(fd &self, int newflags) -> std::expected<int, error>;
+export [[nodiscard]] auto setflags(fd &self, int newflags)
+ -> std::expected<int, error>;
// Remove bits from the fcntl flags for this fd. Returns the new flags.
-export auto clearflags(fd &self, int clrflags) -> std::expected<int, error>;
+export [[nodiscard]] auto clearflags(fd &self, int clrflags)
+ -> std::expected<int, error>;
// Return the fd flags for this fd.
-export auto getfdflags(fd const &self) -> std::expected<int, error>;
+export [[nodiscard]] auto getfdflags(fd const &self)
+ -> std::expected<int, error>;
// Replace the fd flags for this fd.
-export auto replacefdflags(fd &self, int newflags)
+export [[nodiscard]] auto replacefdflags(fd &self, int newflags)
-> std::expected<void, error>;
// Add bits to the fd flags for this fd. Returns the new flags.
-export auto setfdflags(fd &self, int newflags) -> std::expected<int, error>;
+export [[nodiscard]] auto setfdflags(fd &self, int newflags)
+ -> std::expected<int, error>;
// Remove bits from the fd flags for this fd. Returns the new flags.
-export auto clearfdflags(fd &self, int clrflags) -> std::expected<int, error>;
+export [[nodiscard]] auto clearfdflags(fd &self, int clrflags)
+ -> std::expected<int, error>;
// Create two fds by calling pipe() and return them.
-export auto pipe() -> std::expected<std::pair<fd, fd>, error>;
+export [[nodiscard]] auto pipe() -> std::expected<std::pair<fd, fd>, error>;
/*
* Write data to a file descriptor from the provided range. Returns the
* number of bytes written.
*/
-export auto write(fd &file, std::ranges::contiguous_range auto &&range)
+export [[nodiscard]] auto write(fd &file,
+ std::ranges::contiguous_range auto &&range)
-> std::expected<std::size_t, error>
requires(sizeof(std::ranges::range_value_t<decltype(range)>) == 1)
{
@@ -130,7 +141,8 @@ requires(sizeof(std::ranges::range_value_t<decltype(range)>) == 1)
* Read data from a file descriptor into the provided buffer. Returns a
* span containing the data that was read.
*/
-export auto read(fd &file, std::ranges::contiguous_range auto &&range)
+export [[nodiscard]] auto read(fd &file,
+ std::ranges::contiguous_range auto &&range)
-> std::expected<
std::span<std::ranges::range_value_t<decltype(range)>>,
error>
diff --git a/nihil/find_in_path.ccm b/nihil/find_in_path.ccm
index 3c02ca5..3983c40 100644
--- a/nihil/find_in_path.ccm
+++ b/nihil/find_in_path.ccm
@@ -18,6 +18,7 @@ namespace nihil {
* If $PATH is not set, uses _PATH_DEFPATH. If the file can't be found
* or opened, returns std::nullopt.
*/
-auto find_in_path(std::filesystem::path const &file) -> std::optional<fd>;
+export [[nodiscard]] auto find_in_path(std::filesystem::path const &file)
+ -> std::optional<fd>;
} // namespace nihil
diff --git a/nihil/getenv.ccm b/nihil/getenv.ccm
index 25bde77..a7831e0 100644
--- a/nihil/getenv.ccm
+++ b/nihil/getenv.ccm
@@ -18,7 +18,7 @@ namespace nihil {
* Find a variable by the given name in the environment by calling getenv_r().
*/
-export auto getenv(std::string_view varname)
+export [[nodiscard]] auto getenv(std::string_view varname)
-> std::expected<std::string, error>;
} // namespace nihil
diff --git a/nihil/guard.ccm b/nihil/guard.ccm
index 92305f2..554f605 100644
--- a/nihil/guard.ccm
+++ b/nihil/guard.ccm
@@ -20,23 +20,23 @@ namespace nihil {
export template<std::invocable F>
struct guard final {
// Initialise the guard with a callable we will invoke later.
- guard(F func) : _func(std::move(func)) {}
+ guard(F func) : m_func(std::move(func)) {}
/*
* We are being destroyed, so call the callable.
* If the callable throws, std::terminate() will be called.
*/
~guard() {
- if (_func)
- std::invoke(*_func);
+ if (m_func)
+ std::invoke(*m_func);
}
// Release the guard. This turns the destructor into a no-op.
void release() noexcept {
- _func.reset();
+ m_func.reset();
}
- // Not default-constructible or copyable.
+ // Not default-constructible, movable or copyable.
guard() = delete;
guard(guard const &) = delete;
guard(guard &&) noexcept = delete;
@@ -45,7 +45,7 @@ struct guard final {
private:
// The callable to be invoked when we are destroyed.
- std::optional<F> _func;
+ std::optional<F> m_func;
};
} // namespace nihil
diff --git a/nihil/match.ccm b/nihil/match.ccm
index 9859ea4..f51ce4b 100644
--- a/nihil/match.ccm
+++ b/nihil/match.ccm
@@ -10,10 +10,10 @@ export module nihil:match;
namespace nihil {
-template<class... Ts>
+export template<class... Ts>
struct match : Ts... { using Ts::operator()...; };
-template<typename... Ts, typename... Fs>
+export template<typename... Ts, typename... Fs>
constexpr decltype(auto) operator| (std::variant<Ts...> const &v,
match<Fs...> const &match)
{
diff --git a/nihil/next_word.ccm b/nihil/next_word.ccm
index b6345bc..6c988a0 100644
--- a/nihil/next_word.ccm
+++ b/nihil/next_word.ccm
@@ -22,7 +22,7 @@ namespace nihil {
* calling this repeatedly will return each word from the string.
*/
-export template<typename Char>
+export template<typename Char> [[nodiscard]]
auto next_word(std::basic_string_view<Char> text,
std::locale const &locale = std::locale())
-> std::pair<std::basic_string_view<Char>,
diff --git a/nihil/open_file.ccm b/nihil/open_file.ccm
index 89af4e6..1333785 100644
--- a/nihil/open_file.ccm
+++ b/nihil/open_file.ccm
@@ -18,8 +18,8 @@ namespace nihil {
/*
* Open the given file and return an fd for it.
*/
-export auto open_file(std::filesystem::path const &filename,
- int flags, int mode = 0777)
+export [[nodiscard]] auto open_file(std::filesystem::path const &filename,
+ int flags, int mode = 0777)
-> std::expected<fd, error>;
} // namespace nihil
diff --git a/nihil/process.ccm b/nihil/process.ccm
index 83e34b4..6d74513 100644
--- a/nihil/process.ccm
+++ b/nihil/process.ccm
@@ -23,14 +23,16 @@ namespace nihil {
export struct wait_result final {
// Return true if the process exited normally with an exit code of
// zero, otherwise false.
- auto okay(this wait_result const &self) -> bool;
- explicit operator bool(this wait_result const &self);
+ [[nodiscard]] auto okay(this wait_result const &self) -> bool;
+ [[nodiscard]] explicit operator bool(this wait_result const &self);
// Return the exit status, if any.
- auto status(this wait_result const &self) -> std::optional<int>;
+ [[nodiscard]] auto status(this wait_result const &self)
+ -> std::optional<int>;
// Return the exit signal, if any.
- auto signal(this wait_result const &self) -> std::optional<int>;
+ [[nodiscard]] auto signal(this wait_result const &self)
+ -> std::optional<int>;
private:
friend struct process;
@@ -66,20 +68,21 @@ export struct process final {
auto operator=(this process &, process const &) -> process & = delete;
// Get the child's process id.
- auto pid(this process const &self) noexcept -> ::pid_t;
+ [[nodiscard]] auto pid(this process const &self) noexcept -> ::pid_t;
/*
* Wait for this process to exit (by calling waitpid()) and return
* its exit status. This destroys the process state, leaving this
* object in a moved-from state.
*/
- auto wait(this process &&self) -> std::expected<wait_result, error>;
+ [[nodiscard]] auto wait(this process &&self)
+ -> std::expected<wait_result, error>;
/*
* Release this process so we won't try to wait for it when
* destroying this object.
*/
- auto release(this process &&self) -> ::pid_t;
+ [[nodiscard]] auto release(this process &&self) -> ::pid_t;
private:
::pid_t m_pid;
diff --git a/nihil/rename_file.ccm b/nihil/rename_file.ccm
index bffb3fa..4abe975 100644
--- a/nihil/rename_file.ccm
+++ b/nihil/rename_file.ccm
@@ -11,13 +11,14 @@ export module nihil:rename_file;
import :error;
-export namespace nihil {
+namespace nihil {
/*
* Rename a file (or directory).
*/
-auto rename_file(std::filesystem::path const &oldp,
- std::filesystem::path const &newp)
+export [[nodiscard]] auto
+rename_file(std::filesystem::path const &oldp,
+ std::filesystem::path const &newp)
-> std::expected<void, error>;
} // namespace nihil
diff --git a/nihil/skipws.ccm b/nihil/skipws.ccm
index 20f6aa4..3d760a9 100644
--- a/nihil/skipws.ccm
+++ b/nihil/skipws.ccm
@@ -19,7 +19,7 @@ namespace nihil {
* Remove leading whitespace from a string.
*/
-export template<typename Char>
+export template<typename Char> [[nodiscard]]
auto skipws(std::basic_string_view<Char> text,
std::locale const &locale = std::locale())
-> std::basic_string_view<Char>
diff --git a/nihil/spawn.ccm b/nihil/spawn.ccm
index 00c970c..c15ab8d 100644
--- a/nihil/spawn.ccm
+++ b/nihil/spawn.ccm
@@ -56,9 +56,17 @@ export struct fd_pipe final {
auto run_in_child(this fd_pipe &self, process &) -> void
{
- std::ignore = self.m_parent_fd.close();
+ auto err = raw_dup(self.m_child_fd, self.m_fdno);
+ if (!err) {
+ std::print("dup: {}\n", err.error());
+ _exit(1);
+ }
- raw_dup(self.m_child_fd, self.m_fdno);
+ /*
+ * We don't care about errors from close() since the fd
+ * is still closed.
+ */
+ std::ignore = self.m_parent_fd.close();
std::ignore = self.m_child_fd.close();
}
@@ -67,7 +75,7 @@ export struct fd_pipe final {
std::ignore = self.m_child_fd.close();
}
- auto parent_fd(this fd_pipe &self) -> fd &
+ [[nodiscard]] auto parent_fd(this fd_pipe &self) -> fd &
{
return self.m_parent_fd;
}
@@ -103,7 +111,12 @@ export struct fd_file final {
auto run_in_child(this fd_file &self, process &) -> void
{
- raw_dup(self.m_file_fd, self.m_fdno);
+ auto err = raw_dup(self.m_file_fd, self.m_fdno);
+ if (!err) {
+ std::print("dup: {}\n", err.error());
+ _exit(1);
+ }
+
std::ignore = self.m_file_fd.close();
}
@@ -221,7 +234,7 @@ spawn(executor auto &&executor, auto &&...actions)
// try to wait for ourselves, then run child handlers and
// exec the process.
- std::move(proc).release();
+ std::ignore = std::move(proc).release();
(actions.run_in_child(proc), ...);
auto err = executor.exec();
diff --git a/nihil/tabulate.ccm b/nihil/tabulate.ccm
index 9e2303b..9faf885 100644
--- a/nihil/tabulate.ccm
+++ b/nihil/tabulate.ccm
@@ -50,43 +50,70 @@ export struct table_spec_error : error {
*/
template<typename Char>
struct field_spec {
- std::basic_string_view<Char> name;
- std::size_t width = 0;
- enum { left, right } align = left;
+ enum align_t { left, right };
+
+ // Get the name of this field.
+ auto name(this field_spec const &self)
+ -> std::basic_string_view<Char>
+ {
+ return self.m_name;
+ }
+
+ // Set the name of this field.
+ auto name(this field_spec &self,
+ std::basic_string_view<Char> new_name)
+ -> void
+ {
+ self.m_name = new_name;
+ }
+
+ // Set this field's alignment.
+ auto align(this field_spec &self, align_t new_align) -> void
+ {
+ self.m_align = new_align;
+ }
// Ensure the length of this field is at least the given width.
- auto ensure_width(std::size_t newwidth) -> void
+ auto ensure_width(this field_spec &self, std::size_t newwidth)
+ -> void
{
- width = std::max(width, newwidth);
+ self.m_width = std::max(self.m_width, newwidth);
}
// Format an object to a string based on our field spec.
- auto format(auto &&obj) const -> std::basic_string<Char>
+ [[nodiscard]] auto format(this field_spec const &, auto &&obj)
+ -> std::basic_string<Char>
{
- std::basic_string<Char> format_string{'{', '}'};
+ auto format_string = std::basic_string<Char>{'{', '}'};
return std::format(std::runtime_format(format_string), obj);
}
// Print a column value to an output iterator according to our field
// spec. If is_last is true, this is the last field on the line, so
// we won't output any trailling padding.
- auto print(std::basic_string_view<Char> value,
+ auto print(this field_spec const &self,
+ std::basic_string_view<Char> value,
std::output_iterator<Char> auto &out,
bool is_last)
- const
+ -> void
{
- auto padding = width - value.size();
+ auto padding = self.m_width - value.size();
- if (align == right)
+ if (self.m_align == right)
for (std::size_t i = 0; i < padding; ++i)
*out++ = ' ';
std::ranges::copy(value, out);
- if (!is_last && align == left)
+ if (!is_last && self.m_align == left)
for (std::size_t i = 0; i < padding; ++i)
*out++ = ' ';
}
+
+private:
+ std::basic_string_view<Char> m_name;
+ std::size_t m_width = 0;
+ align_t m_align = left;
};
/*
@@ -95,34 +122,36 @@ struct field_spec {
template<typename Char>
struct table_spec {
// Add a new field spec to this table.
- auto add(field_spec<Char> field)
+ auto add(this table_spec &self, field_spec<Char> field) -> void
{
- _fields.emplace_back(std::move(field));
+ self.m_fields.emplace_back(std::move(field));
}
// Return the field spec for a given field. If the field doesn't
// exist, this field and any intermediate fields will be created.
- auto field(std::size_t fieldnr) -> field_spec<Char>&
+ [[nodiscard]] auto field(this table_spec &self, std::size_t fieldnr)
+ -> field_spec<Char> &
{
- if (_fields.size() < fieldnr + 1)
- _fields.resize(fieldnr + 1);
- return _fields.at(fieldnr);
+ if (fieldnr >= self.m_fields.size())
+ self.m_fields.resize(fieldnr + 1);
+ return self.m_fields.at(fieldnr);
}
// The number of columns in this table.
- auto columns() const -> std::size_t
+ [[nodiscard]] auto columns(this table_spec const &self) -> std::size_t
{
- return _fields.size();
+ return self.m_fields.size();
}
// Return all the fields in this table.
- auto fields() const
+ [[nodiscard]] auto fields(this table_spec const &self)
+ -> std::vector<field_spec<Char>> const &
{
- return _fields;
+ return self.m_fields;
}
private:
- std::vector<field_spec<Char>> _fields;
+ std::vector<field_spec<Char>> m_fields;
};
// Parse the field flags, e.g. '<'.
@@ -134,10 +163,10 @@ auto parse_field_flags(field_spec<Char> &field, Iterator &pos, Sentinel end)
while (pos < end) {
switch (*pos) {
case '<':
- field.align = field_spec<Char>::left;
+ field.align(field_spec<Char>::left);
break;
case '>':
- field.align = field_spec<Char>::right;
+ field.align(field_spec<Char>::right);
break;
case ':':
++pos;
@@ -158,7 +187,7 @@ auto parse_field_flags(field_spec<Char> &field, Iterator &pos, Sentinel end)
// Parse a complete field spec, e.g. "{<:NAME}".
template<typename Char,
std::input_iterator Iterator, std::sentinel_for<Iterator> Sentinel>
-auto parse_field(Iterator &pos, Sentinel end)
+[[nodiscard]] auto parse_field(Iterator &pos, Sentinel end)
-> field_spec<Char>
{
auto field = field_spec<Char>{};
@@ -180,17 +209,18 @@ auto parse_field(Iterator &pos, Sentinel end)
if (brace == end)
throw table_spec_error("Invalid table spec: expected '}'");
- field.name = std::basic_string_view<Char>(pos, brace);
+ field.name(std::basic_string_view<Char>(pos, brace));
pos = std::next(brace);
// The field must be at least as wide as its header.
- field.width = field.name.size();
+ field.ensure_width(field.name().size());
return field;
}
template<typename Char>
-auto parse_table_spec(std::basic_string_view<Char> spec) -> table_spec<Char>
+[[nodiscard]] auto parse_table_spec(std::basic_string_view<Char> spec)
+ -> table_spec<Char>
{
auto table = table_spec<Char>();
@@ -215,8 +245,8 @@ export template<typename Char,
std::ranges::range Range,
std::output_iterator<Char> Iterator>
auto basic_tabulate(std::basic_string_view<Char> table_spec,
- Range &&range,
- Iterator &&out)
+ Range &&range,
+ Iterator &&out)
-> void
{
// Parse the table spec.
@@ -243,7 +273,7 @@ auto basic_tabulate(std::basic_string_view<Char> table_spec,
// Add the header row.
for (auto &&field : table.fields())
- data.at(0).emplace_back(std::from_range, field.name);
+ data.at(0).emplace_back(std::from_range, field.name());
// Print the values.
for (auto &&row : data) {
diff --git a/nihil/tests/command_map.cc b/nihil/tests/command_map.cc
index 7d34b33..4490396 100644
--- a/nihil/tests/command_map.cc
+++ b/nihil/tests/command_map.cc
@@ -25,6 +25,8 @@ TEST_CASE("command_map: basic", "[command_map]")
"cmd", "sub1", nullptr
};
auto argv = const_cast<char **>(args.data());
- nihil::dispatch_command(args.size() - 1, argv);
+
+ int ret = nihil::dispatch_command(args.size() - 1, argv);
+ REQUIRE(ret == 0);
REQUIRE(cmd_sub1_called == true);
}