diff --git a/rcl/include/rcl/node.h b/rcl/include/rcl/node.h index 2f1999c..2f63105 100644 --- a/rcl/include/rcl/node.h +++ b/rcl/include/rcl/node.h @@ -352,6 +352,29 @@ RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t * node); +/// Return the fully qualified name of the node. +/** + * This function returns the node's internal namespace and name combined string. + * This function can fail, and therefore return `NULL`, if: + * - node is `NULL` + * - node has not been initialized (the implementation is invalid) + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] node pointer to the node + * \return fully qualified name string if successful, otherwise `NULL` + */ +RCL_PUBLIC +RCL_WARN_UNUSED +const char * +rcl_node_get_fully_qualified_name(const rcl_node_t * node); + /// Return the rcl node options. /** * This function returns the node's internal options struct. diff --git a/rcl/src/rcl/node.c b/rcl/src/rcl/node.c index df7445b..c969dda 100644 --- a/rcl/src/rcl/node.c +++ b/rcl/src/rcl/node.c @@ -603,6 +603,31 @@ rcl_node_get_namespace(const rcl_node_t * node) return node->impl->rmw_node_handle->namespace_; } +const char * +rcl_node_get_fully_qualified_name(const rcl_node_t * node) +{ + if (!rcl_node_is_valid_except_context(node)) { + return NULL; // error already set + } + + const char * name = rcl_node_get_name(node); + const char * ns = rcl_node_get_namespace(node); + char * fq_name = NULL; + + if ('/' == ns[strlen(ns) - 1]) { + fq_name = (char *)calloc(strlen(ns) + strlen(name), sizeof(char)); + strcpy(fq_name, ns); + strcat(fq_name, name); + } + else { + fq_name = (char *)calloc(strlen(ns) + strlen(name) + 1, sizeof(char)); + strcpy(fq_name, ns); + strcat(fq_name, "/"); + strcat(fq_name, name); + } + return fq_name; +} + const rcl_node_options_t * rcl_node_get_options(const rcl_node_t * node) { diff --git a/rcl/test/rcl/test_node.cpp b/rcl/test/rcl/test_node.cpp index 0a5d2f9..e3bcc4c 100644 --- a/rcl/test/rcl/test_node.cpp +++ b/rcl/test/rcl/test_node.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "rcl/rcl.h" #include "rcl/node.h" @@ -99,6 +100,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors) rcl_node_t invalid_node = rcl_get_zero_initialized_node(); const char * name = "test_rcl_node_accessors_node"; const char * namespace_ = "/ns"; + const char * fq_name = "/ns/test_rcl_node_accessors_node"; rcl_node_options_t default_options = rcl_node_get_default_options(); default_options.domain_id = 42; // Set the domain id to something explicit. ret = rcl_node_init(&invalid_node, name, namespace_, &invalid_context, &default_options); @@ -204,6 +206,27 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors) if (actual_node_namespace) { EXPECT_EQ(std::string(namespace_), std::string(actual_node_namespace)); } + // Test rcl_node_get_fully_qualified_name(). + const char * actual_fq_node_name; + actual_fq_node_name = rcl_node_get_fully_qualified_name(nullptr); + EXPECT_EQ(nullptr, actual_fq_node_name); + rcl_reset_error(); + actual_fq_node_name = rcl_node_get_fully_qualified_name(&zero_node); + EXPECT_EQ(nullptr, actual_fq_node_name); + rcl_reset_error(); + actual_fq_node_name = rcl_node_get_fully_qualified_name(&invalid_node); + EXPECT_TRUE(actual_fq_node_name ? true : false); + if (actual_fq_node_name) { + EXPECT_STREQ(fq_name, actual_fq_node_name); + free((char *)actual_fq_node_name); + } + rcl_reset_error(); + actual_fq_node_name = rcl_node_get_fully_qualified_name(&node); + EXPECT_TRUE(actual_fq_node_name ? true : false); + if (actual_fq_node_name) { + EXPECT_EQ(std::string(fq_name), std::string(actual_fq_node_name)); + free((char *)actual_fq_node_name); + } // Test rcl_node_get_logger_name(). const char * actual_node_logger_name; actual_node_logger_name = rcl_node_get_logger_name(nullptr);