diff --git a/rcl/include/rcl/arguments.h b/rcl/include/rcl/arguments.h
index b271dbb..b301887 100644
--- a/rcl/include/rcl/arguments.h
+++ b/rcl/include/rcl/arguments.h
@@ -42,8 +42,8 @@ rcl_get_zero_initialized_arguments(void);
/// Parse command line arguments into a structure usable by code.
/**
- * If an argument does not appear to be a valid ROS argument then it is skipped and parsing
- * continues with the next argument in `argv`.
+ * If an argument does not appear to be a valid ROS argument then it is skipped
+ * and parsing continues with the next argument in `argv`.
* \sa rcl_arguments_get_count_unparsed()
* \sa rcl_arguments_get_unparsed()
*
@@ -99,7 +99,7 @@ RCL_PUBLIC
RCL_WARN_UNUSED
int
rcl_arguments_get_count_unparsed(
- rcl_arguments_t * args);
+ const rcl_arguments_t * args);
/// Return a list of indexes that weren't successfully parsed.
/**
@@ -130,10 +130,47 @@ RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_arguments_get_unparsed(
- rcl_arguments_t * args,
+ const rcl_arguments_t * args,
rcl_allocator_t allocator,
int ** output_unparsed_indices);
+/// Return a list of arguments with ROS-specific arguments removed.
+/**
+ * Some arguments may not have been intended as ROS arguments.
+ * This function populates an array of the aruments in a new argv array.
+ * Since the first argument is always assumed to be a process name, the list
+ * will always contain the first value from the argument vector.
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | Yes
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] argv The argument vector
+ * \param[in] args An arguments structure that has been parsed.
+ * \param[in] allocator A valid allocator.
+ * \param[out] nonros_argc The count of arguments that aren't ROS-specific
+ * \param[out] nonros_argv An allocated array of arguments that aren't ROS-specific
+ * This array must be deallocated by the caller using the given allocator.
+ * If there are no non-ROS args, then the output will be set to NULL.
+ * \return `RCL_RET_OK` if everything goes correctly, or
+ * \return `RCL_RET_INVALID_ARGUMENT` if any function arguments are invalid, or
+ * \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
+ * \return `RCL_RET_ERROR` if an unspecified error occurs.
+ */
+RCL_PUBLIC
+RCL_WARN_UNUSED
+rcl_ret_t
+rcl_remove_ros_arguments(
+ char const * const argv[],
+ const rcl_arguments_t * args,
+ rcl_allocator_t allocator,
+ int * nonros_argc,
+ const char ** nonros_argv[]);
+
/// Reclaim resources held inside rcl_arguments_t structure.
/**
*
diff --git a/rcl/include/rcl/rcl.h b/rcl/include/rcl/rcl.h
index cf8bb94..9787403 100644
--- a/rcl/include/rcl/rcl.h
+++ b/rcl/include/rcl/rcl.h
@@ -121,7 +121,7 @@ extern "C"
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
-rcl_init(int argc, char ** argv, rcl_allocator_t allocator);
+rcl_init(int argc, char const * const * argv, rcl_allocator_t allocator);
/// Signal global shutdown of rcl.
/**
diff --git a/rcl/src/rcl/arguments.c b/rcl/src/rcl/arguments.c
index aa1e1f5..b40ee46 100644
--- a/rcl/src/rcl/arguments.c
+++ b/rcl/src/rcl/arguments.c
@@ -313,7 +313,7 @@ fail:
int
rcl_arguments_get_count_unparsed(
- rcl_arguments_t * args)
+ const rcl_arguments_t * args)
{
if (NULL == args || NULL == args->impl) {
return -1;
@@ -323,7 +323,7 @@ rcl_arguments_get_count_unparsed(
rcl_ret_t
rcl_arguments_get_unparsed(
- rcl_arguments_t * args,
+ const rcl_arguments_t * args,
rcl_allocator_t allocator,
int ** output_unparsed_indices)
{
@@ -355,6 +355,48 @@ rcl_get_zero_initialized_arguments(void)
return default_arguments;
}
+rcl_ret_t
+rcl_remove_ros_arguments(
+ char const * const argv[],
+ const rcl_arguments_t * args,
+ rcl_allocator_t allocator,
+ int * nonros_argc,
+ const char ** nonros_argv[])
+{
+ RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
+ RCL_CHECK_ARGUMENT_FOR_NULL(argv, RCL_RET_INVALID_ARGUMENT, allocator);
+ RCL_CHECK_ARGUMENT_FOR_NULL(nonros_argc, RCL_RET_INVALID_ARGUMENT, allocator);
+ RCL_CHECK_ARGUMENT_FOR_NULL(args, RCL_RET_INVALID_ARGUMENT, allocator);
+
+ *nonros_argc = rcl_arguments_get_count_unparsed(args);
+ *nonros_argv = NULL;
+
+ if (*nonros_argc <= 0) {
+ return RCL_RET_INVALID_ARGUMENT;
+ }
+
+ int * unparsed_indices = NULL;
+ rcl_ret_t ret;
+ ret = rcl_arguments_get_unparsed(args, allocator, &unparsed_indices);
+
+ if (RCL_RET_OK != ret) {
+ return ret;
+ }
+
+ size_t alloc_size = sizeof(char *) * *nonros_argc;
+ *nonros_argv = allocator.allocate(alloc_size, allocator.state);
+ if (NULL == *nonros_argv) {
+ allocator.deallocate(unparsed_indices, allocator.state);
+ return RCL_RET_BAD_ALLOC;
+ }
+ for (int i = 0; i < *nonros_argc; ++i) {
+ (*nonros_argv)[i] = argv[unparsed_indices[i]];
+ }
+
+ allocator.deallocate(unparsed_indices, allocator.state);
+ return RCL_RET_OK;
+}
+
rcl_ret_t
rcl_arguments_fini(
rcl_arguments_t * args)
diff --git a/rcl/src/rcl/rcl.c b/rcl/src/rcl/rcl.c
index c998d48..ca9695d 100644
--- a/rcl/src/rcl/rcl.c
+++ b/rcl/src/rcl/rcl.c
@@ -61,7 +61,7 @@ __clean_up_init()
}
rcl_ret_t
-rcl_init(int argc, char ** argv, rcl_allocator_t allocator)
+rcl_init(int argc, char const * const * argv, rcl_allocator_t allocator)
{
rcl_ret_t fail_ret = RCL_RET_ERROR;
diff --git a/rcl/test/rcl/test_arguments.cpp b/rcl/test/rcl/test_arguments.cpp
index 7d6c226..7a13a61 100644
--- a/rcl/test/rcl/test_arguments.cpp
+++ b/rcl/test/rcl/test_arguments.cpp
@@ -190,3 +190,61 @@ TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_fini_twice) {
EXPECT_EQ(RCL_RET_ERROR, rcl_arguments_fini(&parsed_args));
rcl_reset_error();
}
+
+TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_remove_ros_args) {
+ const char * argv[] =
+ {"process_name", "-d", "__ns:=/foo/bar", "__ns:=/fiz/buz", "--foo=bar", "--baz"};
+ int argc = sizeof(argv) / sizeof(const char *);
+
+ rcl_allocator_t alloc = rcl_get_default_allocator();
+ rcl_arguments_t parsed_args;
+ rcl_ret_t ret;
+ ret = rcl_parse_arguments(argc, argv, alloc, &parsed_args);
+ ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
+
+ int nonros_argc = 0;
+ const char ** nonros_argv = NULL;
+
+ ret = rcl_remove_ros_arguments(
+ argv,
+ &parsed_args,
+ alloc,
+ &nonros_argc,
+ &nonros_argv);
+
+ EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
+ ASSERT_EQ(nonros_argc, 4);
+ EXPECT_STREQ(nonros_argv[0], "process_name");
+ EXPECT_STREQ(nonros_argv[1], "-d");
+ EXPECT_STREQ(nonros_argv[2], "--foo=bar");
+ EXPECT_STREQ(nonros_argv[3], "--baz");
+ EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
+
+ if (NULL != nonros_argv) {
+ alloc.deallocate(nonros_argv, alloc.state);
+ }
+}
+
+TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_remove_ros_args_zero) {
+ const char * argv[] = {""};
+ rcl_ret_t ret;
+
+ rcl_allocator_t alloc = rcl_get_default_allocator();
+ rcl_arguments_t parsed_args = rcl_get_zero_initialized_arguments();
+
+ int nonros_argc = 0;
+ const char ** nonros_argv = NULL;
+
+ ret = rcl_remove_ros_arguments(
+ argv,
+ &parsed_args,
+ alloc,
+ &nonros_argc,
+ &nonros_argv);
+
+ EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << rcl_get_error_string_safe();
+
+ if (NULL != nonros_argv) {
+ alloc.deallocate(nonros_argv, alloc.state);
+ }
+}