Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Name remapping specific to a fully-qualified node's name #807

Open
wants to merge 1 commit into
base: rolling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions rcl/include/rcl/lexer_lookahead.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,28 @@ rcl_lexer_lookahead2_peek2(
rcl_lexeme_t * next_type1,
rcl_lexeme_t * next_type2);

/// Look ahead to check if buffer contains colon prefix.
/**
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes [1]
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
* <i>[1] Only allocates if an argument is invalid or an internal bug is detected.</i>
*
* \param[in] buffer the lookahead2 buffer being used to analyze a string.
* \return `RCL_RET_OK` if peeking was successfull, or
* \return `RCL_RET_INVALID_ARGUMENT` if any function arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_lexer_lookahead2_peek_colon_prefix(
rcl_lexer_lookahead2_t * buffer);

/// Accept a lexeme and advance analysis.
/**
* A token must have been peeked before it can be accepted.
Expand Down
64 changes: 49 additions & 15 deletions rcl/src/rcl/arguments.c
Original file line number Diff line number Diff line change
Expand Up @@ -1504,36 +1504,74 @@ _rcl_parse_remap_nodename_replacement(
return RCL_RET_OK;
}

/// Parse a nodename prefix including trailing colon (ex: `node_name:`).
/// Parse a nodename prefix including trailing colon (ex: `node_name:` or `/ns/node_name:`).
RCL_LOCAL
rcl_ret_t
_rcl_parse_nodename_prefix(
rcl_lexer_lookahead2_t * lex_lookahead,
rcl_allocator_t allocator,
char ** node_name)
{
size_t length = 0;
const char * token = NULL;

// Check arguments sanity
assert(NULL != lex_lookahead);
assert(rcutils_allocator_is_valid(&allocator));
assert(NULL != node_name);
assert(NULL == *node_name);

// Expect a token and a colon
rcl_ret_t ret =
rcl_lexer_lookahead2_expect(lex_lookahead, RCL_LEXEME_TOKEN, &token, &length);
rcl_ret_t ret;
const char * name_start = rcl_lexer_lookahead2_get_text(lex_lookahead);
if (NULL == name_start) {
RCL_SET_ERROR_MSG("failed to get start of node name");
return RCL_RET_ERROR;
}

rcl_lexeme_t next_type;
ret = rcl_lexer_lookahead2_peek(lex_lookahead, &next_type);
if (RCL_RET_OK != ret) {
return ret;
}

if (RCL_LEXEME_FORWARD_SLASH == next_type) {
// repeated slashes and tokens until a colon
do {
ret = rcl_lexer_lookahead2_expect(lex_lookahead, RCL_LEXEME_FORWARD_SLASH, NULL, NULL);
if (RCL_RET_WRONG_LEXEME == ret) {
rcl_reset_error();
break;
}

ret = rcl_lexer_lookahead2_expect(lex_lookahead, RCL_LEXEME_TOKEN, NULL, NULL);
if (RCL_RET_WRONG_LEXEME == ret) {
if (RCL_RET_OK == ret) {
rcl_reset_error();
break;
}
}

ret = rcl_lexer_lookahead2_peek(lex_lookahead, &next_type);
if (RCL_RET_OK != ret) {
return ret;
}
if (RCL_LEXEME_COLON == next_type) {
break;
}
} while (true);
} else {
ret =
rcl_lexer_lookahead2_expect(lex_lookahead, RCL_LEXEME_TOKEN, NULL, NULL);
if (RCL_RET_OK != ret) {
return ret;
}
}

const char * name_end = rcl_lexer_lookahead2_get_text(lex_lookahead);
ret = rcl_lexer_lookahead2_expect(lex_lookahead, RCL_LEXEME_COLON, NULL, NULL);
if (RCL_RET_OK != ret) {
return ret;
}

const size_t length = (size_t)(name_end - name_start);
// Copy the node name
*node_name = rcutils_strndup(token, length, allocator);
*node_name = rcutils_strndup(name_start, length, allocator);
if (NULL == *node_name) {
RCL_SET_ERROR_MSG("failed to allocate node name");
return RCL_RET_BAD_ALLOC;
Expand Down Expand Up @@ -1582,18 +1620,14 @@ _rcl_parse_remap_begin_remap_rule(
{
rcl_ret_t ret;
rcl_lexeme_t lexeme1;
rcl_lexeme_t lexeme2;

// Check arguments sanity
assert(NULL != lex_lookahead);
assert(NULL != rule);

// Check for optional nodename prefix
ret = rcl_lexer_lookahead2_peek2(lex_lookahead, &lexeme1, &lexeme2);
if (RCL_RET_OK != ret) {
return ret;
}
if (RCL_LEXEME_TOKEN == lexeme1 && RCL_LEXEME_COLON == lexeme2) {
ret = rcl_lexer_lookahead2_peek_colon_prefix(lex_lookahead);
if (RCL_RET_OK == ret) {
ret = _rcl_parse_remap_nodename_prefix(lex_lookahead, rule);
if (RCL_RET_OK != ret) {
return ret;
Expand Down
36 changes: 36 additions & 0 deletions rcl/src/rcl/lexer_lookahead.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,42 @@ rcl_lexer_lookahead2_peek2(
return RCL_RET_OK;
}

rcl_ret_t
rcl_lexer_lookahead2_peek_colon_prefix(
rcl_lexer_lookahead2_t * buffer)
{
RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);

RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_FOR_NULL_WITH_MSG(
buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_FOR_NULL_WITH_MSG(
buffer->impl->text, "buffer text not initialized", return RCL_RET_INVALID_ARGUMENT);

rcl_lexeme_t lexeme = RCL_LEXEME_NONE;
rcl_ret_t ret;
size_t length;
const char * ptext = buffer->impl->text;
while (ptext) {
if (*ptext == '\0') {
ret = RCL_RET_ERROR;
break;
}
ret = rcl_lexer_analyze(ptext, &lexeme, &length);
if (RCL_RET_OK != ret) {
break;
}

if (lexeme == RCL_LEXEME_COLON) {
ret = RCL_RET_OK;
break;
}

ptext += length;
}
return ret;
}

rcl_ret_t
rcl_lexer_lookahead2_accept(
rcl_lexer_lookahead2_t * buffer,
Expand Down
28 changes: 25 additions & 3 deletions rcl/src/rcl/remap.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "rcl/error_handling.h"
#include "rcl/expand_topic_name.h"
#include "rcutils/allocator.h"
#include "rcutils/format_string.h"
#include "rcutils/macros.h"
#include "rcutils/strdup.h"
#include "rcutils/types/string_map.h"
Expand Down Expand Up @@ -113,15 +114,34 @@ rcl_remap_first_match(
rcl_remap_t ** output_rule)
{
*output_rule = NULL;

char * full_qualified_name = NULL;
if (node_namespace && node_name) {
const char * fmt = (strlen(node_namespace) == 1) ? "%s%s" : "%s/%s";
full_qualified_name =
rcutils_format_string(allocator, fmt, node_namespace, node_name);
if (NULL == full_qualified_name) {
RCL_SET_ERROR_MSG("failed to allocate memory for full node name");
return RCL_RET_BAD_ALLOC;
}
}

for (int i = 0; i < num_rules; ++i) {
rcl_remap_t * rule = &(remap_rules[i]);
if (!(rule->impl->type & type_bitmask)) {
// Not the type of remap rule we're looking fore
continue;
}
if (rule->impl->node_name != NULL && 0 != strcmp(rule->impl->node_name, node_name)) {
// Rule has a node name prefix and the supplied node name didn't match
continue;
if (rule->impl->node_name != NULL) {
if (rule->impl->node_name[0] == '/' && full_qualified_name) {
if (0 != strcmp(rule->impl->node_name, full_qualified_name)) {
// Rule has a full qualified name and the supplied node name didn't match
continue;
}
} else if (0 != strcmp(rule->impl->node_name, node_name)) {
// Rule has a node name prefix and the supplied node name didn't match
continue;
}
}
bool matched = false;
if (rule->impl->type & (RCL_TOPIC_REMAP | RCL_SERVICE_REMAP)) {
Expand All @@ -138,6 +158,7 @@ rcl_remap_first_match(
RCL_RET_BAD_ALLOC == ret)
{
// these are probably going to happen again. Stop processing rules
allocator.deallocate(full_qualified_name, allocator.state);
return ret;
}
continue;
Expand All @@ -153,6 +174,7 @@ rcl_remap_first_match(
break;
}
}
allocator.deallocate(full_qualified_name, allocator.state);
return RCL_RET_OK;
}

Expand Down
3 changes: 3 additions & 0 deletions rcl/test/rcl/test_arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), check_known_vs_unkno
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "foo:=/bar"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "/foo123:=/bar123"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "node:/foo123:=/bar123"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "node:foo123:=/bar123"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "/node:foo123:=/bar123"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "/ns1/node:foo123:=/bar123"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "rostopic:=/foo/bar"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "rosservice:=baz"}));
EXPECT_TRUE(are_known_ros_args({"--ros-args", "-r", "rostopic://rostopic:=rosservice"}));
Expand Down
40 changes: 38 additions & 2 deletions rcl/test/rcl/test_remap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_topic_re
"--ros-args",
"-r", "Node1:/foo:=/foo/bar",
"-r", "Node2:/foo:=/this_one",
"-r", "Node3:/foo:=/bar/foo");
"-r", "Node3:/foo:=/bar/foo",
"-r", "/Node4:/foo:=/bar/foo",
"-r", "/ns1/Node5:/foo:=/bar/foo");

{
char * output = NULL;
Expand All @@ -220,6 +222,22 @@ TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_topic_re
EXPECT_STREQ("/bar/foo", output);
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
}
{
char * output = NULL;
ret = rcl_remap_topic_name(
NULL, &global_arguments, "/foo", "Node4", "/", rcl_get_default_allocator(), &output);
EXPECT_EQ(RCL_RET_OK, ret);
EXPECT_STREQ("/bar/foo", output);
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
}
{
char * output = NULL;
ret = rcl_remap_topic_name(
NULL, &global_arguments, "/foo", "Node5", "/ns1", rcl_get_default_allocator(), &output);
EXPECT_EQ(RCL_RET_OK, ret);
EXPECT_STREQ("/bar/foo", output);
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
}
}

TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_use_global_topic_name_replacement) {
Expand Down Expand Up @@ -326,7 +344,9 @@ TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_service_
"--ros-args",
"-r", "Node1:/foo:=/foo/bar",
"-r", "Node2:/foo:=/this_one",
"-r", "Node3:/foo:=/bar/foo");
"-r", "Node3:/foo:=/bar/foo",
"-r", "/Node4:/foo:=/bar/foo",
"-r", "/ns1/Node5:/foo:=/bar/foo");

{
char * output = NULL;
Expand All @@ -352,6 +372,22 @@ TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_service_
EXPECT_STREQ("/bar/foo", output);
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
}
{
char * output = NULL;
ret = rcl_remap_service_name(
NULL, &global_arguments, "/foo", "Node4", "/", rcl_get_default_allocator(), &output);
EXPECT_EQ(RCL_RET_OK, ret);
EXPECT_STREQ("/bar/foo", output);
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
}
{
char * output = NULL;
ret = rcl_remap_service_name(
NULL, &global_arguments, "/foo", "Node5", "/ns1", rcl_get_default_allocator(), &output);
EXPECT_EQ(RCL_RET_OK, ret);
EXPECT_STREQ("/bar/foo", output);
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
}
}

TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_use_global_service_name_replacement) {
Expand Down